asm brne question

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I'm trying to port some code written for the Atmel assembler to gcc/binutils. My last error is this code:

brne PC+2

The binutils assembler doesn't know "PC". There is probably an equivalent, but I haven't bothered looking yet since the entire line seems strange to me.

If the condition is true, doesn't brne do a (PC <-- PC + k + 1)? In that case wouldn't that line above jump to (PC + PC + 2 + 1)? Or maybe the Atmel assembler is being nice and fixing this up? I don't have Windows running here to installed and test it?

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IIRC, the GAS equivelent is a ".":

brne .+2

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be sure to check with a couple test programs. IIRC GAS and Atmel ASM differ on the starting address--one is the beginning of the current instruction, and one is the beginning of the >>next<< instruction. I have to re-learn it every time it comes up. Us old farts (search for current "old farts" thread in main Forum) use labels. ;)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
IIRC, the GAS equivelent is a ".":

brne .+2


Thanks. But if the behavior of brne in the true condition is (PC <-- PC + k + 1), won't that do something rather strange if k=.+2

I'll have to install the Atmel simulator or Simulavr and see what it does.

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the Atmel simulator "brne PC+2" just goes to the current PC plus 2. If I change the code to "brne 2" the assembler says "error: Relative branch out of reach". So even the assembler error message calls it a "relative" branch, but the only thing is seems relative to is the start of the program.

So I'm rather confused. Are all the docs describing to the various "br" jump mnemonics as (PC <-- PC + k + 1) wrong? I'm more inclined to think I've missed something, but I'd really like to know what.

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

brne (and lots of others) are 'relative' to the current PC address. The only thing encoded in the instruction that changes is 'k'. So what you have that can't change is-

PC <-- PC + 1

so what you have left is 'k', which has to be filled in by the assembler.

'k' is a word 'address' in the instruction, but the gas assembler wants to work in a byte address, so any of these assembler 'k' numbers will be a multiple of 2.

gcc gas-

brne .+2 -> branch +2 relative to the current address ('.'), which means assuming the brne instruction was at 0x0000, if Z is clear, branch to 0x0004 (byte address)

0x0000 + 1 + 1 (+2 converted to word address by assembler)
or
0x0002 (word address)
0x0004 (byte address)

gas-
brne .-2 would branch to PC + 1 + -1 (loop)
brne .+0 would branch to PC + 1 + 0 (next instruction)
brne .+2 would branch to PC + 1 + 1 (skip next)
brne .+4 would branch to PC + 1 + 2 (skip next 2)
(the number/2 -> directly into 'k')

atmel assembler-
brne PC+0 would branch to PC + 1 + -1 (loop)
brne PC+1 would branch to PC + 1 + 0 (next instruction)
brne PC+2 would branch to PC + 1 + 1 (skip next)
brne PC+3 would branch to PC + 1 + 2 (skip next 2)
(the number-1 -> into 'k')

so it appears to replace brne PC+2, you need brne .+2, but that may be the only one that just so happens to 'match'. Conversion formula-
PC+n -> n=(n-1)*2 -> brne .+n
PC+2 -> (2-1)*2=2 -> brne .+2
PC+3 -> (3-1)*2=4 -> brne .+4
PC-1 -> (-1-1)*2=-4 -> brne .-4
PC+0 -> (0-1)*2=-2 -> brne .-2
PC+1 -> (1-1)*2=0 -> brne .+0

If you can, convert to labels.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> If you can, convert to labels.

Seconded. gas has that nice notion of "local labels" which
can be really helpful here:

1:
   subi r24, 1
   brne 1f
   rjmp 1b
1:

This example has been made artificially confusing to demonstrate
the concept. ;-) The brne jumps to the last label (because it
is tagged `f', so it looks forward to the closest label numbered
1), while the rjmp jumps to the very first label (because it is
tagged `b' to search backwards).

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schickb wrote:
In the Atmel simulator "brne PC+2" just goes to the current PC plus 2. If I change the code to "brne 2" the assembler says "error: Relative branch out of reach". So even the assembler error message calls it a "relative" branch, but the only thing is seems relative to is the start of the program.

So I'm rather confused. Are all the docs describing to the various "br" jump mnemonics as (PC <-- PC + k + 1) wrong? I'm more inclined to think I've missed something, but I'd really like to know what.

schickb wrote:

If the condition is true, doesn't brne do a (PC <-- PC + k + 1)? In that case wouldn't that line above jump to (PC + PC + 2 + 1)? Or maybe the Atmel assembler is being nice and fixing this up? I don't have Windows running here to installed and test it?

While the instruction is encoded with a relative offset, you are always passing the assembler an absolute address. The assembler will then calculate the relative offset (k). (note that the PC+k notation is just a means of turning a relative address back into an absolute one for the assembler)

The branch truly is relative to the instructions location. If the absolute address you pass is truly out of reach by a relative offset, then the assembler will complain.

It is best to use labels, so that the assembler can always adjust the destination for any changes in the code that exists between the branch, and the destination. Explicitly using PC plus some offset means you must manually adjust the offset if you ever alter the code between the branch and the destination.

As stated another problem is how different assemblers provide the current address in PC, some offer the current instruction address, while others offer the address of the next instruction. You will need to account for this accordingly, otherwise you will not be jumping to where you think you should. (some may also expect a word address, while others a byte address)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks everyone. I will indeed convert to labels, but I wanted to understand the details.

I guess its just an issue with the way this is documented. The Atmel assembler doc says the operand is k and the operation is if (Z = 0) then PC <-- PC + k + 1. Sounds like that is a correct description of the resulting object code, but it doesn't seem like an accurate description of the brne mnemonic (which the doc is supposedly describing).

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:

brne .+2

The "PC relative" branches like this are attractive because you don't have to invent a label for the target. However, when used in one particular sequence, it is the source a difficult-to-find bug just waiting to appear. Consider this sequence:

brne .+2
rjmp elsewhere

One day, as your program continues to grow, the "elsewhere" destination gets too far away and the linker complains about the out-of-range error. That's easy to fix - just change the 'rjmp' to 'jmp' and the linker no longer complains. The problem, of course, is that 'rjmp' is two bytes and 'jmp' is four so the preceding branch now has a destination in the middle of an instruction.

A useful alternative is a local label.

brne 1f
rjmp elsewhere
1:

The '1f' reference tells the assembler that the destination is the first '1:' label going forward. In contrast, '1b' means the first '1:' label preceding the line on which it is used.

The potential problem with local labels is that you can have multiple '1:' labels in a file. If you inadvertently delete one of them, all existing references to the deleted label automatically shift to the next one in the specified direction.

The most bullet-proof method is to invent your own unique labels.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schickb wrote:
I guess its just an issue with the way this is documented. The Atmel assembler doc says the operand is k and the operation is if (Z = 0) then PC <-- PC + k + 1. Sounds like that is a correct description of the resulting object code, but it doesn't seem like an accurate description of the brne mnemonic (which the doc is supposedly describing).
Not entirely.
An assembler eats assembly code (duh) whose syntax
and semantics are defined by the assembler's authors.
It excretes object code whose syntax and semantics are
greatly influenced by the machine on which it is to run.
Assembler food, by design, is more or less readable by humans.
By design, the following two instruction go to the same place:
  JMP dest
  RJMP dest

In the case of the RJMP, translating the assembly instruction into machine code
must take into account the location of the instruction and might fail.
In both cases, the meaning of dest is defined by the
assembler's authors and other input to the assembler.

BTW Since neither dest nor the instruction is likely to have a well-defined
location at assembly-time, some of the translation is done by the linker.

BTW IIRC as's '.' and IAR's '*' refer to different instructions.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DKinzer wrote

Quote:

abcminiuser wrote:
Code:
brne .+2
The "PC relative" branches like this are attractive because you don't have to invent a label for the target. However, when used in one particular sequence, it is the source a difficult-to-find bug just waiting to appear. Consider this sequence:
Code:
brne .+2
rjmp elsewhere
One day, as your program continues to grow, the "elsewhere" destination gets too far away and the linker complains about the out-of-range error. That's easy to fix - just change the 'rjmp' to 'jmp' and the linker no longer complains. The problem, of course, is that 'rjmp' is two bytes and 'jmp' is four so the preceding branch now has a destination in the middle of an instruction.

A useful alternative is a local label.
Code:
brne 1f
rjmp elsewhere
1:

The '1f' reference tells the assembler that the destination is the first '1:' label going forward. In contrast, '1b' means the first '1:' label preceding the line on which it is used.

The potential problem with local labels is that you can have multiple '1:' labels in a file. If you inadvertently delete one of them, all existing references to the deleted label automatically shift to the next one in the specified direction.

The most bullet-proof method is to invent your own unique labels.

I have a vague memory of using local symbols (labels) on the PDP-6 [s/n 4 or 9 - the first PDP-6 DEC sold]
at the University of Western Australia in 1969-71. The PDP-6 was, effectively, the prototype for the PDP-10,
DEC-10 and 20's.

My memory is that the assembler for these machines restricted the validity of local symbols to the range
between two successive labels and thus avoided the problem of multiple "destinations" referred to above.

I have been unable to locate my MACRO-10 manual to confirm my memories of nearly 40 years ago.

However, I did locate the following -

Quote:

Extract from PDP11
IAS/RSX-11
MACRO-11 Reference Manual
DEC-11-OIMRA-A-D
IAS Version 1
RSX-11M Version 2
RSX-11D Version 6B (Version 6.1)
digital equipment corporation.maynard.massachusetts
First Printing Dec 1975
Copyright (C) 1975 by Digital Equipment Corporation

pages 3-10 - 3-11

Full manual avaiable at:

http://computer-refuge.org/bitsa...

SYMBOLS AND EXPRESSIONS

3.5 LOCAL SYMBOLS

Local sysmbols are specially formatted symbols used as labels within a
given block of coding that has been delimited as a local symbol block.
Local symbols are of the form n$, where n is a decimal integer from 1
to 65535, inclusive. Examples of local symbols are:

1$
27$
59$
104$

A local symbol block is delimited in one of three ways:

1. The range of a local symbol block usually consists of those
statements between two normally-constructed sumbolic labels
(see Figure 3-1). Note that a statement of the form:

ALPHA=expression

is a direct assignment statement (see section 3.3), but does
not create a label and thus does not delimit the range of a
local symbol block.

2. The range of of a local symbol block is normally terminated upon
encountering a .PSECT, .CSECT, or .ASECT directive in the
source program (see Figure 3-1).

3. The range of a local symbol block is delimited through
MACRO-11 directives, as follows:

Starting delimiter: .ENABL LSB (see section 6.2)

Ending delimitor .DSABL LSB (see section 6.2)
or
Followed by one of: Symbolic label
.PSECT (see section 6.8.1)
.CSECT (see section 6.8.2)
.ASECT (see section 6.8.2)

Local symbols provide a convenient means of generating labels for
branch instructions and other such references within a local symbol
block. Using local symbols reduces the possibility os symbols with
multiple definitions appearing within a user programs. In addition,
the use of local symbols differentiates entry-point labels from local
labels, since local symbols cannot be referenced from outside their
respective local symbol block. Thus, local symbols of the same name
can appear in other local symbol blocks without conflict.

The use of local symbols is encouraged, since they require less symbol
table space than other types of symbols. When defining local symbols,
the programmer is advised to use the range from 1$ to 63$ first, then
the range from 128$ to 65535$. Local symbols within the range 64$
through 128$, inclusive can be generated automatically as feature
MACRO-11. Such local symbols are useful in the expansion of macros
during assembly and are described in detail in this context in section
7.3.5.

Care must be exercised in specifying local symbols in oreder to avoid
multiple definitions within the same local symbol block. For example
if the local symbol 10$ is defined two or more times within the same
local symbol block, each symbol represents a different address value.
Such a multi-defined symbol causes an error code (P) to be generated
in the assembly listing (see Appendix D).

For example of local symbols and local symbol blocks as they appear
in a source program, see Figure 3-1.

 121                               ;
 122                               ;  PROGRAM INITIALIZATION CODE
 123                               ;
 124
 125 000000                                .PSECT  XCTPRG,GBL
 126 000000  012700  000000'       XCTPRG::MOV     #IMPURE,R0    ;IMPURE DATA INITIALIZATION
 127 000004  005020                1$:     CLR     (R0)+
 128 000006  022700  000000'               CMP     #IMPURE,R0
 129 000012  101374                        BMI     1$
 130
 131 000000                                .PSECT  XCTPAS,GBL
 132 000000  012700  000000'       XCTPRG::MOV     #IMPPAS,R0    ;PASS INITIALIZATION
 133 000004  005020                1$:     CLR     (R0)+
 134 000006  022700  000000'               CMP     #IMPPAT,R0
 135 000012  101374                        BMI     1$
 136
 137 000000                                .PSECT  XCTLIN,GBL
 138 000000  012700  000000'       XCTPRG::MOV     #IMPLIN,R0    ;LINE INITIALIZATION
 139 000004  005020                1$:     CLR     (R0)+
 140 000006  022700  000000'               CMP     #IMPLIN,R0
 141 000012  101374                        BMI     1$
 142
 
 
                                     Figure  3-1
                    Assembly Listing Showing Local Symbol Block

I would welcome such an addition to the current assembler

Regards, Gordon

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> I would welcome such an addition to the current assembler

You'll probably have a hard time convincing the gas maintainers
about that. The current existing practice of local labels simply
has a long history among Unix assemblers, so that's their reason
why they implemented it that way.

Yes, I also remember that feature of the Macro-11 assembler. ;-)

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.