68000 MACHINE LANGUAGE COURSE PART III by Mark van den Boer

In  part  I & II the basics of programming the  68000  have  been
introduced.  In the following parts of this course I will discuss
the  instructions of the 68000.  To understand this part and  the
coming  ones  I suggest you keep a printed copy of part  II  (the
addressing modes) in close range, so you can look things up.
Before discussing the individual instructions of the 68000 I will
divide its instructions into eight classes.
These classes are:
- Data movement operations.
- Integer  arithmetic  operations  (on  two's  complement  binary
numbers.
- Logical operations.
- Shift and rotate operations.
- Bit manipulation operations.
- Binary Coded Decimal (BCD) operations.
- Program control instructions.
- System control operations.

In  this  part  and  the following  parts  all  classes  will  be
discussed.  This approach is somewhat different of the one chosen
by  other authors (the alphabetic order).  For an explanation  of
the source and destination addressing modes I refer to the  table
at the end of part II.
To  specify  the  operands  of  the  instructions  the  following
conventions are used:

Rn   stands for either a data- or addressregister
An   stands for an address register
Dn   stands for a data register
<ea> stands  for an effective address operand.  This  means  that
after the operand after evaluation must yield an address.
#    stands for immediate data

All other symbols which appear in either field of the
instruction's assembler syntax will be explained.
One  suggestion  before  the  explanation  starts:   Since  68000
instructions  may operate on bytes,  words and longwords,  it  is
wise  to always specify which size you want to  manipulate.  This
way will considerably reduce the amount of very hard to find bugs
in your program.  Since assemblers take defaults when no size  is
specified you can get very odd results.  E.g.  BSET  (instruction
will  be explained later) operates only on bytes  and  longwords.
The assembler makes the default for you. Suppose you want a word-
operation  to  be  performed  and you  don't  specify  the  size,
thinking  that the default is nearly always word.  Well  in  this
case the default isn't word, so the assembler thinks your code is
alright, but it doesn't do what you want.

Data movement operations

Instruction:   EXG
Syntax:        EXG Rn,Rn
Data sizes:    Long
Condition codes affected: None
source:   Dn
An
destination:
Dn
An
Function:      Exchange the contents of two registers

Example:
Instruction              Before         After
EXG a0,d0                d0=11111111    d0=22222222
a0=22222222    a0=11111111

Instruction:   LEA
Syntax:        LEA <ea>,An
Data sizes:    Long
Condition code affected: None
Source:
(An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
Destination:
An
Example:
Instruction              Before         After
LEA (a1),a0              a0=00000000    a0=12345678
a1=12345678    a1=12345678
LEA 9(a0),a0             a0=00111111    a0=00111119
LEA 5(a0,d0.w)           a0=10000100    a0=10001111
d0=0000100b    d0=0000100b
LEA \$12345678,a0         a0=00000000    a0=12345678

Data sizes:    None
Condition codes affected: None
source:   An
destination:
#w

Function:      Create  temporary  space  on  stack.   The  source
(address register) is pushed onto the  stack,  the
stack-pointer  (a7) is copied into the source  and
the destination is added to the stack-pointer. The
destination-operand  is usually  negative  because
the  68000-stack grows downward  in  memory.  This
instruction  is  used  very  much  by   high-level
languages such as C and PASCAL.  This  instruction
has  the  advantage  that  local  variables  in  a
subroutine  can  be accessed through  the  source-
E.g.:  Every C-compiler on the Atari St uses  this
instruction at the beginning of every subroutine.
Example:
Instruction              Before         After
a7=44444448    a7=44444440
Let's analyse: First  a6 is pushed onto the  stack:  a7=44444444.
Then the stack-pointer is copied into a6. Then the

Instruction:   UNLK
Syntax:        UNLK source
Data sizes:    None
Condition codes affected: None
source:   An
Function:      The opposite of LINK. Also used by all C-compilers
at the end of functions.
Example:
Instruction              Before         After
UNLK a6                  a6=44444444    a6=12345678
a7=????????    a7=44444448
First a6 is copied into a7:  a7=44444444.  Then a6
is pulled from the stack,  which yields the  final
values of a6 and a7

Instruction:   MOVE
Syntax:        MOVE <ea>,<ea>
Data sizes:    Byte, Word, Long
Condition codes affected: N,Z (conditionally set/cleared),
V,C (always cleared)
source:   Dn
An
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
#x
destination:
Dn
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
Function:      Move   the   contents  of  the   source   to   the
destination.   This   instruction  is   the   most
frequently  used  68000-instruction  and  is  very
powerful.
modes are not allowed as destination-operand. This
seems illogical, but there's a good reason for it.
In the view of the designers at Motorola it is bad
practice to have self-modifying code in a program.
Example:
See part II of this course for examples on the MOVE-instruction.

Instruction:   MOVE to CCR
Syntax:        MOVE <ea>,CCR
Data sizes:    Byte
Condition  codes  affected:   All  as  a  direct  result  of  the
instruction.

source:   Dn
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
#x
Function: Set some condition codes. With this instruction you can
clear/set the N,Z,V,C and X flag.
Example: See part II

Instruction:   MOVE to SR
Syntax:        MOVE <ea>,SR
Data sizes:    Word
Condition  codes  affected:   All  as  a  direct  result  of  the
instruction. This instruction is priviliged .

source:   Dn
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
#x
Function: Set condition codes.
Example: See part II

Instruction:   MOVE from SR
Syntax:        MOVE SR,<ea>
Data sizes:    Word
Condition codes affected: None.
source:   SR

destination:
Dn
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
Function: Request   condition  codes.   This  function   is   not
priviliged on the 68000 and 68008, but is priviliged on
all other members of the 68000-family.
Example: See part II

Instruction:   MOVE to/from USP
Syntax:        MOVE USP,An   or   MOVE An,USP
Data sizes:    Long
Condition codes affected: None.

Function: This instruction is priviliged.  The instruction exists
because the 68000 has in fact two stack-pointers.  They
are both contained in a7.  This is possible because the
68000 has two modes of operation: user- and supervisor-
mode.  When in usermode it is impossible to access  the
supervisor  stackpointer.  It  is rather  logical  that
there are in fact two stackpointers.  If there had been
only  one  it would have been possible to mess  up  the
stack  in  such  a way that  the  system  would  crash.
However, the supervisor must have the ability to access
the user-stackpointer (for parameter-passing etc.).
Example:
Instruction              Before         After
MOVE USP,a6              USP=12345678   USP=12345678
a6=33333333    a6=12345678

Instruction:   MOVEA
Syntax:        MOVEA <ea>,An
Data sizes:    Word, Long
Condition codes affected: None

source:   Dn
An
(An)
(An)+
-(An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
#x
destination:
An

is word-sized then the address is  sign-extended.  Most
assemblers will accept MOVE <ea>,An as well. However, I
think it is better to write MOVEA instead of just MOVE.
When  you  intend  to  move a  value  into  an  address
register but you forget to specify an address  register
and  specify  something else,  the assembler  will  not
generate an error. E.g. you want to move \$12345678 into
a0.  MOVE.L #\$12345678,d0   will not generate an error,
while MOVEA.L #\$12345678,d0 will generate an error.
Example: See part II

Instruction:   MOVEM
Syntax:        MOVEM register list,<ea>      or
MOVEM <ea>,register list
register list is a set of registers.  Suppose  you
want  to  specify  all  data-register.  You  could
write:  d0-d7  or d0/d1/d2/d3/d4/d5/d6/d7  or  d0-
d3/d4/d5-d7. A number of registers in a row can be
denotated with a minus ('-') between them.  Single
registers  can  be specified with  a  slash  ('/')
between them.
Data sizes:    Word or Long
Condition codes affected: None
destination:
(An)
-(An)
w(An)
b(An,Rn)
w
l
source:   (An)
(An)+
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)

Example:
Instruction:             Before         After
MOVEM.W \$1000,d0/d3      \$1000=\$1234    d0=\$1234
\$1002=\$5678    d1=\$5678
MOVEM.L d0-d7/a0-a6,-(a7) will push all registers onto the stack.
MOVEM.L (a7)+,d0-d7/a0-a6 will pull all registers from the stack.

Instruction:   MOVEP
Syntax:        MOVEP Dn,w(An)   or   MOVEP w(An),Dn
Data sizes:    Word, Long
Condition codes affected: None
Function: Transfer data from or to a peripheral. This instruction
has been specially designed for communication with  all
devices  which have been originally designed for  8-bit
micro-processors.  This  way the 68000 can  communicate
with these devices.  E.g.  in the Atari are two  ACIA's
present.  ACIA's  are designed for 8-bit  computers.  I
won't  explain the operation of this  instruction  here
for it is rather seldom used,  especially by beginners.
If  you  want  to know all  about  this  instruction  I
suggest you contact the writer of this article.

Instruction:   MOVEQ
Syntax:        MOVEQ #,Dn
Data sizes:    Long
Condition codes affected: See move.
Function: This  instruction  provides an efficient way  (both  in
space  and  time) to set a data register to  a  value).
Values range from -128 to +127 decimal. Most assemblers
will generate MOVEQ-instructions where possible.
Example:
Instruction              Before         After
MOVEQ #\$34,d0            d0=ffffffff    d0=00000034

Instruction:   PEA
Syntax:        PEA <ea>
Data sizes:    Long
Condition codes affected: None

source:   (An)
w(An)
b(An,Rn)
w
l
w(PC)
b(PC,Rn)
Function: Push  an address onto the stack.  This  instruction  is
often used to write position independent code.  It  has
nearly the same function as MOVE.L <ea>,-(a7).
Example:
Instruction              Before         After
PEA (a6)                 a6=12345678    a6=12345678
a7=44444444    a7=44444448

Instruction:   SWAP
Syntax:        SWAP Dn
Data sizes:    None
Condition codes affected: V, C: always cleared
Z set if the result is 0
N set if bit 31 of the result is 1
Function: exchange upper and lower half of a data register.  This
instruction  is  often  used in  conjunction  with  the
divide operation (will be explained further)
Example:
Instruction              Before         After
SWAP d0                  d0=12345678    d0=56781234

Next  time I will discuss the integer arithmetic  operations.  By
the  way:  I'm beginning to believe that this course is the  best
there is,  since I don't get any comments!!! If you read this and
react you can earn yourself a surprise.

Disclaimer
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.