ASM style question

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

Given

var16:   .dw    VAL16

I want to do

    lds  zl, low_byte(var16)
    lds  zh, high_byte(var16)

I know I could load var16 and var16+1, but I'm wondering if there is some directive or somesuch, which I'm not seeing, that does that a bit more readably.

Of course you may feel that var16, var16+1 is perfectly readable. :)

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

kk6gm wrote:
Given

var16:   .dw    VAL16

I want to do

    lds  zl, low_byte(var16)
    lds  zh, high_byte(var16)

I know I could load var16 and var16+1, but I'm wondering if there is some directive or somesuch, which I'm not seeing, that does that a bit more readably.

Of course you may feel that var16, var16+1 is perfectly readable. :)

Usually high_byte(var16) != low_byte(var16)+1 .
low_byte(var16)=var16 & 0xFF
high_byte(var16)=(var16>>8) & 0xFF

Iluvatar is the better part of Valar.

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

skeeve wrote:
kk6gm wrote:
Given

var16:   .dw    VAL16

I want to do

    lds  zl, low_byte(var16)
    lds  zh, high_byte(var16)

I know I could load var16 and var16+1, but I'm wondering if there is some directive or somesuch, which I'm not seeing, that does that a bit more readably.

Of course you may feel that var16, var16+1 is perfectly readable. :)

Usually high_byte(var16) != low_byte(var16)+1 .
low_byte(var16)=var16 & 0xFF
high_byte(var16)=(var16>>8) & 0xFF

I think I didn't explain myself well. I want to e.g. load the 16-bit value stored at var16 into Z. To do this I need to load the 8-bit value at var16 into ZL, and the 8-bit value at var16+1 into ZH.

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

But var16 is a 16 bit value. var16 + 1 would give you the 16 bit value after var16.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
But var16 is a 16 bit value. var16 + 1 would give you the 16 bit value after var16.

var16 is the address of a 16-bit variable, holding the 16-bit value VAL16. I want to do the equivalent of

lds  Z,var16  ;Z now holds VAL16

but AVR has no such 16-bit loads, so I need to do the load as two 8-bit loads. I can do

lds  ZL,var16
lds  ZH,var16+1  ;Z now holds VAL16

but I'm just wondering if there's anything in the Atmel assembler that makes that a bit cleaner (like the low,high keywords).

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

Quote:

but I'm just wondering if there's anything in the Atmel assembler that makes that a bit cleaner (like the low,high keywords).

You could easily create a macro to load both bytes of a word--pointer or otherwise. As it turns out, CodeVision C uses R30/31 as the most basic scratchpads in its code generation model. And as it compiles to ASM source vs. an object file, the guts is there for everyone to see.

So there are a series of helper macros, including one for what you are describing. You could easily create your own. The examples of definition and use below have an additional parameter as the offset...

R31:R30--
                 	.MACRO __GETW1MN
                 	LDS  R30,@0+(@1)
                 	LDS  R31,@0+(@1)+1
                 	.ENDM
32-bit --                 
                 	.MACRO __GETD1MN
                 	LDS  R30,@0+(@1)
                 	LDS  R31,@0+(@1)+1
                 	LDS  R22,@0+(@1)+2
                 	LDS  R23,@0+(@1)+3
                 	.ENDM
                 
Arbitrary register pair --                 
                 	.MACRO __GETWRMN
                 	LDS  R@0,@2+(@3)
                 	LDS  R@1,@2+(@3)+1
                 	.ENDM
...
                +
004854 91e0 1ca2+LDS R30 , _fmod_name + ( 32 )
004856 91f0 1ca3+LDS R31 , _fmod_name + ( 32 ) + 1
                 	__GETW1MN _fmod_name,32
...
                +
005ae0 9100 1d14+LDS R16 , 0 + ( _FatFs_G002 )
005ae2 9110 1d15+LDS R17 , 0 + ( _FatFs_G002 ) + 1
                 	__GETWRMN 16,17,0,_FatFs_G002
...
                +
005b51 9140 1d14+LDS R20 , 0 + ( _FatFs_G002 )
005b53 9150 1d15+LDS R21 , 0 + ( _FatFs_G002 ) + 1
                 	__GETWRMN 20,21,0,_FatFs_G002

                 

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

A few macros I use.

;Load immediate a register pair with a value. registers r16-r30
;
.MACRO LDIW 		;Arguments: Register pair,  Data (ie zl,zh,1234)
		ldi	@0,low (@2)
		ldi	@1,high (@2)
.ENDMACRO

;Load immediate X with a value.
;
.MACRO LDI_X 		;Arguments: Data (ie 1234)
		ldi	xl,low (@0)
		ldi	xh,high (@0)
.ENDMACRO

;Load immediate Z with a value.
;
.MACRO LDI_Y 		;Arguments: Data (ie 1234)
		ldi	yl,low (@0)
		ldi	yh,high (@0)
.ENDMACRO

;Load immediate Z with a value.
;
.MACRO LDI_Z 		;Arguments: Data (ie 1234)
		ldi	zl,low (@0)
		ldi	zh,high (@0)
.ENDMACRO

edit I think I got it wrong. :oops: If you want to get the value stored at the label then you neeed to write at least 2 different macros, 1 for EEPROM and 1 for FLASH as the 2 types of memories need to be accessed differently.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

The 'low' and 'high' keywords work specifically on addresses usually for labels:

[code]
mystring: .db "Does this work?"

ldi zl, low (mystring)
ldi zh, high (mystring)
lpm r16,z ; r16 has 'D' after execution

Here the z register is acting like a pointer (a variable that holds an address) to get data from Flash program memory. I suspect, but I'm not sure that 'low' and 'high' will work on a 16-bit variable.

Using var and var+1 to access the 8-bit sections of a 16-bit variable is risky because you shouldn't have to remember whether the low or the high part of the variable is stored first in memory. Code might work well on one processor type and then fail on a different processor type. The shift-method of isolating the high and low sections of a variable does work.

Another thing to think about is avoiding the whole 8-bit mind-set totally. 32-bit ARM processors are beginning to approach high-end AVRs in price and some ARMs are selling for a few dollars each. With ARMs assembler code is irrelevant and register/memory locations fit nearly all data types. We are beginning to get away from making our programming style fit the processor and more towards selecting a processor to fit our programming style.
The reply that said use

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

The first question I would have is whether the value you want to load is in SRAM, EEPROM, or flash. As John said, different methods for each.

If it's in flash, then you must use the LPM instruction, and those will be word addresses, not byte addresses. You'll need to tweak them.

From SRAM it's all byte addresses and you have a choice of instructions.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Simonetta wrote:
The 'low' and 'high' keywords work specifically on addresses usually for labels:

[code]
mystring: .db "Does this work?"

ldi zl, low (mystring)
ldi zh, high (mystring)
lpm r16,z ; r16 has 'D' after execution


Right, that's what I would do for indirection, but I don't want the address of the data, I want the data, all 16 bits. So I'm asking if there is an equivalent of 'low' and 'high' for fetching that 16 bits of data.

Quote:
Using var and var+1 to access the 8-bit sections of a 16-bit variable is risky because you shouldn't have to remember whether the low or the high part of the variable is stored first in memory.

I agree it's something I would prefer not to spell out so explicitly in the code, which is why I'm asking about it.

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

Simonetta wrote:

[code]
mystring: .db "Does this work?"

ldi zl, low (mystring)
ldi zh, high (mystring)
lpm r16,z ; r16 has 'D' after execution


In AVRASM[2] it hasn't. Must multiply the label address by two.

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

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

zbaird wrote:
If it's in flash, then you must use the LPM instruction, and those will be word addresses, not byte addresses. You'll need to tweak them.
LPM uses byte addresses.
It's phrased badly in the documentation,
but the end result is byte addresses.

Iluvatar is the better part of Valar.

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

Quote:
you must use the LPM instruction, and those will be word addresses, not byte addresses

I meant that the label addresses are word addresses. The LPM needs byte addresses. You have to manually convert, as has been mentioned.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org