Before I introduce you to the addressing modes on the 68K, I want to teach you an instruction, namely move. As its name suggests, move is used to move a piece of data from one location to another. It has the following form:
move.[size] [source], [destination]
Size, can be either b (byte), w (word, 2bytes), or l (longword, 4 bytes). As an example,
move.w d0, d1
would move 1 word (2 bytes) of data from register d0 to register d1
Now it's time to get acquainted with the addressing modes on the 68K. "What is an addressing mode?", you ask. Simply put, an addressing mode is a kind of thing you can put in either the Keep in mind that while the 68K uses 32-bit addresses, it only has a 24-bit address space. The upper 8 bits are ignored so $FF0000 is equivalent to $FFFF0000.
Register Addressing:
The source or destination is a processor register. Immediate Addressing:
The source is a constant value that becomes part of the instruction. This is useful if you want to set a register or memory location to a specific value, but you don't need to do any calculations based on it ahead of time. It also is very useful in simple mathematics calculations. Oftentimes you'll find that you need to add or subtract 1 to a register. Rather than eating up another register you can use immediate addressing. Keep in mind that all immediate values must be prefixed by a #.
Example: Absolute Addressing:
Here the source or destination is a location in memory. You give the address of the location you want to use.
Examples: On a Genesis, the first example would move a longword from the header of the cartridge. That location should contain the ASCII values for the string 'SEGA'. Absolute Near Addressing:
Before I explain this mode I have to tell you a little about sign extension. Sign extension is a way of putting a smaller value in a place where a longer value belongs. What happens is that the highest bit of the smaller value is copied into all the extra values in the larger number. So when $8000 is sign extended from a word value to a longword value it becomes $FFFF8000, but when $7FFF is sign extend it it becomes $00007FFF or $7FFF. If you don't want to think in binary just remember this: If the highest hex digit is greater than 7 then the extra digits will be filled with 'F's. If the highest hext digit is less than 8 then the extra digits will be filled with 0s. Note that when I say the highest digit, I mean the highest digit in the data width. $80 as a word value has a highest digit of 0.
Absoute near addressing is similar to absolute addressing except that instead of using a longword for the address a word is used. This word is sign-extended giving you access to the first and last 32K of the memory space ($0 - $7FFF and $FF8000 - $FFFFFF).
Example: Pointer Addressing:
You remember those address registers? Now you get to use them. Let's say you want to access the same location in memory over and over again. You could include the address as part of the instruction every time using the absolute addressing mode, but that's kind of slow and innefficient. Instead, you can put the address in an address register and use that to reference the memory location. If you want to use or affect the value stored in the address register, just use the name of the register by itself. If you want to use or affect the memory location pointed to by the adress register, enclose the name of the register in parenthesis.
Examples: Pointer Relative Addressing:
Let's say you've got two values stored in RAM pretty close together, but you don't want to use two address registers and you don't want to use absolute addressing. You can point an address register at the first, and then use that address register along with an offset to access the second. An offset is a number from -$8000 to $7FFF that is added to the register to calculate the address that is used. Note, this addition is not permanent. It doesn't effect the value stored in the address register.
Example: PC Relative Addressing:
The program counter (PC) is a special address register that points to the current instruction. Although you can't treat it like an address register in most respects, you can use it for relative addressing in the same way that you use it with an address register. This will be more useful once we get to labels.
Example: Pointer Addressing with Predecrement/Postincrement:
Let's say you wanted to access a bunch of sequential memory locations. You could use relative addressing to access each location, but there is a better way. With postincrement the value in the address register is incremented by the size of the last operation each time postincrement addressing is used. With postdecrement the value in the address register is decremented by the size of the operation before the operation is completed.
Examples: Whew, that took longer than I thought it would. I know this was probably a lot of material to absorb in one sitting, but don't worry about mastering this now. Just try to remember the basic concepts and remember where to find the specifics (namely in Part II of this tutorial). If you find any of this confusing just say so and I'll do my best to explain it better.
Example:
move.w d0, d1
Equivalent:
d1 = d0
move.w #1, d0
Equivalent:
d0 = 1
move.l $100, d0 (move a longword from memory location $100 to register d0)
move.b #1, $FF0000 (store the number 1 at memory location $FF0000)
The second example would store the number 1 in the first byte of Work RAM.
move.w #1, $8000.w
Equivalent:
Memory Location $FF8000 = 1
move.l #$FF0000, a0 ;Store the address $FF0000 in a0
move.w #1, (a0) ;Store the number 1 at the memory location pointed to by a0 ($FF0000)
move.l #$FF0000, a0 ;Store address $FF0000 in a0
move.w #1, (a0) ;store the number 1 at memory location $FF0000
move.w #1, 2(a0) ;store the number 1 at memory location $FF0002
move.w #1, $100(pc) ;stores the value 1 at the memory location $100 bytes from the current instruction.
move.l #$FF0000, a0 ;store address $FF0000 in a0
move.b #7, (a0)+ ;store 7 at $FF0000 and add 1 to a0, a0 now equals $FF0001
move.b #4, (a0)+ :store 4 at $FF0001 and add 1 to a0
move.w #3, (a0)+ ;store 3 at $FF0002 and add 2 to a0
move.l #9, (a0)+ ;store 9 at $FF0004
;a0 is now equal to $FF0008
move.w #6, -(a0) ;store 7 at $FF0006