loading...
All Genesis articles | Back to top

SEGA Genesis: Motorola 68000

Motorola 68000 Reference Manual

This page serves as a extended cheat sheet, condensing selected information from MC68000 assembler manuals and adding some useful examples. This is by no means a comprehensive guide to MC68000 assembler code.

The information here is system agnostic, and should be the same for all MC68000 systems, Sega Megadrive/Genesis, Commodore Amiga, Neo Geo, etc.

Table of contents:

Useful References

Instruction References

M68000 Family Resident Structured Assembler Reference Manual

Instruction Timing

These pages basically contain the same information, pick the one you like the most:

Overview

A list of potentially useful one-liners:

--------------------------------------------------------------------------
Example One-liners

Code                    Description
--------------------------------------------------------------------------
move.l  0,a0            a0 = *(0)    (direct addressing)
move.l  #0,a0           a0 = 0       (immediate)
move.w  (a0,d0),d1      d1 = a0[d0]  (indirect, indexed)
clr.w   d0              d0 = 0

lea     0,a0            a0 = 0
lea     4(a7),a7        a7 = a7 + 4
lea     0(a2,d0.w),a2   a2 = a2 + d0

add.l   d0,a2           a2 = a2 + d0
subq.w  #2,a3           a3 = a3 - 2
muls.w  #8,d0           d0 *= 8
lsl.w   #1,d0           d0 <<= 2 / d0 *= 2 (assumes unsigned int)
lsl.w   #8,d0           d0 <<= 8 (max shift bits)

not.w   d0              inverts all bits
exg     d0,d1           exchange two registers
nop                     no operation
--------------------------------------------------------------------------

Here's a table of examples that may help clarify certain edge cases related to instruction data size and other issues:

--------------------------------------------------------------------------
Clarifying Examples

                  ------- D0 -------   ------- *0 -------
Code              before    after      before    after
--------------------------------------------------------------------------
swap   d0         AAAABBBB  BBBBAAAA
add.b  #$20,d0    FFFFFFFF  FFFFFF1F
sub.b  #$20,d0    FFFFFF00  FFFFFFE0
move.b #$20,D0    FFFFFFFF  FFFFFF20
move.w #$20,D0    FFFFFFFF  FFFF0020
move.l #$20,D0    FFFFFFFF  00000020
move.b #$20,(0)                        FFFFFFFF  20FFFFFF
move.w #$20,(0)                        FFFFFFFF  0020FFFF
move.l #$20,(0)                        FFFFFFFF  00000020
and.b  #$F,d0     FFFFFFF1  FFFFFF01
and.w  #$F,d0     FFFFFFF1  FFFF0001
lsl.b  #4,d0      00000012  00000020
lsl.w  #4,d0      00001234  00002340
lsl.l  #4,d0      12345678  23456780
--------------------------------------------------------------------------

The MC68000 has a lot of useful addressing modes, here's an overview.

--------------------------------------------------------------------------
MC68000 Addressing Modes

Addressing Mode        Example                  Description              
--------------------------------------------------------------------------

Immediate Mode: Data specified in code ...................................
Immediate              moveq   #5, d0           Load immediate 5 into d0 


Absolute Mode ............................................................
Absolute Short         move.b  $1000, d0        Byte from addr $1000     
Absolute Long          move.l  $00100000, d1    Long from addr $00100000 


Direct Mode: Data in registers ...........................................
Data Register Direct   move.b  d0, d1           Byte from d0 to d1       
Address Reg. Direct    move.l  a0, a1           Address from a0 to a1    


Indirect Mode: Address register points to data ...........................
Address Reg. Indirect  move.b  (a0), d0         Byte from address in a0  
Post-Increment         move.w  (a0)+, d1        Word from (a0), then a0+2
Pre-Decrement          move.l  -(a1), d2        a1-4, then load long     
Displacement           move.b  4(a2), d3        Byte at a2 + 4
                                                Displacement is a 16-bit
                                                signed int
Indexed                move.w  0(a3,d4.w), d5   Word at a3 + d4          


PC Relative ..............................................................
PC Relative Displ.     move.w  6(pc), d2        Word from PC + 6         
PC Relative Indexed    move.b  0(pc,d3.w), d4   Byte at PC + d3          

--------------------------------------------------------------------------

The Move Instruction

Motorola 68000 Die

Here are some clarifying examples of how the MOVE instruction works.

  move.l    #$12345678,d0  ; d0 = $12345678
  move.b    d0,d1          ; d1 = $78

If memory contains:

  addr      data
  $00000000 $12345678

  move.l    0,d0           ; d0.l = $12345678
  move.w    0,d1           ; d1.w = $1234
  move.b    0,d2           ; d2.b = $12

Address registers:

  lea      0,a0            ; a0 = 0
  move.l   #0,a0           ; a0 = 0
  move.l   #$FF,(a0)       ; Write $000000FF to address 0

Displacement addressing:

  lea     0,a0             ; a0 = 0
  move.w  #$17,2(a0)       ; Write $17 to address 2

Note that the displacement always is measured in BYTES, regardless of data size.

--------------------------------------------------------------------------
Move Variants

Example                     Description
--------------------------------------------------------------------------
moveq    #127,d0            move to data register, only [-128;127].
                            - optimized form of move.b

movea.l  #$12345678,a0      only way to MOVE to an address reg.
                            - Assembler will automatically generate this
                              from move.l #$12345678,a0

movem.l  d0-d7/a0-a6,-(sp)  move multiple registers
--------------------------------------------------------------------------

Bit Manipulation

--------------------------------------------------------------------------
Example One-liners

Code                    Description
--------------------------------------------------------------------------
not.w   d0              d0 = ~d0          Invert all bits
and.w   #%11111000,d0   d0 &= 0b11111000  Set lower 3 bits to 0
or.w    #%00000111,d0   d0 |= 0b00000111  Set lower 3 bits to 1
--------------------------------------------------------------------------

Set first 3 bits of D0 to %101

  and.w   #%11111000,d0
  or.w    #%00000101,d0

Branching

If d0 == 7, do stuff

    cmp.w  d0,#7    ; compute 7-d0 and set CC flags (ignore result)
    beq    .done    ; branch if flag Z is set
    ...             ; do stuff if flag Z is NOT set
.done

If d0 != 0, do stuff

   tst.w  d0        ; set Z if d0 is 0
   bne    .done     ; branch if flag Z is not set
   ...              ; do stuff if flag Z IS set
.done

The Condition Code Register (CCR, lower byte of status register) has 5 bits that are set by certain instructions:

+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | X | N | Z | V | C |
+---+---+---+---+---+---+---+---+

    C - Carry
    V - Overflow
    Z - Zero
    N - Negative
    X - Extend

The branching instructions depend on the CCR bits:

  --------------------------------------------------------------------------
  Branching Instructions
  
  Mnemonic   Branch on what?           Boolean formula
  --------------------------------------------------------------------------
  BCC        carry clear               !C
  BCS        carry set                 C
  BEQ        equal                     Z
  BGE        greater than or equal     (N and V) or (!N and !V)
  BGT        greater than              (N and V and !Z) or (!N and !V and !Z)
  BHI        higher than               !C and !Z
  BLE        less than or equal        Z or (N and !V) or (!N and V)
  BLS        lower than or same        C or Z
  BLT        less than                 (N and !V) or (!N and V)
  BMI        minus (i.e., negative)    N
  BNE        not equal                 !Z
  BPL        plus (i.e., positive)     !N
  BVC        overflow clear            !V
  BVS        overflow set              V
--------------------------------------------------------------------------

Unconditional Branching

The unconditional branch instructions

JMP, BRA

are functionally equivalent, but after assembly, JMP will use an absolute address, and BRA will use a relative one:

    jmp    label  ; set PC = #label
    bra.w  label  ; set PC += label (relative to current addr)
    bra.s  label  ; "

JMP could be to a word (first 64 KB) or long address, which is 10 or 12 CPU cycles, respectively. BRA is to a word or byte offset, and always takes 10 CPU cycles. In cases where your code resides in memory above address $FFFF, using BRA will always be 2 cycles faster, but sometimes will have to be converted to a JMP, if the target address is too far away.

JSR and BSR are like JMP and BRA, but store PC on the stack, to enable returning using RTS.

Loops

We can implement loops using DBcc instructions, instructions that optionally check a condition and decrement a loop counter.

Simple Loops

To perform action N times we use dbra/dbf:

      move.w  #N-1,d7
  loop
      ...                ; perform this N times
      dbra    d7,loop    ; dbra

If you prefer setting N-1, we can jump directly to the dbra:

      move.w  #N,d7
      jmp     loop_end
  loop_start
      ...                ; perform this N times
  loop_end
      dbra    d7,loop_start

C-style For Loops

If you want a C-style for loop:

        move.b  #0,d7    ; for(i=0; i<3; ++i):
  loop
        cmp.b   #3,d7
        bge     loop_end

        ...              ; do something, d7 = i

        add.b   #1,d7
        bra     loop
  loop_end

Modulus

If you want an unsigned integer that runs from 0..17 and then wraps to 0:

    move.w  #0,d0

    add.w   #1,d0     ; d0 = (d0+1) % 18
    cmp.w   #18,d0
    blt     .skip     ; BLT: lower than or same, unsigned!
    sub.w   #18,d0
.skip

Note: only works if we don't add more than 1 at a time to d0.

Changelog

References