Range of ARM branch instructions
- From: chrisbazley@xxxxxxxxxxx
- Date: 4 Jan 2006 07:02:07 -0800
(Cross-posted from comp.sys.acorn.programmer ; I would be very grateful
for any help).
druck wrote:
> On 2 Jan 2006 chrisbazley@xxxxxxxxxxx wrote:
> > I maintain some code (written in C) that synthesises ARM branch
> > instructions for the purpose of dynamic linking. I would like to add
> > range checks so that an error is reported on 32-bit versions of RISC OS
> > if an address is too far to encode in a branch instruction. (As I
> > understand it all addresses can be reached in 26-bit versions of RISC
> > OS.)
> >
> > My code is equivalent to the following:
>
> [snip]
>
> > Please can anyone confirm that my code is correct?
>
> Looks ok to me.
....Except that it doesn't balk at generating instructions that branch
past zero (overflow/underflow of unsigned address), unless there is
something unintended side-effect of my code that I've missed.
> > In particular, is it valid to branch from addresses in the bottom 32Mb of
> > logical address space to 'negative' (i.e. top bit set) addresses, and
> > vice-versa?
> >
> > At least one disassembler (I think it was ARMalyser) reports such
> > branch instructions as 'unpredictable'
>
> Thats based on the ARM Bible, ARM Architecture Reference Manual, Issue E,
> Section A4-11, page 111.
Really must get my hands on a copy some day.
By the way, I have noticed that PC-relative load instructions at low
addresses (e.g. LDR R0,[PC,#-128]) that reference data below &0 are not
flagged as unpredictable by the disassembler built into the Debugger
module. This seems inconsistent with the undefined behaviour of branch
instructions in the equivalent situation.
Could you please clarify whether such LDR/STR instructions are also
unpredictable?
> > but that may be because the effect varies depending on whether the address
> > space wraps at &3FFFFFF or &FFFFFFFF, rather than because it is inherently
> > bad.
>
> I'm not sure if they are still considering legacy 26bit support when they
> state that, its more likely that the address caculation logic (which can be
> seperate from the main ALU in a core with a dedicated load/store pipeline)
> isn't guaranteed give the correct results in situation where a wrap may
> occur.
OK, so it looks like I also need to avoid creating instructions that
branch past zero. The code below is best I could come up with but I
can't help feeling there might be a more elegant method.
unsigned long *instruction;
char *branch_destination;
if((signed int)branch_destination < (signed int)instruction) {
if(branch_destination > (char *)instruction)
return error_BRANCH_OUT_OF_RANGE;
} else {
if(branch_destination < (char *)instruction)
return error_BRANCH_OUT_OF_RANGE;
}
int offset = (branch_destination - (char *)instruction - 8) >> 2;
if(test32() && (offset > 0x7fffff || offset < -0x800000))
return error_BRANCH_OUT_OF_RANGE;
instruction = 0xEAul << 24 | (unsigned long)(offset & 0xFFFFFF);
Can anyone improve on or pick holes in my code?
One thing I found to be a real headache was the effects of pipelining,
which means that branch instructions with a negative offsets may
actually be
branching forwards!
Note that my code doesn't prevent an instruction at &FFFFFFFC from
branching to &FFFFFFF8, even though this requires an offset of -12 and
relies on the PC wrapping from &00000004 (8 bytes ahead due to
pipelining) to &FFFFFFF8. Whether this is legal and how it would work
with address calculation logic that doesn't handle wrap-around (as
suggested by David) I can't begin to imagine.
I would be grateful if any passing ARM guru could explain it to me.
Chris Bazley
.
- Prev by Date: wireless 315 mhz serial port with LPC 2106
- Next by Date: Re: Low-cost XScale dev board
- Previous by thread: wireless 315 mhz serial port with LPC 2106
- Next by thread: Re: Low-cost XScale dev board
- Index(es):
Relevant Pages
|