Addressing Modes
When using an arithmetic instruction, the application programmer must be able to specify the instruction’s explicit operands. Operands may be constants, the contents of registers, or the contents of memory locations. Hence, the processor has to provide means to specify the type of the operand. While every processor allows you to specify the above-mentioned types, access to memory locations can be done in many different ways depending on what is required. So the number and types of addressing modes provided is another important characteristic of any processor. There are numerous addressing modes2 , but we will restrict ourselves to the most common ones.
immediate/literal: Here, the operand is a constant. From the application programmer’s point of view, processors may either provide a distinct instruction for constants (like the LDI —load immediate— instruction of the ATmega16), or require the programmer to flag constants in the assembler code with some prefix like #.
register: Here, the operand is the register that contains the value or that should be used to store the result. direct/absolute: The operand is a memory location. register indirect: Here, a register is specified, but it only contains the memory address of the actual source or destination. The actual access is to this memory location.
autoincrement: This is a variant of indirect addressing where the contents of the specified register is incremented either before (pre-increment) or after (post-increment) the access to the memory location. The post-increment variant is very useful for iterating through an array, since you can store the base address of the array as an index into the array and then simply access each element in one instruction, while the index gets incremented automatically.
autodecrement: This is the counter-part to the autoincrement mode, the register value gets decremented either before or after the access to the memory location. Again nice to have when iterating through arrays.
displacement/based: In this mode, the programmer specifies a constant and a register. The contents of the register is added to the constant to get the final memory location. This can again be used for arrays if the constant is interpreted as the base address and the register as the index within the array.
indexed: Here, two registers are specified, and their contents are added to form the memory address. The mode is similar to the displacement mode and can again be used for arrays by storing the base address in one register and the index in the other. Some controllers use a special register as the index register. In this case, it does not have to be specified explicitly.
memory indirect: The programmer again specifies a register, but the corresponding memory location is interpreted as a pointer, i.e., it contains the final memory location. This mode is quite useful, for example for jump tables.
Table 2.2 shows the addressing modes in action. In the table, M[x] is an access to the memory address x, d is the data size, and #n indicates a constant. The notation is taken from [HP90] and varies from controller to controller.
As we have already mentioned, CISC processors feature more addressing modes than RISC processors, so RISC processors must construct more complex addressing modes with several instructions. Hence, if you often need a complex addressing mode, a CISC machine providing this mode may be the wiser choice.
Before we close this section, we would like to introduce you to a few terms you will often encounter:
Ø An instruction set is called orthogonal if you can use every instruction with every addressing mode.
Ø If it is only possible to address memory with special memory access instructions (LOAD, STORE), and all other instructions like arithmetic instructions only operate on registers, the architecture is called a load/store architecture.
Ø If all registers have the same function (apart from a couple of system registers like the PC or the SP), then these registers are called general-purpose registers.
Table 2.2: Comparison of addressing modes.