Home Teaching Glossary ARM Processors Supplements Prof issues About

68K Addressing Modes

A key concept in computing in both high-languages and low-level languages is the addressing mode. Computers perform operations on data and you have to specify where the data comes from. The various ways of specifying the source or destination of an operand are called addressing modes. We can’t discuss instructions  or low-level programming until we have introduced three fundamental concepts in addressing:

Absolute addressing (the operand specifies the location of the data)

Immediate addressing (the operand provides the operand itself)

Indirect addressing (the operand provides a pointer to the location of the data)

In absolute addressing you specify an operand by providing its location in memory or in a register. For example, ADD P,D1 uses absolute addressing because the location of the operand P is specified as a memory location. Another example of absolute addressing is the instruction CLR 1234 which means set the contents of memory location 1234 to zero.

When you specify a data register as an operand that also is an example of absolute addressing, although some call it register direct addressing.

In immediate addressing the operand is an actual value rather than a reference to a memory location. The 68K assembler indicates immediate addressing by prefixing the operand with the ‘#’ symbol; for example, ADD #4,D0 means add the value 4 to the contents of register D0 and put the result in register D0. Immediate addressing lets you specify a constant, rather than a variable. This addressing mode is called immediate because the constant is part of the instruction and is immediately available to the computer. The addressing mode is also called immediate because the operand is immediately available from the instruction and you don’t have to fetch it from memory or a register. When you specify the absolute address of a source operand, the computer has to get the address from the instruction and then read the data at that location.

Indirect addressing specifies a pointer to the actual operand which is invariably in a register. For example, the instruction, MOVE (A0),D1 , first reads the contents of register A0 to obtain a pointer that gives you the address of the operand. Then it reads the memory location specified by the pointer in A0 to get the actual data. This addressing mode requires three memory accesses; the first is to read the instruction to identify the register containing the pointer, the second is to read the contents of the register to get the pointer. The third is to get the desired operand at the location specified by the pointer.

You can easily see why this addressing mode is called indirect because the address register specifies the operand indirectly by telling you where it is, rather than what it is. Motorola calls this mode address register indirect addressing, because the pointer to the actual operand is in an address register. Consider the effect of executing MOVE (A0),D0


In the previous diagram, address register A0 points to a memory location. In this case, A0 contains 1234 and points at memory location 1234. When MOVE (A0),D0 is executed, the contents of the memory location pointed at by A0 (i.e., location 1234) are copied into data register D0. In this example, D0 will be loaded with 3254.

Why do we implement this addressing mode? Consider the following two operations

    MOVE   (A0),D0    ;copy the item pointed at by A0 into D0

    ADD    #2,A0      ;increment A0 to point to the next item

The first operation loads D0 with the 16-bit element pointed at by address register A0. The second instruction increments A0 by 2 to point to the next element. The increment is 2 because the elements are two bytes (i.e., 16 bits) wide and successive elements are two bytes apart in memory.

Address register indirect addressing allows you to step though an array or table of values accessing consecutive elements. Suppose we have a table of 20 consecutive bytes that we have to add together. We can write

    MOVE.L #Table,A0  ;A0 points to the table (A0 has the address of Table)

    CLR.B  D0         ;Use D0 to hold the sum - clear it first

    MOVE.B #20,D1     ;There are 20 numbers to add

Next ADD.B  (A0),D0    ;Add a number to the total in D0

    ADD.L  #1,A0      ;Point to the next number in the list

    SUB.B  #1,D1      ;Decrement the counter

    BNE    Next       ;Repeat until all added in

The first three instructions set up the initial values. We load A0 with the address of the numbers. The location has the symbolic name ‘Table’. The # symbol precedes table because A0 is being loaded with the address table and not the contents of that address.  Data register D0 holds the sum of the numbers and is cleared prior to its first use. Finally, we put the number 20 into D1 to count the elements as we add them.

The body of the code is in blue. The first instruction fetches the byte pointed at by A0 and adds it to the running total in D0, and the second instruction points to the next byte element in the list. Note that when we increment the pointer we use a longword operation because all pointers are 32 bits.

The last part of the program decrements the element count by one and then branches back to ‘Next’ if we haven’t reached zero. We look at the branching operations in more detail later.

The three addressing modes form a natural progression. The following table defines them in RTL and the figure illustrates these three modes.

Address Register Indirect Addressing with Postincrementing and Predecrementing

An effective computer architecture should be efficient in term of space and speed. Ideally, instructions should exist to convert common sequences of operations into a single instruction; for example, the load effective address instruction LEA (12,A0,D3.L),A2 has the same effect as the three instructions: ADDA.L D3,A0, ADDA #12,A0, and  MOVEA.L A3,A2.

We now look at how the power of the 68000's address register indirect addressing mode has been enhanced by letting the 68000 automatically alter the contents of the pointer register each time it is used.

Let's first look at a typical application of address register indirect addressing in accessing a data structure in which the individual elements are stored consecutively. For example, consider the following fragment of a program designed to fill a 16-element table (i.e., array) of bytes, called BUFFER, with zeros.

    MOVE.B  #16,D0       Set up a counter for 16 elements

    LEA     BUFFER,A0    A0 points to the first element of the array

LOOP CLR.B   (A0)         Clear the element pointed at by A0

    ADDA.L  #1,A0        Move the pointer to point to the next element

    SUB.B   #1,D0        Decrement the element counter

    BNE     LOOP         Repeat until the count is zero

There’s nothing wrong with this fragment of code and it does what it is supposed to. However, note that when we use A0 as a pointer (i.e., CLR.B (A0)), we follow it by the instruction ADDA.L #1,A0 to bump up the pointer. Because this second instruction frequently follows a memory access employing address register indirect addressing, the designers of the 68000 have provided two addressing modes to improve its efficiency: address register indirect with post-incrementing addressing, and address register indirect with pre-decrementing addressing.

Address register indirect with post-incrementing is a variation of address register indirect addressing and is also called address register indirect with autoincrementing. The basic operation is the same as address register indirect, except that the contents of the address register from which the operand address is derived are incremented by 1, 2 or 4 after the instruction has been executed. A byte operand causes an increment by 1, a word operand by 2, and a longword by 4.

An exception to this rule occurs when the stack pointer, A7, is used with byte addressing. The contents of A7 are then automatically incremented by 2 rather than one. This restriction is intended to keep the stack pointer always pointing to an address on a word boundary. Some examples should clarify the action of this addressing mode.

Assembly language form           RTL definition                    Action

MOVE.B (A0)+,D3                [D3] ¬ [[A0]]                    The contents of the memory location whose address                                                         [A0] ¬ [A0] + 1                 is in A0 are copied into register D3. The contents of A0                                                                                                     are then increased by 1.

MOVE.L (A0)+,D3              [D3] ¬ [[A0]]                     The contents of the memory location whose address                                                       [A0] ¬ [A0] + 4                 is in A0 are copied into register D3. The contents of A0 are                                                                                                    then increased by 4.

MOVE.W (A7)+,D4               [D40:15] ¬ [[A7]]               The 16-bit contents of the location whose address                                                          [A7] ¬ [A7] + 2                 is in A7 are copied into the lower order 16 bits of D4.                                                                                                    The contents of A7 are then increased by 2.

MOVE.B (A7)+,D4                [D40:7] ¬ [[A7]]               The 8-bit contents of the location whose address                                                        [A7] ¬ [A7] + 2                is in A7 are copied into the lower order 8 bits of D4.                                                                                                    The contents of A7 are then increased by two, rather than one,                                                                                                    because A7 is the stack pointer.

Figure 4.18 illustrates the effect of the 68000's autoincrementing mechanism. The state of the system before and after the execution of a MOVE.B (A0)+,D0 instruction is described. Before the instruction is executed, A0 points at location 1001. After execution, it points at location 1002. The increment is by one because the operand is a byte.

Figure 4.18  The effect of auto-incrementing on an address register

Consider again the fragment of a program designed to fill a 16-element array of byte with zeros. This time we will use the post-incrementing variation of address register indirect addressing.

    MOVE.B  #16,D0  Set up a counter for 16 elements

    LEA     BUFFER,A0 A0 points to the first element of the array

LOOP CLR.B   (A0)+ Clear an element and move the pointer to the next one

    SUB.B   #1,D0 Decrement the element counter

    BNE     LOOP Repeat until the count is zero

Let's look at a second example of this addressing mode. Suppose that a program employs two data tables, each N bytes long, and it is necessary to compare the contents of the tables, element by element, to determine whether they are identical. The following program will do this. The work is done by the CMPM (A0)+,(A1)+ instruction, that compares the contents of the element pointed at by A0 with the contents of the element pointed at by A1, and then increments both pointers. The mnemonic CMPM used in this program stands for compare memory with memory.

TABLE_1 EQU    $002000     Location of Table 1

TABLE_2 EQU    $003000     Location of Table 2

N       EQU    $30         48 elements in each table




       LEA    TABLE_1,A0  A0 points to the top of Table 1

       LEA    TABLE_2,A1  A1 points to the top of Table 2

       MOVE.B #N,D0       D0 is the element counter

NEXT    CMPM.B (A0)+,(A1)+ Compare a pair of elements

       BNE    FAIL        IF not the same THEN exit to FAIL

       SUB.B  #1,D0       ELSE decrement the element counter

       BNE    NEXT        REPEAT until all done

SUCCESS .                  Deal with success (all matched)



FAIL       .               Deal with fail (not all matched)

Address Register Indirect with Pre-decrement Addressing

This variant of address register indirect addressing is similar to the one above, except that the specified address register is decremented before the instruction is carried out. As before, the decrement is by 4, 2, or 1, depending on whether the operand is a long word, a word, or a byte, respectively. Figure 4.19 demonstrates how this addressing mode differs from address register indirect addressing with post-incrementing.

As you can see from figure 4.19, the address register is decremented before it is used to access an operand in memory. The following two definitions in RTL show how this addressing mode can be applied to word and longword operands.

Assembly language form      RTL definition           Action

MOVE.W -(A7),D4           [A7] ¬ [A7] - 2        The contents of address register A7 are first

                                                   [D40:15] ¬ [[A7]]     decremented by 2. The contents of the memory location                                                                                       pointed at by A7 are moved into register D4.

MOVE.L -(A0),D3            [A0] ¬ [A0] - 4       The contents of address register A0 are first

                                                   [D3] ¬ [[A0]]         decremented by 4. The contents of the memory location

                                                                                     pointed at by A0 are then moved into register D3.

Figure 4.19  The effect of auto-decrementing on an address register

Why does the 68000 support both post-incrementing and pre-decrementing, and why does one mode act on the contents of an address register after it is used to access an operand and the other before it is used? One reason for implementing both incrementing and decrementing modes is that the programmer can step through a table in both directions (from top-down or from bottom-up). We will explain why the 68000 implements post-incrementing and pre-decrementing when we demonstrate how these addressing modes are used to implement a stack.

We now demonstrate an example that employs both of these two addressing modes. The order of the 16 bytes in a region of memory called BUFFER is to be reversed. For example, the sequence


is be reversed to give


There are many ways of reversing the numbers. One method is to swap the top element with the bottom element, and then the next element down from the top with the next element up from the bottom, and so on.

We will employ a very simple but rather crude technique to reverse the order of the numbers. The contents of BUFFER are copied into a second region of memory, BUFFER1, using post-incrementing for both source and destination operands (i.e., MOVE.B (A0)+,(A1)+), see figure 4.20. Having made a copy of the data, all we have to do is to copy the contents of BUFFER1 back into BUFFER in the reverse order. To do this we set A1 to the top of BUFFER1 and move down, and leave A0 pointing to the bottom of BUFFER and move up. The data transfer is carried out by MOVE.L -(A1),(A0)+.

     MOVE.B  #16,D0           Set up a counter for 16 elements

     LEA     BUFFER,A0        A0 points to first element of the source array

     LEA     BUFFER1,A1       A1 points to first element of the destination array

LOOP  MOVE.B  (A0)+,(A1)+      Move an element from its source to its destination

     SUB.B   #1,D0            Decrement the element counter

     BNE     LOOP             Repeat until the count = zero and all elements moved


*     At the end of this operation A0 points to one location beyond

*     (i.e., higher than) BUFFER and A1 points to one location beyond BUFFER1    


     MOVE.B  #16,D0           Reset the counter for 16 elements

     LEA     BUFFER1,A0       A1 points to first element of the destination array

LOOP1 MOVE.B  -(A1),(A0)+      Move an element from BUFFER1 to BUFFER

     SUB.B   #1,D0            Decrement the element counter

     BNE     LOOP1                                Repeat until the count is zero

Using both post-incrementing and pre-decrementing

Figures missing