Skip to main content

Microcontrollers

Section 13.4 Memory Addressing

Memory addressing refers to the ways in which a microcontroller accesses data to carry out an instruction. The instruction contains operands that specify the data to be operated on, while the program counter provides the address of the next instruction in program memory. Memory addressing modes are determined when a microcontroller is designed and cannot be changed by a programmer.
In general, memory can be addressed directly or indirectly. Direct addressing occurs when the memory address is stored as part of the instruction itself. Direct addressing is typically fast (the data to be operated on in memory is pointed to directly), and has the flexibility of allowing variable data to be manipulated, rather than constant data (which is used in immediate addressing).
Indirect addressing occurs when a pointer is used instead of the memory address. Indirect addressing enables a microcontroller to access memory contents even if the number of addresses available exceeds the size of the instruction itself, but suffers the drawback of being slower than direct addressing (first the pointer must be loaded, then the contents of the memory address that the pointer points to is operated on).

Subsection 13.4.1 General Purpose Register Addressing

General purpose register addressing occurs when one or more operand is a general purpose register. The two types of general purpose register addressing modes in the AVR instruction set are
Direct, single register addressing instructions have only a single general purpose register operand. This operand is known as a destination register and is denoted as Rd. The destination register is capable of addressing the entire general purpose register space, which means that 5ย bits are used in the instruction to represent this operand. Direct, single register addressing is shown schematically in Figureย 13.4.1.
A long rectangle on the left has a vertical dividing the left and right portions. The left side of the rectangle is labeled "opcode" and the right side of the rectangle is labeled "Rd." The bottom of the "Rd" part of the rectangle has an arrow pointing to a section in another rectangle. This second rectangle is tall and wide. Itโ€™s labeled "general purpose registers." The top right of the general purpose registers rectangle is labeled on the right hand side as 0. The bottom right of the general purpose registers rectangle is labeled on the right hand side as 31. The section that the arrow is pointing to is labeled "d."
Figure 13.4.1. Direct, single register addressing occurs when an instruction contains a single general purpose register as an operand.

Example 13.4.2. NEG instruction.

The twoโ€™s complement instruction (NEG) uses direct, single register addressing. This instruction takes the twoโ€™s complement value of a register and saves the result back into that same register. It is capable of addressing all of the 32 general purpose registers using 5 bits in the instruction. The remaining 11 bits are used for the opcode. The 16-bit machine instruction is 1001010ddddd0001, where the bits denoted d represent the value of the general purpose register.
Direct, two register addressing instructions have two general purpose register operands. These operands consist of a destination register (Rd) and a source register (Rr). Both operands can address the entire general purpose register space, which means that 10 bits are used in the instruction to represent the operands. Direct, two register addressing is shown schematically in Figureย 13.4.3.
A long rectangle on the left is divided into three sections. The left side of the rectangle is labeled "opcode," the middle is labeled "Rr," and the right side of the rectangle is labeled "Rd." The bottom of the "Rd" part of the rectangle has an arrow pointing to a section in another rectangle. The bottom of the "Rr" part of the rectangle also has an arrow pointing to a different section in the other rectangle. The second rectangle is tall and wide. Itโ€™s labeled "general purpose registers." The top right of the general purpose registers rectangle is labeled on the right hand side as 0. The bottom right of the general purpose registers rectangle is labeled on the right hand side as 31. The section that the "Rd" arrow is pointing to is labeled "d." The section that the "Rr" arrow is pointing to is labeled "r."
Figure 13.4.3. Direct, two register addressing occurs when an instruction contains two general purpose registers as operands.

Example 13.4.4. ADD instruction.

The add without carry instruction (ADD) uses direct, two register addressing. This instruction takes the sum of two values (each of which is stored in a general purpose register) and saves the result back into the destination register. The instruction is capable of addressing all of the 32 general purpose registers using 10 bits (5 each for the source and destination operands) in the instruction. The remaining 6 bits are used for the opcode. The 16-bit machine instruction is 000011rdddddrrrr, where the bits denoted d represent the value of the destination register and the bits denoted r represent the value of the source register.

Subsection 13.4.2 Immediate Addressing

In immediate addressing, the instruction contains data to be operated on immediately. In other words, one or more operand is part of the instruction itself. Because the data is part of the instruction, immediate addressing can be fast. However, it is also less flexible when it comes to changing or repurposing code.
Most of the instructions that contain immediate addressing in the ATmega328P allow for the immediate data to take on values between 0-255. This requires 8ย bits of data, which means that only 8 bits remain in the instruction for the opcode and any other operand. AVR instructions that use immediate addressing use a general purpose register as the other operand. The number of general purpose registers that can be addressed is limited to registers 16-31, which means that 4 bits are used to address the register. The remaining 4 bits of the instruction are used to store the opcode.
Not all arithmetic and logical operations have immediate addressing instructions. In that case, an immediate can be loaded into a general purpose register using the load immediate (LDI) instruction. Then, the data stored in those registers can be operated on using general purpose register addressing.

Example 13.4.5. AND versus ANDI instructions.

The logical AND instruction (AND) and logical AND with immediate instruction (ANDI) demonstrate the difference between two-register addressing and immediate addressing. AND is a logical AND operation that occurs between two general purpose registers (Rd and Rr). The data is fetched from each of the registers, routed to the ALU, and then stored in the destination register. All of the general purpose registers can be addressed in this instruction, leaving 6 bits for the opcode. The machine instruction is for AND is 001000rdddddrrrr.
ANDI is the immediate addressing instruction used to compute a logical AND. With ANDI, the microcontroller performs a logical AND between the contents of general purpose register Rd and a constant (the immediate), with the result stored in the destination register. 8 bits of the instruction are used for the immediate, 4 bits are used for the general purpose register, leaving 4 bits for the opcode. The machine instruction for ANDI is 0111KKKKddddKKKK, where the bits denoted d represent the value of the destination register and the bits denoted K represent the value of the immediate.

Subsection 13.4.3 I/O Register Addressing

I/O register addressing instructions have two operands: one thatโ€™s a general purpose register and the other thatโ€™s an I/O register. The general purpose register operand can address the entire general purpose register space (which requires 5 bits of the machine instruction). Because the I/O register space is 64ย bits, 6 bits of instruction is required to represent the I/O register operand. I/O register addressing is shown schematically in Figureย 13.4.6.
A long rectangle on the left is divided into three sections. The left side of the rectangle is labeled "opcode," the middle is labeled "Rr/Rd," and the right side of the rectangle is labeled "A." The bottom of the "A" part of the rectangle has an arrow pointing to a section in another rectangle. The second rectangle is tall and wide. Itโ€™s labeled "I/O registers." The top right of the I/O registers rectangle is labeled on the right hand side as 0. The bottom right of the I/O registers rectangle is labeled on the right hand side as 63. The section that the "A" arrow is pointing to is labeled "A."
Figure 13.4.6. I/O register addressing occurs when an instruction contains an I/O registers as an operand.
In I/O direct addressing, instructions contain an I/O address (A) as well as a destination general purpose register (Rd) and/or a source general purpose register (Rr).
Notable instructions that use direct I/O addressing are IN and OUT, which loads data from an I/O register into a destination general purpose register or stores the contents from a source register into one of the I/O registers, respectively. 6 bits are used to address the I/O register, 5 bits are used to address the (source or destination) general purpose register, and the remaining 5 bits are used for the opcode.

Subsection 13.4.4 Data Memory Addressing

Data memory addressing is used to access the entirety of data memory (SRAM). These instructions contain two 16-bit words; the least significant word contains the 16-bit data memory address. Because there are two instruction words to decode, these instructions require at least 2 clock cycles to execute.
Data direct addressing has two operands: a general purpose register and an address in data memory. Data direct addressing is shown schematically in Figureย 13.4.7. The general purpose operand is capable of addressing the entire data memory space, and therefore requires 5 bits of the instruction. The data memory address is 8ย bits and can therefore address 65k of memory (this is more than sufficient to address the 2k data memory in the ATmega328P).
A long rectangle on the left is split horizontally in two. The top half has two sections and the bottom half has one section. The top left side of the rectangle is labeled "opcode." The top right side of the rectangle is labeled "Rr/Rd." The bottom half of the rectangle is labeled "data address." The bottom of the "data address" part of the rectangle has an arrow pointing to a section in another rectangle. The second rectangle is tall and wide. Itโ€™s labeled "data memory." The top right of the data memory rectangle is labeled on the right hand side as 0. The bottom right of the data memory rectangle is labeled on the right hand side as 0x08FF.
Figure 13.4.7. Data direct addressing occurs when an instruction contains a 16-bit data address as an operand.

Example 13.4.8. LDS instruction.

The load direct from data space instruction (LDS) loads data from an address in SRAM into a destination general purpose register. 16 bits are available for the data memory address, which means that it is limited to addressing the first 64k of data stored in SRAM. This is not a problem on the ATmega328P which only has 2k of memory. The remaining part of the instruction contains 5 bits to address the general purpose register, with the remaining 11 bits used for the opcode. The 32-bit machine instruction is 1001000ddddd0000 kkkkkkkkkkkkkkkk, where the bits denoted d represent the value of the destination register and the bits denoted k represent the data memory address.
Data indirect addressing instructions have two operands: a general purpose register and a pointer register (X, Y, or Z). This type of addressing can be used when the address of a desired memory location is not known at the time that a program is written. Data indirect addressing is shown schematically in Figureย 13.4.9, is used to access extended I/O registers or the internal SRAM.
A long rectangle on the left has a label at the top left reading 15 and a label at the rop right reading 0. The inside of this box is labeled "X, Y, or Z register." The bottom of this rectangle has an arrow pointing to a section in another rectangle. The second rectangle is tall and wide. Itโ€™s labeled "data memory." The top right of the data memory rectangle is labeled on the right hand side as 0. The bottom right of the data memory rectangle is labeled on the right hand side as 0x08FF.
Figure 13.4.9. Data indirect addressing occurs when an operand is a pointer register whose contents point to an SRAM address.
Data indirect memory addressing can also occur with any one of the following modifications. These three modes are detailed below.
  • displacement: add a constant value to the address in pointer register Y or Z (not available with pointer register X),
  • post-increment: add one to the value in pointer register X, Y, or Z after the operation, and
  • pre-decrement: subtract one from the value in pointer register X, Y, or Z before the operation.
Data indirect with displacement addressing, shown in Figureย 13.4.10 is used when the operand address is the result of the contents of Y or Z pointer registers added to the address contained in 6 bits (q) of the instruction word. This mode is useful for writing position-independent code, since an address register can be used to stored a base address, with data access using displacements relative to the base.
A long rectangle on the left has a label at the top left reading 15 and a label at the rop right reading 0. The inside of this box is labeled "Y or Z register." The bottom of this rectangle has an arrow pointing to a circle with a plus sign in it. Another long rectangle on the left has a label at the top left reading 15 and a label at the top right reading 0. The rectangle is split into three sections with vertical dividing lines between them. The left part is labeled "OP" and the dividing line at right of this section is labeled 10. The center part is labeled "Rr/Rd" and has a label of 6. The right part is labeled "q." The q part of this rectangle has an arrow also pointing to the circle with the plus sign in it. The circle with the plus sign in it has an arrow pointing to a section of a second rectangle. The second rectangle is tall and wide. Itโ€™s labeled "data memory." The top right of the data memory rectangle is labeled on the right hand side as 0. The bottom right of the data memory rectangle is labeled on the right hand side as 0x08FF.
Figure 13.4.10. Data indirect addressing with displacement occurs when an operand is a pointer register whose contents are added to 6 bits (q) contained in the instruction word to point to an SRAM address.
Data indirect with pre-decrement addressing is used when the operand address is the contents of the X, Y or Z register, which is automatically decremented before the operation. This addressing mode is useful for accessing array contents, for example. It is depicted schematically in Figureย 13.4.11.
A long rectangle on the left has a label at the top left reading 15 and a label at the rop right reading 0. The inside of this box is labeled "X, Y, or Z register." The bottom of this rectangle has an arrow pointing to a circle with a plus sign in it. Another rectangle on the left is labeled "-1." This rectangle has an arrow also pointing to the circle with the plus sign in it. The circle with the plus sign in it has an arrow pointing to a section of a second rectangle. The second rectangle is tall and wide. Itโ€™s labeled "data memory." The top right of the data memory rectangle is labeled on the right hand side as 0. The bottom right of the data memory rectangle is labeled on the right hand side as 0x08FF.
Figure 13.4.11. Data indirect with pre-decrement addressing occurs when an operand is a pointer register whose contents are decremented prior to the instruction and then used to point to an SRAM address.
Data indirect with post-increment addressing is used when the operand address is the contents of the X, Y or Z register, which is automatically incremented after the operation. This addressing mode is also useful for accessing array contents. It is depicted schematically in Figureย 13.4.12.
A long rectangle on the left has a label at the top left reading 15 and a label at the rop right reading 0. The inside of this box is labeled "X, Y, or Z register." The bottom of this rectangle has an arrow pointing to a circle with a plus sign in it. Another rectangle on the left is labeled "1." This rectangle has an arrow also pointing to the circle with the plus sign in it. The circle with the plus sign in it has an arrow pointing to a section of a second rectangle. The second rectangle is tall and wide. Itโ€™s labeled "data memory." The top right of the data memory rectangle is labeled on the right hand side as 0. The bottom right of the data memory rectangle is labeled on the right hand side as 0x08FF.
Figure 13.4.12. Data indirect with post-increment addressing occurs when an operand is a pointer register whose contents point to an SRAM address and then is incremented after the operation.

Subsection 13.4.5 Program Memory Addressing

Program memory addressing is used to access the full program memory space. It requires at least 14 bits to address the total flash memory section on the ATmega328P. The Z pointer register is used to refer to the address in program memory. Because program memory stores 16-bit words, and the destination register can only store 8 bits of data, the Z register additionally specifies if the LOW byte or HIGH byte should be returned. Program memory addressing can also be done with a post-increment or with a pre-decrement. Program memory addressing is shown schematically in Figureย 13.4.13.
A long rectangle on the right has a label at the top left reading 15 and a label at the rop right reading 0. The inside of this box is labeled "Z register." The right side of this rectangle depicts the LSB of this register. The LSB has an arrow pointing to a larger rectangle. The left side of the rectangle also has arrows as well to a larger rectangle. The second rectangle is tall and wide. Itโ€™s labeled "program memory." The top right of the program memory rectangle is labeled on the right hand side as 0. The bottom right of the program memory rectangle is labeled on the right hand side as 0x3FFF.
Figure 13.4.13. Program memory addressing accesses the full memory space given by the address in pointer register Z. The LSB of Z indicates if the low or high byte should be returned as the result.
In direct program addressing, instructions can contain a pointer (indirect) to be loaded to the program counter, or a 16-bit word (immediate) following the instruction to load to the program counter. The program counter can also be incremented by a constant k. Program execution will then continue at that space in program memory. This is depicted in Figureย 13.4.14.
A long rectangle on the left has a label at the top left reading 31 and a label at the rop right reading 16. A vertical dividing line in the rectangle is labeled 19 at the top. The left side of the rectangle is labeled "OP." The right side of the rectangle is labeled "6 MSB." The long rectangle has a bottom portion with a label at the bottom left reading 15 and a label at the bottom right reading 0. This rectangle is labeled "16 LSB." The bottom of the "16 LSB" part of the rectangle has an arrow pointing down to another rectangle labeled "PC." This "PC" rectangle points to another rectangle which is is tall and wide. Itโ€™s labeled "program memory." The top right of the program memory rectangle is labeled on the right hand side as 0. The bottom right of the program memory rectangle is labeled on the right hand side as 0x3FFF.
Figure 13.4.14. Direct program addressing accesses the full memory space given by a pointer loaded into the program counter.
The types of instructions that use direct programming addressing include the jump instruction (JMP), which causes the program counter to load an immediate value and continue executing instructions from that location in memory and the extended indirect jump instruction (EIJUMP), which has the program counter jump to the memory location stored in pointer register Z.

Subsection 13.4.6 Bit Addressing

Bit addressing instructions contain one opcode that specifies one bit to be modified in a register. Because data registers are 8 bits wide, each bit opcode requires 3 bits (b) to specify which bit (between 0-7) is to be read from/written to. Bit addressing is depicted in Figureย 13.4.15.
A long rectangle on the left has a label at the top left reading 15 and a label at the rop right reading 0. The box is split into three sections with vertical lines separating them. The left part is labeled "OP" and the vertical line at its right has the label 8. The middle part is labeled "A" and the vertical line at its right has the label 3. The right part is labeled "b". Under the "A" part an arrow points to the side of a grid of boxes depicting different data memory addresses. To the right of the "b" part is an arrow that points to an individual bit at the top of a grid of boxes depicting different elements in data memory.
Figure 13.4.15. Bit addressing is used to access specific bits in registers.

Example 13.4.16. CBIinstructions.

The clear bit in I/O register instruction (CBI) clears a single bit in an I/O register. The instruction can only address the lower 32 I/O registers because only 5 bits are used in the instruction to define the data memory address. The 16-bit machine instruction is 10011000AAAAAbbb, where the bits denoted A represent the I/O register and the bits denoted b represent the specific bit to be cleared in the corresponding I/O register.