Addressing Modes: Working with AVR’s Load-Store RISC Architecture

READING
The AVR Microcontroller and Embedded Systems using Assembly and C
by Muhammad Ali Mazidi, Sarmad Naimi, and Sepehr Naimi

Sections: 2.3, 6.2

Table of Contents

LOAD-STORE INSTRUCTIONS AND THE ATMEGA328P MEMORY MODEL

When selecting an addressing mode you should ask yourself where is the operand (data) located within the memory model of the AVR processor and when do I know its address (assembly time or at run time).

Figure 1: 8-bit AVR Instruction Set
Source: atmel.com

LOAD-STORE INSTRUCTIONS AND ADDRESSING MODES

  • When loading and storing data we have several ways to “address” the data.
  • The AVR microcontroller supports addressing modes for access to the Program memory (Flash) and Data memory (SRAM, Register file, I/O Memory, and Extended I/O Memory).

Figure 2: Load-Store Instructions Table

IMMEDIATE

  • Data is encoded with the instruction. Operand is therefore located in Flash Program Memory. This is why technically our memory model is a Modified Harvard.

ldi r16, 0x23 // where ldi = 1110, Rd = 00002, and constant K = 001000112

  • Notice that only four bits (dddd) are set aside for defining destination register Rd. This limits us to 24 = 16 registers. The designers of the AVR processor chose registers 16 to 31 to be these registers (i.e., 16 ≤ Rd ≤ 31).

DIRECT

lds r16, A
sts A, r16

Within the AVR family there are two (2) possible lds/sts instructions. A specific family member will have only one lds/sts combination. The ATmega328P lds/sts instruction is illustrated here with the exception that 5 bits (not 4) encode Rr/Rd. This means all 32 registers are available to the lds/sts instruction.

in r16, PINC
out PORTD, r16

REGISTER-REGISTER INSTRUCTIONS

Data Transfer

  • Register-register move byte (mov) or word (movw)

Arithmetic and Logic (ALU)

  • Two’s complement negate (neg), Arithmetic add (add, adc, adiw), subtract (sub, subi, sbc, sbci), and multiply (mul, muls, mulsu, fmul, fmuls, fmulsu)
  • Logical not (com), and (and, andi, cbr, tst), or (or, ori, sbr), exclusive or (eor)
  • Clear (clr), set (ser), increment (inc), decrement (dec)

Bit and Bit-Test

  • Register logical shift left (lsl) or right (lsr); arithmetic shift right (asr); and rotate left or right (rol, ror)
  • Register swap nibble (swap)
  • Register bit load (bld) or store (bst) from/to T flag in the Status Register SREG
  • I/O Register Clear (cbi) or set (sbi) a bit
  • Clear (clFlag) or set (seFlag) a Flag bit in the Status Register SREG by name (I, T, H, S, V, N, Z, C) or bit (bclr, bset).

REGISTER DIRECT

In the following figures, OP means the operation code part of the instruction word. To simplify, not all figures show the exact location of the addressing bits. To generalize, the abstract terms RAMEND and FLASHEND have been used to represent the highest location in data and program space.

com r16

add r16, r17

LOAD-STORE PROGRAM EXAMPLE

Write an Assembly program to add two 8-bit numbers.
C = A + B

lds r16, A ; 1. Load variables
lds r17, B
add r16, r17 ; 2. Do something
sts C, r16 ; 3. Store answer

  • Identify the operation, source operand, destination operand in the first Data Transfer instruction.
  • Identify the source/destination operand in the Arithmetic and Logic (ALU) instruction.
  • What addressing mode is used by the source operand, in the first instruction?
  • Show contents of Flash Program Memory (mnemonics)
  • Show contents of SRAM Data Memory, assuming variables are stored in sequential memory locations starting at address 010016.
  • Modify the program to leave register r16 unchanged by making a copy (use r15).

SPECIAL TOPIC – HARVARD VERSUS PRINCETON ARCHITECTURE

Princeton or Von Neumann Memory Model
Program and data share the same memory space. Processors used in all personal computers, like the Pentium, implement a von Neumann architecture.
Harvard Memory Model
Program and data memory are separated. The AVR processors among others including the Intel 8051 use this memory model. One advantage of the Harvard architecture for microcontrollers is that program memory can be wider than data memory. This allows the processor to implement more instructions while still working with 8-bit data. For the AVR processor program memory is 16-bits wide while data memory is only 8-bits.

You may have already noticed that when you single step your program in the simulator of AVR Studio it is incremented by 1 each time an instruction is executed. No surprise there right? Wrong. The program memory of the AVR processor can also be accessed at the byte level. In most cases this apparent paradox is transparent to the operation of your program with one important exception. When you want to access data stored in program memory, you will be working with byte addresses not words (16-bits). The assembler is not smart enough to know the difference and so when you ask for an address in program memory it returns its word address. To convert this word address into a byte address you need to multiply it by 2. Problematically we do this by using the shift left syntax of C++ to explicitly tell the assembler to multiply the word address by 2. Remember, when you shift left one place you are effectively multiplying by 2.

With this in mind, we would interpret the following AVR instruction as telling the AVR assembler to convert the word address of label beehives in program memory to a byte address and then to take the low order of the resulting value and put into the source operand of the instruction.

ldi ZL,low(beeHives<<1) // load word address of beeHives look-up

APPENDIX A – ATMEGA328P INSTRUCTION SET