Initializing Z pointer in assembly

Thread Starter

Sebbe

Joined Dec 20, 2015
8
Hey, I am learning how to code in assembly to a AtMega32u4 cpu.
In the example below (from Atmel) the LPM-instruction is demonstrated.
What I don't get is why it is necessary to shift the bits one step left when it loads the address to the Z-registers.

<quote>

ldi ZH, high(Table_1<<1) ; Initialize Z pointer
ldi ZL, low(Table_1<<1)
lpm r16, Z ; Load constant from program
; memory pointed to by Z (r31:r30)
...
Table_1:
.dw 0x5876; 0x76 is addresses when ZLSB = 0
; 0x58 is addresses when ZLSB = 1
...

</quote>
 

sailorjoe

Joined Jun 4, 2013
365
Atmel instructions say that program memory is organized as 16 bit words, but the Z pointer is a byte address. So the left shift by one position changes the Z pointer to act like a word address (16 bits) rather than a byte address. OK?
 

Thread Starter

Sebbe

Joined Dec 20, 2015
8
Thanks, I think I understand the purpose but the way it works has me wondering.
So in the following scenario:

Table: .dw 0xFFFF ;0b1111111111111111
.
.
LDI ZH, high(Table<<1)
LDI ZL, low(Table<<1)

...this would result in register ZH being given what value exactly?
And ZL?

My guess would be
ZH : 0b11111111
ZL : 0b11111110
But if so is the case why is the left shift used twice?
Left shift, shifts all bits one position to the left, introducing zeroes from the right, correct?
 
Last edited:

Thread Starter

Sebbe

Joined Dec 20, 2015
8
I think I understand it now, please correct me if I'm wrong.

By initiating Z we give each of the two registers (ZL=R30 and ZH=R31) a byte each.
These two bytes form a 16-bit word address where the first bit (LSB) is a 1 by default. When you then load a register with the value that Z points to (through the address it contains) one has to specify which of the bytes (low or high byte) you want to load to the register because the register has a capacity of 1 byte not 2. The LSB in the address does just that, specifies which byte, if it is the higher byte or the lower byte that should be loaded when the address Z contains is used.

Example:
table_1: DB. 0x1A2B
.
.
LDI ZL,LOW(table_1)
LDI ZL,HIGH(table_1)
LPM R16,Z ;R16 will now be loaded with 0x1A
LDI ZL,LOW(table_1 <<1) ;The shiftLeft doesn't change the original address
LDI ZL,HIGH(table_1 <<1) ;shiftLeft to get same as above since high byte might've changed
LPM R17,Z ;R17 will now be loaded with 0x2B
 
Last edited:

Thread Starter

Sebbe

Joined Dec 20, 2015
8
"The LSB in the address does just that, specifies which byte, if it is the higher byte or the lower byte that should be loaded when the address Z contains is used."

is used through Z (indirect access).
 

sailorjoe

Joined Jun 4, 2013
365
I believe you've got it, Sebbe. Understanding the memory architecture of a microcontroller is an important first step in understanding how to write programs for it. This is true even in mainframe programming. Every system is different. If you aren't familiar with these terms already, look up "little endian", "big endian", and Harvard Architecture. Just for fun.
 
Top