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 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 Addressing modes: 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 ,An Data sizes: Long Condition code affected: None Addressing modes: Source: (An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Destination: An Function: Load an address register with a value. LEA stands for Load Effective Address. 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 Instruction: LINK Syntax: LINK An,# Data sizes: None Condition codes affected: None Addressing modes: 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- address register. E.g.: Every C-compiler on the Atari St uses this instruction at the beginning of every subroutine. Example: Instruction Before After LINK a6,#-4 a6=12345678 a6=44444444 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 destination-operand is added to a7. Instruction: UNLK Syntax: UNLK source Data sizes: None Condition codes affected: None Addressing modes: source: An Function: The opposite of LINK. Also used by all C-compilers at the end of functions. Example: For values see LINK 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 , Data sizes: Byte, Word, Long Condition codes affected: N,Z (conditionally set/cleared), V,C (always cleared) Addressing modes: 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. Note that the PC-relative addressing 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 ,CCR Data sizes: Byte Condition codes affected: All as a direct result of the instruction. Addressing modes: 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 ,SR Data sizes: Word Condition codes affected: All as a direct result of the instruction. This instruction is priviliged . Addressing modes: 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, Data sizes: Word Condition codes affected: None. Addressing modes: 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. Addressing modes: see Syntax 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 ,An Data sizes: Word, Long Condition codes affected: None Addressing modes: source: Dn An (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) #x destination: An Function: Load an address register with a value. If the operation is word-sized then the address is sign-extended. Most assemblers will accept MOVE ,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, or MOVEM ,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 Addressing modes: 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 Data sizes: Long Condition codes affected: None Addressing modes: 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 ,-(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. Originally published in ST NEWS Volume 2 Issue 2.