## MAJOR problem with GNU assembler under AVR

20 posts / 0 new
Author
Message

I need a way to "assemble" a 16 bit reference to a ***BYTE*** address to some label that has been defined within the .text section .

foo:

asm code of some sort goes here

...

bar:

.word foo    ; this will assemble a cell address, i need byte address

.word (2 * foo) failes. cannot use *

.word (foo + 5) works but .word (foo + foo) does not

also .word pm(foo) also does not work because when i do this some rjmp assembled further on in the build suddenly fails to assemble because its target is now mysteriously out of range.

i have spent the past 3 or 4 hours trying to figure this out

also, doing the conversion at run time is exactly what I am trying to avoid, in fact having to do that would turn my very very very simple code into a horrendously over complificated gordian knot.

p.s.

I am ***NOT*** using gcc ***AT ALL***

I am therefore NOT using avr-libc lol

If something can be read without effort then great effort has gone into its writing

It seems these operations are not legal on labels, but maybe you can do something like

.word (foo-base)*2 + base

where base is a label that has address zero.

Last Edited: Tue. Apr 30, 2019 - 05:15 PM

and this would result in my having to do a run time addition of "base" back in to the value assembled.

why is .word (xxx * 2) | 0x8000 such a problem for this assembler?

"The Unix operating system was not designed to stop you from doing stupid things because that would stop you doing clever things"  -- i for get who --

Seems to me like these development tools are being mommy and holding my hand and protecting me from me.

If something can be read without effort then great effort has gone into its writing

Why runtime?

Can't you just

.org 0

base:

or something like that?

Please provide a small complete program that demos the issue.

Tell what assembler you are using (or toolchain).

What does unix have to do with AVR or assembler?

Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get 5 free gold/silver https://www.onegold.com/join/713... Total votes: 0 El Tangas wrote: Why runtime? Can't you just .org 0 base: or something like that? The presented solution to subtract the base address at compile time would mean having to add it back in at run time doing .org 0 does not help because .text addresses 0 1 and 2 refer to cell addresses where each cell is 2 bytes in size. how can i assemble a .word to some predefined .text section label thats assembled as a byte address (i.e. 2 times its cell address). If something can be read without effort then great effort has gone into its writing Total votes: 0 This is why the pm() macros exist in the assembler. . EDIT user manual... https://sourceware.org/binutils/docs-2.32/as/AVR_002dModifiers.html#AVR_002dModifiers . EDIT2: I reread your first post. pm() is the solution so I'd solve any issue arising from its usage. . Oh and the C compiler is VERY good at writing avr-as, better than any of us ever will be so ask it for guidance (save-temps etc) Last Edited: Tue. Apr 30, 2019 - 05:44 PM Total votes: 0 ki0bk wrote: Please provide a small complete program that demos the issue. Tell what assembler you are using (or toolchain). What does unix have to do with AVR or assembler? Jim I am usubg the GNU assembler that comes with atmel studio. the unix quote was because I feel these tools are specifically designed to stop me from doing things THEY consider stupid and they are thus preventing me from doing what I am trying to do. I have written this code using the GNU development tools countless times for different architectures and THIS incantation of the GNU assembler has been a thorn in my side from the get-go. Things I have had no problem doing on say... ARM... simply do not assemble with the AVR version of the GNU assembler. I have worked around every single issue except this one issue which I have been working on for the past 3 or 4 hours and would have taken me 2 minutes if the mommy compiler did not know better than me how i should be doing things. fudge: rcall flubber ; a .text label defined somewhere within my code that calls some subroutine ... more asm code here .word fudge ; except this address is going to be a cell address and i need a byte address .word fudge * 2 fails and actually what i need is .word (fudge * 2 ) | 0x8000 but again the OR operation is disallowed. I can use + in its place if i can get the * to work For a ***WORKING*** example of what I am trying to do here I can show you my ARM (thumb2) version of this code on github at https://github.com/mark4th/t4/bl... there are some differences, the arm version does not need to convert .text addresses from cell aligned to byte aligned because ALL addresses in ARM are byte addresses. as they are pretty much everywhere else in the world (im sure there are other cases besides avr). actually the pasted link is not a good one because that forth is subroutine threaded so every execution token is a bl opcode to some address where as here I am using a direct threaded model so every execution token is an address. If something can be read without effort then great effort has gone into its writing Last Edited: Tue. Apr 30, 2019 - 05:47 PM Total votes: 0 clawson wrote: This is why the pm() macros exist in the assembler. . EDIT user manual... https://sourceware.org/binutils/... . EDIT2: I reread your first post. pm() is the solution so I'd solve any issue arising from its usage. . Oh and the C compiler is VERY good at writing avr-as, better than any of us ever will be so ask it for guidance (save-temps etc) the pm macro does exactly the opposite of what I am trying to do. it DIVIDES the address by 2 not multiplies it by 2 when you do mov zl, lo8(fudge) mov zh, hi9(fudge) the assembler assumes a byte address on fudge and if you need your code to use a cell address the macro comes to the rescue mov zl, lo8(pm(fudge)) ... but when you do .word fudge it assumes a CELL address If something can be read without effort then great effort has gone into its writing Total votes: 0 mark4th wrote: Things I have had no problem doing on say... ARM... simply do not assemble with the AVR version of the GNU assembler. Probably from its (AVR) Harvard architecture, .text is in flash (readonly, mostly) memory. good luck with your project, others here are much more skilled then I with AVR assembler. Jim Click Link: Get Free Stock: Retire early! PM for strategy share.robinhood.com/jamesc3274 get5 free gold/silver https://www.onegold.com/join/713...

ki0bk wrote:

mark4th wrote:
Things I have had no problem doing on say... ARM... simply do not assemble with the AVR version of the GNU assembler.

Probably from its (AVR) Harvard architecture, .text is in flash (readonly, mostly) memory.

good luck with your project, others here are much more skilled then I with AVR assembler.

Jim

understood, but i have written similar code for 8051 in the past and not had this problem at all :)

If something can be read without effort then great effort has gone into its writing

and I may have just KLUDGED a solution.  it is a kludge though because Im hand assembling 16 bit addresses as two 8 bit items... see my code below in is entirety.

the relevant bits are in the header macro where i reference the wrd macro.  previously i was trying to .word xxxxx.  splitting the address into two 8 bit items allows me to use the lo8() macro which I have already verified converts the .text CELL address into a byte address.

; macros.s
; -----------------------------------------------------------------------

#define tl  r20            // top of stack
#define th  r21
#define wl  r22            // working register
#define wh  r23
#define ipl r24            // interpretive pointer
#define iph r25

#define _IO _SFR_IO_ADDR   // i dont want _EXTRALONGBULLSHITMACRONAMES

; -----------------------------------------------------------------------

; x = parameter stack pointer
; y = return stack pointer
; z = gp pointer

; -----------------------------------------------------------------------

.set lex, 0               ; marks next word as immediate, alias etc

.set e_link, 0            ; chain of eeprom variables

; -----------------------------------------------------------------------

.set FORTH, 1
.set COMPILER, 2
.set ROOT, 3

; -----------------------------------------------------------------------

IMM     = 0x80
ALIAS   = 0x40
BODY    = 2

; ------------------------------------------------------------------------
; make next assembled word an immediate word

.macro _imm_
.set lex, IMM
.endm

; -----------------------------------------------------------------------

.macro next
jmp _next
.endm

; -----------------------------------------------------------------------

.macro hstring name
.byte lex + 9f-(.+1)
.ascii "\name"
9:
.balign 2
.endm

; -----------------------------------------------------------------------

.endm

; -----------------------------------------------------------------------

hstring "\name"
.set lex, 0
wrd \cfa   ; note: can probably delete this link
.endm

; -----------------------------------------------------------------------

.macro xt xx q:vararg
wrd \xx
.ifnb \q
xt \q
.endif
.endm

; -----------------------------------------------------------------------

.macro code name, cfa
\cfa:
.endm

; -----------------------------------------------------------------------

.macro colon name, cfa
\cfa:
jmp nest
.endm

; -----------------------------------------------------------------------

.macro lit name, value
xt plit
.word \value
.endm

; -----------------------------------------------------------------------

.macro alias name, cfa, label
.set lex, ALIAS
.set \label, \cfa
.endm

; -----------------------------------------------------------------------

.macro constant name, cfa, value
\cfa:
jmp doconstant
.word \value
.endm

; -----------------------------------------------------------------------

.macro variable name, cfa, value
\cfa:
jmp dovariable
.word b_\cfa
.section .data
b_\cfa\():
.word \value
.section .text
.endm

; -----------------------------------------------------------------------

.macro var name, cfa, value
\cfa:
jmp dovar
.word b_\cfa
.section .data
b_\cfa\():
.word \value
.section .text
.endm

; -----------------------------------------------------------------------
; assemble a deferred word

.macro defer name, cfa, value
\cfa:
jmp dodefer
.word b_\cfa              ; point to deferred words ram vector
.word e_\cfa              ; ram vector is shadowed in eeprom
.section .data
b_\cfa\():
.word \value              ; run time ram vector
.section .eeprom            ; above ram vector is initialized at boot
e_\cfa\():                  ; by copying this eeprom data to ram
.word \value
.section .text
.endm

; -----------------------------------------------------------------------

.macro evar name, cfa, value
\cfa:
jmp dovar
.word b_\cfa
.word e_\cfa
.section .data
b_\cfa:
.word \value
.section .eeprom
e_\cfa\():
.word \value
.section .text
.endm

; -----------------------------------------------------------------------

\cfa:
jmp dovoc
.word e_\cfa
.section .eeprom
e_\cfa\():
.fill 15, 2, 0
.section .text
.endm

; =======================================================================


If something can be read without effort then great effort has gone into its writing

Ironically, MattRW had the opposite MAJOR problem with avr-as:

MattRW wrote:
I'm working with avr-as and trying to load the word address of a function into a register pair.  I am getting the byte address.

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.

>> why is .word (xxx * 2) | 0x8000 such a problem for this assembler

It’s a linker problem. “Foo” is a relocatable symbol, and the linker only allows some operations to do the relocation. (Ie addition/subtraction of offsets.)

OK so I'm confused. I built:

/*
* Assembler1.S
*
* Created: 01/05/2019 10:01:19
*  Author: uid23021
*/
.global main
main:
ldi R16, 0x55

bar:
.word main

It created:

0000006c <main>:
* Created: 01/05/2019 10:01:19
*  Author: uid23021
*/
.global main
main:
ldi R16, 0x55
6c:	05 e5       	ldi	r16, 0x55	; 85

0000006e <bar>:
6e:	6c 00       	.word	0x006c	; ????


The word is 0x006C. That already is a BYTE address ?? (you can tell they are byte address as the two bytes of the LDI opcode offset from 6C to 6E). You said:

bar:

.word foo    ; this will assemble a cell address, i need byte address

The comment is wrong - I don't know what "cell" address means though I suspect you mean "word" (ie 16 bit) because Atmel has a habit of using word addressing in the flash space - but the comment is wrong anyway - by experiment it seems it already is a byte address.

(which is why pm() exists to convert byte to word by having the value).

PS Of course the Atmel debugger does insist on using Word address for flash so in that you see:

--- No source file -------------------------------------------------------------
00000000 0c.94.2a.00          JMP 0x0000002A		Jump
00000002 0c.94.34.00          JMP 0x00000034		Jump
00000004 0c.94.34.00          JMP 0x00000034		Jump
00000006 0c.94.34.00          JMP 0x00000034		Jump
00000008 0c.94.34.00          JMP 0x00000034		Jump
0000000A 0c.94.34.00          JMP 0x00000034		Jump
0000000C 0c.94.34.00          JMP 0x00000034		Jump
0000000E 0c.94.34.00          JMP 0x00000034		Jump
00000010 0c.94.34.00          JMP 0x00000034		Jump
00000012 0c.94.34.00          JMP 0x00000034		Jump
00000014 0c.94.34.00          JMP 0x00000034		Jump
00000016 0c.94.34.00          JMP 0x00000034		Jump
00000018 0c.94.34.00          JMP 0x00000034		Jump
0000001A 0c.94.34.00          JMP 0x00000034		Jump
0000001C 0c.94.34.00          JMP 0x00000034		Jump
0000001E 0c.94.34.00          JMP 0x00000034		Jump
00000020 0c.94.34.00          JMP 0x00000034		Jump
00000022 0c.94.34.00          JMP 0x00000034		Jump
00000024 0c.94.34.00          JMP 0x00000034		Jump
00000026 0c.94.34.00          JMP 0x00000034		Jump
00000028 0c.94.34.00          JMP 0x00000034		Jump
--- ../../../../crt1/gcrt1.S ---------------------------------------------------
0000002A 11.24                CLR R1		Clear Register
0000002B 1f.be                OUT 0x3F,R1		Out to I/O location
0000002C cf.e5                LDI R28,0x5F		Load immediate
0000002D d4.e0                LDI R29,0x04		Load immediate
0000002E de.bf                OUT 0x3E,R29		Out to I/O location
0000002F cd.bf                OUT 0x3D,R28		Out to I/O location
00000030 0e.94.36.00          CALL 0x00000036		Call subroutine
00000032 0c.94.38.00          JMP 0x00000038		Jump
00000034 0c.94.00.00          JMP 0x00000000		Jump
--- c:\users\uid23021\Documents\Atmel Studio\7.0\GnuAsTest\Debug/.././Assembler1.S
ldi R16, 0x55
00000036 05.e5                LDI R16,0x55		Load immediate
00000037 6c.00                ??? 		Unknown instruction 

So the word is still 0x006C but the location it references is annotated in this debugger as 0x0036 (which is 0x006C / 2). Maybe that's the source of your confusion?

PS irrelevant I know but you can see the action of pm() here too:

 .global main
main:
ldi R16, 0x55

bar:
.word main
.word pm(main)

yields:

	ldi R16, 0x55
6c:	05 e5       	ldi	r16, 0x55	; 85

0000006e <bar>:
6e:	6c 00       	.word	0x006c	; ????
70:	36 00       	.word	0x0036	; ????


So this does then encode the 0x006C byte address as the 0x0036 word value.

I fought with this for hours and every time I looked it was a cell address I was seeing, looking at it the way you did DOES show it to be a byte address :/

So frustrating, i basically wasted all of yesterday fighting to fix a non problem lol

ty

If something can be read without effort then great effort has gone into its writing

Was it that Atmel debugger disasm view you were looking at? It confuses the hell out of me. I've been programming computers for 40+ years and I've always thought about everything in terms of bytes so 16bit word displays confuse the living daylights out of me!

no! I have two "listings".  One is produced by the assembler and almost every address is listed as .word 0000 (with the ARM Gnu Assembler this listing shows offsets just fine).  The other listing which is pretty much useless is the .lss file which is simply an objdump of the code.  It was here that I was seeing CELL based addresses but either my eyes were squirly yesterday or something else was going on because today they do all seem to be byte addresses.  So you are not the only one who is thoroughly confused

If something can be read without effort then great effort has gone into its writing