Motorola 68000: addressing modes
By Leonardo Giordani -
The Motorola 68000 is an impressive microprocessor, and this is reflected by the large amount of addressing modes that it provides; it is actually surprising, for people used to the x86 family, to find in this microprocessor's Assembly language constructs that are very similar to the ones provided by high level languages such as pre- and postdecrements, or multiconditional branching instructions.
The processor provides 6 different addressing modes, each of which has multiple versions, for a grand total of 14. The specific instruction used to manipulate the data can also work on different data sizes, but these variations are not considered here, being features of the instruction and not of the addressing mode.
Addressing refers to the format of the effective address (ea
or EA
in many manuals), that is the representation of the source or destination of an instruction. Remember that not all the instructions support all 14 modes, so whenever you read ea
remember that we are talking about data which address can be represented by one or more of those modes.
The syntax of the movea
instruction, for example, is movea <ea>, An
, which tells us that the source is one of the 14 possible combinations presented here, while the destination is one of the address registers a1-a6
. Strictly speaking, however, the syntax of the instruction is movea <ea1>, <ea2>
, where <ea1>
can be one of the 14 modes, and <ea2>
can only be an address register (Address Register Direct Mode).
The addressing mode is encoded using three fields of the binary instruction. The EA Mode field, the EA register field, and the Extension words. The first two are 3-bit fields contained in the instruction word, which combination uniquely identifies the addressing mode and the number of the register, in case this is needed. The extension words, instead, are words that follow the instruction word in memory, and that usually represent actual 8-, 16-, or 32-bit numbers.
Sign extension¶
Before we discuss the addressing modes provided by the MC68000 it is worth explaining the sign-extension mechanism used by this processor. Sometimes addressing modes use 8-bit or 16-bit data instead of a full long word, for example to provide a constant that is added to a register before using its value. Calculations inside the microprocessor, however, are always performed on 32-bits numbers, so such values are extended to a long word.
There are two ways to extend a byte/word to a long word. One is to pad with zeroes on the left (unsigned extension) and the other is to pad preserving the sign (signed extension). While this doesn't change positive numbers it affects negative ones. Let's consider an 8-bit negative number like -126, which is represented by 10000010
in 8-bit two's complement, 0x82
in hexadecimal. A 32-bit signed extension of this number becomes 0xffffff82
, which is still -126 in 32-bit two's complement, but an unsigned extension would give 0x00000082
, which is 130.
While the MC68000 can use both address and data registers for general-purpose data storage, the two categories are meant to manage data of different nature. In particular, data registers never sign-extend bytes or words, as this would change the pure representation of that sequence of bits, adding spurious bits to keep the sign. Addressed, instead, should never change their value, so the address registers sign-extend incoming values to preserve the real address or displacement represented by the bits.
Addressing Modes¶
Register Direct¶
This is the simplest addressing mode, as it reads or writes data in one of the microprocessor's registers. There are two versions of it, one for data registers and one for address registers.
Data Register Direct¶
- Assembly syntax:
Dn
- EA Mode field:
000
- EA Register field: Register number
- Extension words: 0
This mode addresses the data contained in one of the data registers d0-d7
. The EA Mode field is 000
and the EA Register field contains the register number. The official documentation uses the syntax Dn
to identify this mode. No extension words are used.
cmpi.w #0x1111,d1
Compare
+----------+
| 0x1111 |
+----------+
d1 0x12ca ------------> | 0x12ca |
+----------+
Address Register Direct Mode¶
- Assembly syntax:
An
- EA Mode field:
001
- EA Register field: Register number
- Extension words: 0
This mode identifies the data contained in one of the address registers a0-a6
. The EA Mode field is 001
and the EA Register field is the number of the register, while the official syntax for it is An
. No extension words are used.
cmpi.w #0x1111,a1
Compare
+------------+
| 0x1111 |
+------------+
a1 0xfc1d28 ----------> | 0xfc1d28 |
+------------+
Register Indirect¶
As the name of this mode suggests, the addressing is performed using a register, but the data is accessed indirectly. The register doesn't contain the data we want to use, but the address in memory of the data. This is what higher level languages like C call memory pointer.
Address Register Indirect¶
- Assembly syntax:
(An)
- EA Mode field:
010
- EA Register field: Register number
- Extension words: 0
The simplest form of indirect access is when the address of the data is stored in one of the address registers a0-a6
. The syntax for this mode is (An)
, while the binary form has the EA Mode field set to 010
and the EA Register field represents the number of the address register in use. No extension words are used.
The following example compares the number 0x1111
with the content of the memory cell which address is contained in a1
cmpi.w #0x1111,(a1)
a1 0xfc1d28
| 0xfc1d24 | | Compare
| +---------+ +----------+
| 0xfc1d26 | | | 0x1111 |
| +---------+ +----------+
+------------> 0xfc1d28 | 0x13c | -----------> | 0x13c |
+---------+ +----------+
0xfc1d2a | |
+---------+
0xfc1d2c | |
Address Register Indirect with Postincrement¶
- Assembly syntax:
(An)+
- EA Mode field:
011
- EA Register field: Register number
- Extension words: 0
This addressing mode is another of the high-level languages constructs that the MC68000 provides directly in its Assembly language. This mode works exactly like the Address Register Indirect, but after the data has been fetched from memory the address register is incremented by the size of the data itself. So, this addressing mode is perfectly suited for algorithms that need to read consecutive arrays from memory, as there is no need to add instructions that increment the pointer.
cmpi.w #0x1111,(a1)+
a1 0xfc1d28
^ | 0xfc1d24 | | Compare
| | +---------+ +----------+
| | 0xfc1d26 | | | 0x1111 |
+----+ v +---------+ +----------+
| +2 | <--+------------> 0xfc1d28 | 0x13c | -----------> | 0x13c |
+----+ +---------+ +----------+
0xfc1d2a | |
+---------+
0xfc1d2c | |
The standard syntax is (An)+
, and for this mode, the EA Mode field is 011
, while the EA Register field contains the register number. No extension words are used.
This mode and the following one are very powerful, as they automatically add to the address the size of the data that has been read, so 1 for a byte read, 2 for a word, and 4 for a long word. The only exception to this rule is when the register is a7
, which is an alias for sp
, the system Stack Pointer. In that case the pointer is always kept aligned to a word boundary, so the increment is 2 even for a byte read.
Address Register Indirect with Predecrement¶
- Assembly syntax:
-(An)
- EA Mode field:
100
- EA Register field: Register number
- Extension words: 0
This is the specular version of the previous mode, where the address register used to point to the data is decremented before the addressing is performed. The standard syntax is -(An)
; the EA Mode field is 100
and the EA Register field contains the register number. No extension words are used.
cmpi.w #0x1111,-(a1)
a1 0xfc1d28
^ |
| v
| +----+
| | -2 | 0xfc1d22 | | Compare
| +----+ +---------+ +----------+
| | 0xfc1d24 | | | 0x1111 |
| v +---------+ +----------+
+-------+----------> 0xfc1d26 | 0x13c | -----------> | 0x13c |
+---------+ +----------+
0xfc1d28 | |
+---------+
0xfc1d2a | |
Address Register Indirect with Displacement¶
- Assembly syntax:
(d16,An) / d16(An)
- EA Mode field:
101
- EA Register field: Register number
- Extension words: 1
The natural evolution of the previous two addressing modes is to use an arbitrary offset that is added to the base address contained in the register. The standard syntax for this mode is (d16,An)
or d16(An)
, where d16
is a 16-bit signed integer. So for example 0xf(a1)
is the data contained in memory at the address a1 + 0xf
. The EA Mode field is 101
and the EA register fields is the number of the address register used. This address mode requires 1 extension word that contains the 16-bit displacement.
cmpi.w #0x1111,0x140(a1)
a1 0xfc1d28
|
v
+---+
0x140 -> | + | 0xfc1e64 | | Compare
+---+ +---------+ +----------+
| 0xfc1e66 | | | 0x1111 |
v +---------+ +----------+
+------------> 0xfc1e68 | 0x13c | -----------> | 0x13c |
+---------+ +----------+
0xfc1e6a | |
+---------+
0xfc1e6c | |
Please note that the displacement is fixed to 16-bit, so its value limited in the range (-32768,32767)
; the displacement is however sign-extended to 32-bit before being added to the base address.
Note: this mode is sometimes called "Register Indirect with Offset".
Address Register Indirect with Index¶
- Assembly syntax:
(d8,An,Dn)
- EA Mode field:
110
- EA Register field: Register number
- Extension words: 1
Besides an addressing mode that mimics C-style loops and a way to perform random access of arrays through a 16-bit displacement, the MC68000 provides a double-indexed array access with this addressing mode. The base address contained in one of the address registers is added to the content of a 16/32-bit register and an 8-bit index. This address mode requires 1 extension word that contains the 8-bit index; only the 8 least significant bits of the extension words are kept and sign-extended to 32-bits before any calculation.
cmpi.w #0x1111,(0x4,a1,d0)
a1 0xfc1d28 d0 0x140
| |
v |
+---+ |
| + | <--------+
+---+
|
v
+---+
0x4 --> | + | 0xfc1e68 | | Compare
+---+ +----------+ +----------+
| 0xfc1e6a | | | 0x1111 |
v +----------+ +----------+
+------------> 0xfc1e6c | data | -----------> | 0x13c |
+----------+ +----------+
0xfc1e6e | |
+----------+
0xfc1e70 | |
For this mode the EA Mode field is set to 110
and the EA Register field contains the number of the address register in use. The standard syntax used by manuals is (d8, An, Dn.SIZE)
, where SIZE
can be either w
or l
. This addressing mode can provide an invaluable way to access two-dimensional arrays, and once again shows how powerful this microprocessor is.
Note: this mode is sometimes called "Indexed Register Indirect with Offset"
Absolute Data¶
These modes provide a version of the Address Register Indirect mode where the address is specified directly in the instruction and not through a register.
Absolute Short Data¶
- Assembly syntax:
<address>.w
- EA Mode field:
111
- EA Register field:
000
- Extension words: 1
This mode specifies the address of the data in memory through a 16-bit direct operand specified in the extension word. The standard syntax is <address>.w
, while the EA mode and EA register fields are respectively 111
and 000
. Since the address is a signed word, only the first or the last 32KiB of memory can be addressed (respectively using positive and negative addresses).
Absolute Long Data¶
- Assembly syntax:
<address>.l
- EA Mode field:
111
- EA Register field:
001
- Extension words: 2
This is the 32-bit version of the previous mode, with EA mode and EA register fields set respectively to 111
and 001
. The standard syntax is <address>.l
, and it requires two extension words. As always in the MC68000 long words are given in big endian order, that is the first word is the most significant part of the address and the second word is the least significant one.
It is worth noting that this mode overcomes the limitation of the previous one, allowing you to access the full 16MiB address space. However, it requires more memory space, having two extension words, and 4 additional CPU cycles to be executed.
Program Counter Relative¶
The addressing modes relative to the Program Counter (PC) are the fundamental building block of relocatable programs, as the effective address is computed as a displacement from the address of the current instruction being executed. Strictly speaking the base address is that of the extension word, as will be shown in detail later in this article.
Please note that effective addresses expressed with Program Counter Relative can only be used to read from memory.
Program Counter Relative with Displacement¶
- Assembly syntax:
(d16,PC)
ord16(PC)
- EA Mode field:
111
- EA Register field:
010
- Extension words: 1
This mode is very similar to Address Register Indirect with Displacement, as both use a 16-bit offset added to a base address; in this case the latter is provided by the PC instead of an address register. The EA mode field is 111
and the EA Register field is 010
. One extension word is needed, to provide the signed 16-bits displacement, extended to 32-bit before any other calculation.
Note: this mode is sometimes called "Program Counter Relative with Offset".
Program Counter Relative with Index¶
- Assembly syntax:
(d8,Dn,PC)
- EA Mode field:
111
- EA Register field:
011
- Extension words: 1
This is the Program Counter version of Address Register Indirect with Index. The EA mode field is 111
and the EA Register field is 011
. One extension word is needed, to provide the signed 8-bits displacement, which will be extended to 32 bit before using it.
Note: this mode is sometimes called "Program Counter Relative with Index and Offset".
Immediate Data¶
- Assembly syntax:
#<data>
- EA Mode field:
111
- EA Register field:
100
- Extension words: 1,2
Immediate data uses the plain data written in the extension words instead of referring to the system memory. In this mode you can specify a constant of any length (byte, word, long word). The EA mode and EA register fields are respectively 111
and 100
, and the number of extension words is either 1 (byte and word) or 2 (long word). Remember that the 68000 sign-extends data only when the destination is an address register, leaving it untouched when a data register is used. The standard syntax for this addressing mode is #<data>
Quick Immediate¶
This addressing mode is available for a set of 3 instructions only, namely addq
, subq
, and moveq
. For the first two instructions, it allows to specify a value between 1 and 8 (3 bits), while the third one can interact with a full signed byte, managing a value between -128 and 127. The "quick" label comes from the fact that the instructions use bits of their own binary representation to store the data, thus requiring no extension words. As happens for the simple Immediate Data addressing, EA mode field is 111
and EA Register field is 100
.
Implied¶
This is another mode that is available only for some instructions. Those are bound to specific registers, and are thus not really allowing any generic effective address to be used. The registers used in this addressing mode are only SP
, PC
, SP
, SSP
, SR
, and USP
.
Table of addressing modes¶
The following table gives an overview of all the addressing modes. For each of them I show the name, the standard Assembly syntax, the value of the EA Mode field, the value of the EA Register field, and the number of extension word required.
Name | Syntax | EA Mode | EA Register | Extension words |
---|---|---|---|---|
Data Register Direct | Dn |
000 |
Reg. number | 0 |
Address Register Direct Mode | An |
001 |
Reg. number | 0 |
Address Register Indirect | (An) |
010 |
Reg. number | 0 |
Address Register Indirect with Postincrement | (An)+ |
011 |
Reg. number | 0 |
Address Register Indirect with Predecrement | -(An) |
100 |
Reg. number | 0 |
Address Register Indirect with Displacement | (d16,An) or d16(An) |
101 |
Reg. number | 1 |
Address Register Indirect with Index | (d8,Dn,An) |
110 |
Reg. number | 1 |
Absolute Short Data | <address>.w |
111 |
000 |
1 |
Absolute Long Data | <address>.l |
111 |
001 |
2 |
Program Counter Relative with Displacement | (d16,PC) / d16(PC) |
111 |
010 |
1 |
Program Counter Relative with Index | (d8,Dn,PC) |
111 |
011 |
1 |
Immediate | #<data> |
111 |
100 |
1,2 |
Examples¶
Let's consider some example of actual MC68000 code that uses effective addressing modes.
Example 1¶
0280 0003 ffff andi.l #0x3ffff,d0
This instruction uses the the Data Register Direct mode to address register d0
. The instruction format of andi
is the following
| 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | SIZE | EFFECTIVE ADDRESS |
| | | MODE | REGISTER |
which in the example shown above translates to
00000010 10 000 000 0000000000000011 1111111111111111
^ ^ ^ ^
andi long Dn d0
So the microprocessor expects the instruction to be followed by two extension words (long), that will contain the immediate data that will be added to the register. The register is selected among the data ones because the EA Mode field is 000
, and the EA Register field selects register number 0. The two following extension words are 0003
and ffff
, so the number 0x3ffff
is added to the register.
Example 2¶
2052 movea.l (a2),a0
The movea
instruction moves data into an address register, but in this case uses the Address Register Indirect mode to specify the source. The instruction format is
| 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
| 0 | 0 | SIZE | DEST. REG. | 0 | 0 | 1 | SOURCE EFFECTIVE ADDRESS |
| | | | | MODE | REGISTER |
so in this case the hexadecimal code 2052
becomes
00 10 000 001 010 010
^ ^ ^ ^
long a0 (An) a2
Example 3¶
397c 0200 0100 move.w #0x200,0x100(a4)
This move
instruction puts a word with the value 0x200
into an address which is 0x100
above the address pointed by a4
. It uses Immediate Data for the source and Address Register Indirect with Displacement for the destination. The format of the move
instruction is
| 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
| 0 | 0 | SIZE | DEST. EFFECTIVE ADDRESS | SOURCE EFFECTIVE ADDRESS |
| | | REGISTER | MODE | MODE | REGISTER |
(please note that register and mode are swapped in the destination part)
In this case we have
00 11 100 101 111100
^ ^ ^ ^ ^
move word a4 (d16,An) Immediate Data
It is interesting to note that the word for the source is given with Immediate Data, and is indeed just after the instruction (0x0200
), followed by the 16-bit displacement for Address Register Indirect with Displacement (0x0100
).
LEA: Load Effective Address¶
Many newcomers to Assembly are confused by the need of the lea
instruction, so I want to briefly show why we need it, and dig into its low-level representation to clarify possible doubts.
As we saw in the previous sections there are three ways to manage data in the M68000 Assembly language: the first is to mention a pure number, the second is to use a register, and the third is to use a memory address. Registers can be considered memory, but since they are not proper arrays I will consider them something different.
The Immediate Data addressing mode allows us to use pure data in an instruction. For example we may write move.l #0x20000,d0
, which puts the number 0x20000
into the first data register. So when we mention a pure number the microprocessor uses its binary representation directly.
When we mention a register, the microprocessor does the only thing it can do with it, that is it reads its value or writes into it. The instruction mentioned previously, move.l #0x20000,d0
, puts the number into the register d0
. An instruction like cmp.l d2,d3
, instead, reads the value of both registers and performs the comparison.
Memory addresses are similar to registers, but they are identified by a number and not by a name (and are part of a contiguous array). Whenever an instruction mentions a memory address the microprocessor automatically tries to access that location, to read or to write. An instruction like move.l 0x4,d3
moves into d3
the content of the address 0x4
, and this happens just because 0x4
is a memory address.
That said, the problem we face is that often we want to compute a memory address and deal with its value and not with its content. For example, if we write move.w 0xe(a1),d0
, the microprocessor computes a1 + 0xe
, that is, the content of a1
plus the number 0xe
, and then fetches the content of that address in memory, putting it into d0
. How can we compute a1 + 0xe
and put that result into d0
?
This is where lea
comes into play. This instruction loads the effective address computed by the addressing mode that we are using into an address register. So lea 0xe(a1),a2
puts the sum between the content of a1
and 0xe
into the register a2
. Familiarising with lea
is very important, as it is one of the most important instructions that the Motorola 68000 provides. A quick analysis of the Amiga Kickstart code shows that lea
is the 4th most used instruction, after move
, jsr
, and bra
.
Program Counter Relative syntax and representation¶
As we discussed previously, the two Program Counter Relative modes just mirror Address Register Indirect with Displacement and Address Register Indirect with Index, binding them to the Program Counter instead of a generic register. It is worth however digging exactly into what the microprocessor is doing when decoding this addressing mode, and what the standard Assembly representation means.
To describe the mechanism behind this modes let's consider an example of actual M68000 code
00000364: 41fa ffa6 lea 0x30c(pc),a0
This lea
instruction stores the address 0x30c
into a0
, but it's pretty evident that this address mode doesn't work like the traditional Address Register Indirect with Displacement. The instruction is at address 0x364
and if we read the displacement as usual we would expect the effective address to be at 0x364 + 0x30c
. It is important to understand that this is what the Assembler (or the disassembler) shows, and that the proper meaning of 0x30c(pc)
is "the address 0x30c
knowing that this instruction is at 0x364
". I believe this clearly shows why relocatable code makes use of this addressing mode. The address that we identify with 0x364
might actually be anywhere in memory, as this number means only 0x364
words after the first instruction (which is at 0x0
in our relative space).
The binary representation of the instruction is actually revealing. The hexadecimal values of the two words 41fa ffa6
become 01000001111110101111111110100110
which can be split as follows
0100 000 111 111010 1111111110100110
^ ^ ^ ^
lea a0 (d16,PC) extension word
According to the documentation of the addressing mode, the extension word 1111111110100110
is a signed 16-bit displacement, so it is a number expressed in two's complement notation. The conversion gives -0x5a
, which added to the instruction relative address 0x364
surprisingly gives 0x30a
.
The documentation of the addressing mode, however, states that
In this mode, the operand is in memory. The address of the operand is the sum of the address in the program counter (PC) and the sign-extended 16-bit displacement integer in the extension word. The value in the PC is the address of the extension word.
(2.2.11, page 13)
The thing that can be easily overlooked is that the PC points to the extension word and not to the instruction word. In this case, while the instruction word is at 0x364
, the extension word is at 0x366
, and 0x366 - 0x5a
gives exactly 0x30c
, which is what the Assembly syntax shows us. As you can see, the Assembler and the Disassembler have to perform some calculations to show the actual relative final value.
Resources¶
- Motorola M68000 Family Programmer's Reference Manual PDF here
- M68000 Microprocessors User's Manual PDF here
- The 68000 Principles and Programming, Leo J. Scanion, 1981
Updates¶
2017-12-24: Reddit user SpaceShrimp pointed out the rage of a signed 16-bit number is (-32768,32767)
and not (-32767,32768)
. Thanks!
2023-11-16: René W. Olsen spotted a mistake in the Address Register Indirect with Index, where the two registers An
and Dn
were swapped. Thanks René!
Feedback¶
Feel free to reach me on Twitter if you have questions. The GitHub issues page is the best place to submit corrections.
Related Posts

Exploring the Amiga - Part 8
Updated on

Exploring the Amiga - Part 7
Updated on

Exploring the Amiga - Part 6
Updated on

Exploring the Amiga - Part 5
Updated on

Exploring the Amiga - Part 4
Updated on

Exploring the Amiga - Part 3
Updated on

Exploring the Amiga - Part 2
Updated on

Exploring the Amiga - Part 1
Updated on
