Assembler handling of Z reg and .db tables

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

Hi All,

Can anyone tell me why the Z register instruction does not load correctly with an address in Program space? It seems that the Tiny10 Reference and the AVR 8-bit programming set have documentation errors. If I follow their simple usage, I load Zreg this way:


LD ZH,High(Data*2)
LD ZL,Low(Data*2)
LD Rd,Z

This does not work because ZH is not pointed to the code segment upon assembly and resulting Hex code loads it with 00.
This is also impossible to work with in the simulator.

After reading that code segmant starts ar 0x40, and looking at the assembler stats, my code for my larger project ends at 0x0140, so I load ZH with 0x41. The following example works at 0x40 because it is small, but I found this after much searching and trial and error.

.INCLUDE 	"tn10def.inc"

.cseg

main:
	ldi	r16,0    ;index provided in r16
loop:	
	ldi ZH,0x40     ;This is start of Code in Tiny10
	ldi ZL, low (Data*2) ; init Z-pointer to storage bytes
	add	ZL,R16	

	ld	r17,Z ; Pull value directly 

    inc	r16    ;vary the index for example
	rjmp	loop 

.dw 0xEEEE
Data: 
.db 0,1, 2, 3, 4, 5, 6, 7, 8

So where can the novice find correct forms of these (and probably other) obscure assembly language programming methods?

Cheers,
Bob

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

If you read Figure 5-1 in the full data sheet, it shows that FLASH is byte-addressed at 0x4000.

I always imagine that anyone brave enough to write code for this size of mcu, is fairly experienced.

Mind you, there are beginners that choose to write ASM for a Mega128. I do not think I will ever be that brave.

David.

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

Two things:
1) The method that you are using only works because the code is very short. Your loading of ZH should be:

ldi ZH, high(Data*2) + 0x40 

In the example you gave, high(Data*2) happens to be 0. If it were not 0, your code would fail.

2) You can simplify your code using ld rd, Z+. Then you wouldn't have to mess with incrementing the address manually. Your code would also fail if the data crosses a page boundary.

   ldi ZH,high(Data*2) + 0x40     ;This is start of Code in Tiny10
   ldi ZL, low (Data*2) ; init Z-pointer to storage bytes

loop:   
   ld   r17,Z+ ; Pull value directly
   rjmp   loop

By the way, as far as I know, this is the only AVR that you have to add the starting address in like that. My guess is that the assembler has a bug.

Regards,
Steve A.

The Board helps those that help themselves.

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

Yes, it says Flash memory is mapped to Data memory at byte address 0x4000. I don't consider myself brave writing in assembly language, I just don't see why the proper procedure isn't documented properly. A programmer has to use intuition to write the necessary code to implement what the assembler manual depicts as a straightforward load indirect using register Z. A couple of sentences about how to load a program code address into Z is warranted (i.e. ensure the high byte reflects the start of the code segment - look into the platform specific reference manual for the address of the start of Flash memory).

Thanks David.

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

But Steve's point is that normally doing it the "obvious" way just works. It's just this "odd architecture" AVR that is a bit different from all the rest (and so new that the bugs may not yet have been ironed out of the assembler)

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

Koshchi,

Yes - it helps.
1) Your Z register loading code is simple and elegant. If only it was documented. It would have saved me a few hours.

2) My increment was only for the example. I would have used the auto-increment if I needed, but I call the routine with an index pointer.

Thanks for your help.

Bob

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

clawson wrote:
But Steve's point is that normally doing it the "obvious" way just works. It's just this "odd architecture" AVR that is a bit different from all the rest (and so new that the bugs may not yet have been ironed out of the assembler)

Clawson,
I thought I tried the obvious - the way the documentation describes. The novice has to depend on that.

I also agree that it should have been handled in the assembler. I used to manage the QA dept at a high tech firm and my folks would have had a test case for all the instructions for the assembler - for every platform. That would have been an easy one to catch.

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

But the point about this Tiny10 is that it's very new design and they are still polishing off the sharp corners. If this is your first dabble into AVR land you picked possibly the very worst model to get started with.

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

Clawson,

Although I grew up in assembler, I am guilty as charged in AVR land.
By your statements, I'm assuming the Z reg works as documented on other platforms.

The only thing I'm surprised at is the quality of the documentation - mostly finding bits here and there. Stuff in the US website seems to be different than the Norway site. The STK600 platform is overkill for the ATTiny10 and the scarcity of docs for it (Norway had it, US didn't) and the help files were only stubs.
The support mechanism was pretty weak too so I rely on this forum for most of the AVR specific stuff.

BTW: This forum is awesome.
Thanks.

Oh - one more thing:

ldi ZH, high(Data*2) + 0x40 

Didn't work. Maybe +0x41 would have since my code goes up that high.

Cheers.
Bob

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

Quote:
By your statements, I'm assuming the Z reg works as documented on other platforms.

But again, it is likely that it is not the documentation that is wrong, it is the implementation in the assembler for this model that is wrong. The way that it is documented should be correct. Atmel needs to correct the bug in the assembler.
Quote:
Oh - one more thing:

ldi ZH, high(Data*2) + 0x40

Didn't work. Maybe +0x41 would have since my code goes up that high.


That should work in all circumstances. "Data" is the offset from 0 that the assembler thinks the data is at. Adding 0x40 to the high byte will correct that to the actual place in flash that the data is at. Show us your code.

Regards,
Steve A.

The Board helps those that help themselves.

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

One more thing, the .inc file for the tiny10 has a macro "MAPPED_FLASH_START". You could use this instead of the hard coded 0x40 (i.e. use high(MAPPED_FLASH_START)). Searching the .inc files, the tiny4, tiny5 and tiny9 also have this, so it is likely that the same problem exists with these chips.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks Steve.

I agree it should have worked but I did not spend the time on what was going on. The MAPPED_FLASH_START macro is a much better solution than the hard coded 0x40.
The SIM works with:

ldi ZH,high(Ascii*2+MAPPED_FLASH_START)

but I don't know how the Tiny10 handles it yet.

This is the kind of info I expect to see in the errata or reference materials.

Thanks for your help.

Bob

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

Quote:

This is the kind of info I expect to see in the errata or reference materials.

??? OK, I'll bite: Why would this be an errata when the flash is addressed as shown in the datasheet? Wouldn't the "reference material" be the datasheet?

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

I was wondering if/when you would jump in Lee.

Being a newbie, I rely on the documentation. The data sheet and the AVR 8-Bit instruction set manual are two documents that show the LD rd,Z instruction. Neither show or mention that Z register must be loaded using an offset for the Flash memory. I figured the label was already in Flash mem space so the assembler and linker would do the math. I came across examples including on this forum that show the calculation needed as (label*2). The assembler/Linker should take care of the final address and from the comments above, they normally do. I also hacked a word alignment by preceding my label with a .dw 0xFF to ensure a word aligned byte for my data. I didn't see that anywhere, but I didn't want to waste more time trying to find out.

If the datasheet had it in there, I missed it. I just did what it said to do and it didn't work. My guess is that the ATmel folks use much of the 16 and 32-bit documentation for the 8-bit AVR products.

Bob

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

Quote:

Neither show or mention that Z register must be loaded using an offset for the Flash memory. I figured the label was already in Flash mem space so the assembler and linker would do the math. I came across examples including on this forum that show the calculation needed as (label*2). The assembler/Linker should take care of the final address and from the comments above, they normally do. I also hacked a word alignment by preceding my label with a .dw 0xFF to ensure a word aligned byte for my data. I didn't see that anywhere, but I didn't want to waste more time trying to find out.

OK, let's take these one by one. [N.B.: I >>do<< understand frustration. ;) ]

Quote:

Neither show or mention that Z register must be loaded using an offset for the Flash memory.

A. In "real" AVRs, LPM would be used to read from flash. LD can't. Hmmm--Xmega?... still LPM. (As Xmega has mapped extended I/O and EEPROM to the "SRAM" address space reached by LD, I was unsure.)
B. In any AVR except Xmega, when I use LD rd,Z I have to have Z set with the address that I want to read. Let's say I set Z to 0x0008. What do I read with LD R0, Z? The contents of R8. I know that by looking at the
memory map in the datasheet. Let's pick a Mega88 for the next example, and if Z is 0x0070 then LD R0, Z--I get TIMSK2. I know that from the memory map in the datasheet which refers me to the "Register Summary" section. And LD R0, Z with Z of 0x180 reads a certain SRAM location. I know that from the memory map in the datasheet.

The assembler doesn't know anything about the three memory spaces in a Mega88; it assembles the three examples that I used into the correct op codes. (Well, it might know a bit in ASM2 about max addresses by using the XML part description but that doesn't really apply here.)

Let's go back to my first two examples with 0x8 and 0x70. You might well have two of your strings at those addresses in flash memory. How is the assembler to know then when told LD R0, Z that Z is to be from a different memory space?!?

Quote:

I figured the label was already in Flash mem space so the assembler and linker would do the math.

From above, the assembler can't know what Z might contain and the same op code is generated in all three examples. So I think you are considering the load of the Z regiater in this comment? >>The assembler can't know what you intend to do with the value in the Z register.<< It can only put in there what you command it to. You might well be loading the address for an ICALL or IJMP.

Quote:

I came across examples including on this forum that show the calculation needed as (label*2).

The byte-address-using-word-locations gets the best of the 'Freaks, but makes sense in the long run to find the byte address in word-addressed memory. The examples are prep to use >>LPM<<, not LD, to access program memory.

Quote:

The assembler/Linker should take care of the final address and from the comments above, they normally do.

Well, now we are getting into toolchain dependencies. I assumed you were speaking of Atmel's Assembler2. That has no linker. Tell what you mean by how they "take care of the final address" in ANY manner different than putting into the "LDI ZH/ZL, frog" anything other than exactly the 8-bit value that you indicate in the "frog" expression?

It grabbed you. I understand your frustration, and I can grumble with the best of them. On that Tiny series the flash is mapped to a certain "SRAM" address range. It is really no different than the twin I/O addresses that have been in AVRs since day one. If on the Mega88 and want to load the contents of PORTC into R0 I can do In R0, PORTC. I can also load Z with (PORTC+0x20) and if I don't add the offset an LD R0,Z will give me R8 instead of PORTC. We've all been bitten by that also.

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

Lee,
Thanks. Now I don't feel so bad - just a newbie falling into the same old traps that affect most users.

Bob

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

From one assembler programmer to another......

The beast of burden those of us who still use assembler is that no two micros are EXACTLY alike. The AVR's come close compared to others, but as has been posted already, sometimes you have to think outside the chip. I hate to say this believe me, but this in my opinion is the advantage of coding in 'C' over ASM(damn that hurt to type).

I am currently coding ASM for a tiny2313, a Mega48 and a Mega128, ALL in assembler. Even though the architechure is the same the behavior is diffferent, and as a result I must remember programming tricks to overcome these obstacles.

One good thing is that js and I arent the only ASM holdouts on the site anymore!!(LOL)

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user