This is the machine code course,parts 1-10,where you probably will learn something about the tricky language. It is written by Mark van de Boer and we thank him very much for making this "small" course. I hope you will learn something,guys! Put together by Sorcerer of The Digital Dictators! 68000 MACHINE LANGUAGE COURSE PART I by Mark van de Boer As the title already says this is the first part of an 68000 assembly language programming course. This course is intended for people who already have a little experience with programming in assembly language on microprocessors like the 6502 (6510 is in fact the same) and the 68xx (like 6800, 6801, 6805, 6809) series. In this course these two microprocessor-families will be referenced by their most famous members, the 6502 and the 6809. At this time it is not exactly known how many articles this course will have. I think it will be about six articles long. Now I will describe some features of the 68000. The 68000 is a sixteen-bit microprocessor. This means that an opcode is always sixteen bits (On the 6502 and 6809 an opcode is 8 bits, therefore they are called 8-bit microprocessors). The databus of the 68000 is 16 bits wide, this means that 16 bits can be transferred at once by the 68000 (The 6502 and 6809 both have a databus that is eight bits wide, so they can transfer 8 bits at once). Another important feature of the 68000 is its impressive set of registers. First there are the eight data registers, numbered D0- D7. They are 32 bits wide and can be used for operations on 8-bit, 16-bit and 32-bit quantities. Data registers can be compared with the A-register (Accumulator) on the 6502 and 6809, their function same, but the use of the data registers is much more convenient. Second, there are the eight address registers, numbered from A0-A7. They are 32 bits wide as well and their only use is in addressing memory. However, the upper 8 bits are ignored by the 68000 since its address bus is 'only' 24 bits wide, meaning that the 68000 can address up to 16 megabytes of memory. Register A7 has a special function; it is called the system stackpointer. This means that if you execute a JSR instruction, some data will be saved on the address contained in this register. By the way, you can use every address register very easily as a stackpointer. The third class consists of one register, the PC (program counter). This register always contains the address of the instruction to be executed next. Of course, the upper eight bits of the PC are also ignored. The fourth class consists of one 16 bit register, the status register, called SR. This register is built up like this: ------------------------------------------------------------- | T | | S | | I0| I1| I2| | | | X | N | Z | V | C | ------------------------------------------------------------- system-byte | user-byte The upper 8 bits are called the system byte. This byte contains information that is important to the system. Normally you can not change this byte if you run an application. Bit 15 is called the trace-bit. If this bit is set, every time after executing an instruction the 68000 will generate an exception (This is called an interrupt on the 6502 and 6809). This is especially useful when debugging programs. Bit 13 is called the supervisor bit. When this bit is set the 68000 is in supervisor mode; when this bit is cleared, however, the 68000 is in user mode. When executing in supervisor mode, the 68000 can execute the so called privileged instructions, which are not available in user mode. For example, it is illegal trying to change the upper 8 bits of the SR when in user mode. Bits 8, 9 and 10 are called the interrupt mask. In total they can contain eight different values ranging from zero to seven. For instance, if bits 8 and 10 are set and bit 9 is cleared, the value of the interrupt mask is 5. This means that only interrupts with a level of 5 and higher are recognized by the 68000 and interrupts with a level lower than 5 are ignored. Interrupts of level 7 can be considered as non maskable interrupts (compare this to the NMI on the 6502 and 6809). The lower 8 bits are called the conditioncode register, CCR (this can be compared to the CC of the 6502 and 6809). The CCR contains 5 bits, which contain useful data. Bit 0 is the carry-flag (C), bit 1 is the overflow-flag (V), bit 2 is the zero-flag (Z), bit 3 is the negative-flag (N). The meanings of these bits are exactly the same as on the 6502 and 6809. Then there is bit 4 which is called the extend-flag (X). It is nearly exactly the same as the carry- flag, but is not affected by every instruction that affects the carry-flag. This feature of the extend-flag is especially useful when using multiple precision arithmetic, e.g. adding 64-bit numbers. Another feature of the 68000 is its ability to access three data formats: byte (8 bits), word (16 bits) and longword (32 bits). You can indicate this with a suffix in the mnemonic field. The suffixes are .b for byte, .w for word and .l for longword. E.g. asr.b d0 , asr.w d0 , asr.l d0. These instructions shift data register d0 one place to the right. I think this is enough new stuff for today. Next time I will explain the addressing modes of the 68000. If you have any comments or questions on this article, please write to the correspondence address and I'll take your notes into account. A good Motorola MC 68000 book is: The Motorola 68000 programming guide, which unfortunately is not available in the stores. Further there are a number of books on the 68000. I would like to mention the book written by Lance Leventhal & Gerry Kane, which I think gives good value for its money. Another good book is Steve Williams' "Programming the 68000". 68000 ASSEMBLY LANGUAGE COURSE PART II by Mark van den Boer Welcome to part II of this course. In part I, some fundamentals of the 68000 were shown. In this part, I will show you which addressing modes the 68000 uses. First an example of addressing modes which the 6502 and 6809 use: lda #10 * immediate addressing lda $10 * zero-page (6502) or direct-page addressing (6809) inx * inherent (6502) inca * inherent (6809) Now, what does a line of code in 68000 assembler look like? LABEL OPCODE OPER1,OPER2 COMMENT The meanings of these fields are: label: A name given to this line of code. Some assemblers require a : to follow the label-name. This field is optional. opcode: This field specifies the operation you wish to perform. It is the only field that isn't optional. Depending on the opcode the 68000 expects 0, 1 or 2 operands. oper1: The first operand to appear with the opcode. The appearance of this field depends on the specified opcode. oper2: The second operand to appear with the opcode. The appearance of this field depends (surprise, surprise) on the specified opcode. comment: Another optional field which is used for commenting all tricks people put in their programs. Most assemblers require a * as the first character of the comment field. The comment field is optional. Now what does an addressing mode do? An addressing mode specifies on which data the opcode (instruction) must operate. The 68000 has a total of 14 addressing modes, all of which now will explained. As examples in all addressing modes I will use the MOVE instruction. MOVE can have the .b, .w and .l suffixes as mentioned in part I of the course. The MOVE instruction moves the data specified by oper1 to the place specified by oper2. Example: MOVE.B $1,$2 performs exactly the same operation as the following 6502 and 6809 code: LDA $1 STA $2. The addressing modes: 1. Inherent addressing In this addressing mode there are no operands since they are already supplied by the opcode. E.g.: RESET * reset all peripherals RESET is an 68000 instruction which is used to reset all the peripherals. 2. DATA REGISTER DIRECT ADDRESSING Assembler syntax: Dn (n can range from 0 to 7) In this addressing mode a data register contains the operand. E.g.: Instruction Before After MOVE.B D1,D0 d0=ffffffff d0=ffffff67 d1=01234567 d1=01234567 MOVE.W D1,D0 d0=ffffffff d0=ffff4567 d1=01234567 d1=01234567 MOVE.L D1,D0 d0=ffffffff d0=01234567 d1=01234567 d1=01234567 As you might have noticed, an instruction with .b as a suffix only changes the lowest 8 bits of the destination, and instructions with .w as a suffix only change the lowest 16 bits of the destination. Instructions with .l as a suffix change all 32 bits of the destination. 3. ADDRESS REGISTER DIRECT ADDRESSING Assembler syntax: An (n can range from 0 to 7) In this addressing mode an address register contains the operand. Byte operators (those with .b suffix) are not allowed in this addressing mode. When using the address register as a destination and it is a word operation (suffix is .w), the word is sign- extended into a longword. This means that during a wordtransfer into a data register the upper 16 bits are filled with the value of the most-significant bit (this is bit 15) of the word. An example below will show you how it's done. E.g.: Instruction Before After MOVE.W A1,D0 d0=ffffffff d0=ffff4567 a1=01234567 a1=01234567 MOVE.W D0,A1 d0=01234567 d0=01234567 a1=ffffffff a1=00004567 <- extend!! MOVE.W D0,A1 d0=0000ffff d0=0000ffff a1=00000000 a1=ffffffff <- extend!! MOVE.L A1,D0 d0=ffffffff d0=01234567 a1=01234567 a1=01234567 4. ADDRESS REGISTER INDIRECT ADDRESSING Assembler syntax: (An) (n between 0 and 7) In this addressing mode, the address register contains the address of the operand. In assembler this is being denotated by putting parentheses around an address registers name, e.g. (a0). The contents of a0 points to the address where the data has to be fetched from. When using word (.w) or longword (.l) addressing it is absolutely necessary that the address register contains an even number (I will explain the reason for this in a forthcoming article). E.g.: Instruction Before After MOVE.L (A1),D0 d0=ffffffff d0=01234567 a1=00001000 a1=00001000 address $1000 contains 01234567 MOVE.L D0,(A1) d0=76543210 d0=76543210 a1=00001000 a1=00001000 address $1000 now contains 76543210 5. ADDRESS REGISTER INDIRECT ADDRESSING WITH POST-INCREMENT Assembler syntax: (An)+ (n between 0 and 7) This addressing mode resembles the address register indirect addressing mode. The only difference is that after having fetched or stored the data, the address register is incremented. The increment depends on the suffix used in the opcode. If the suffix is .b then the address register will be incremented by one. If the suffix is .w then the address register will be incremented by two (one word is two bytes). If the suffix is .l then the address register will be incremented by four (one longword is four bytes). In assembler this addressing mode is denotated by putting the address register within parentheses followed by a + sign. For example: (a7)+ E.g.: Instruction Before After MOVE.L (A1)+,D0 d0=ffffffff d0=01234567 a1=00001000 a1=00001004 address $1000 contains 01234567 MOVE.W (A1)+,D0 d0=ffffffff d0=ffff0123 a1=00001000 a1=00001002 address $1000 contains 01234567 MOVE.B (A1)+,D0 d0=ffffffff d0=ffffff01 a1=00001000 a1=00001001 address $1000 contains 01234567 MOVE.L D0,(A1)+ d0=76543210 d0=76543210 a1=00001000 a1=00001004 address $1000 now contains 76543210 6. ADDRESS REGISTER INDIRECT ADDRESSING WITH PRE-DECREMENT Assembler syntax: -(An) (n between 0 and 7) This addressing mode resembles the address register indirect addressing mode. The only difference is that after before fetching or storing the data, the address register is decre- mented. The decrement depends on the suffix used in the opcode. If the suffix is .b then the address register will be decremented by one. If the suffix is .w then the address register will be decremented by two (one word is two bytes). If the suffix is .l then the address register will be decremented by four (one longword is four bytes). In assembler this addressing mode is denotated by putting the address register within parentheses preceded by a - sign. For example: -(a7) E.g.: Instruction Before After MOVE.L -(A1),D0 d0=ffffffff d0=01234567 a1=00001004 a1=00001000 address $1000 contains 01234567 MOVE.W -(A1),D0 d0=ffffffff d0=ffff4567 a1=00001004 a1=00001002 address $1000 contains 01234567 MOVE.B -(A1),D0 d0=ffffffff d0=ffffff67 a1=00001004 a1=00001003 address $1000 contains 01234567 MOVE.L D0,-(A1) d0=76543210 d0=76543210 a1=00001004 a1=00001000 address $1000 now contains 76543210 7. ADDRESS REGISTER INDIRECT ADDRESSING WITH DISPLACEMENT Assembler syntax: w(An) (w stands for word displacement) This addressing is also rather similar to address register indirect addressing. The only difference lies in the fact that before fetching or moving the data a 16-bit signed displacement is added to the contents of the address register (the address register itself does not change). In assembler this addressing mode is denotated by enclosing the address register name in parentheses preceded by a 16-bit constant. For example: 8(a6) denotes the memory location whose address is the contents of a6 plus 8. This addressing method comes in very handy when passing parameters to subroutines. By the way, did you ever wonder why the ATARI ST has a resolution of 640 by 400 pixels? Here's one reason: 640*400=256000 bits=32000 bytes. Since 32000 bytes can be addressed using 16 bits, the address register indirect with displacement is an easy way to address the screen. E.g.: Instruction Before After MOVE.L 8(A1),D0 d0=ffffffff d0=01234567 a1=00001000 a1=00001000 address $1008 contains 01234567 MOVE.L D0,-6(A1) d0=76543210 d0=76543210 a1=00001006 a1=00001006 address $1000 now contains 76543210 8. ADDRESS REGISTER INDIRECT ADDRESSING WITH INDEX Assembler syntax: b(An,Rn.w) or b(An,Rn.l) ( b stands for byte, w and l for word and longword and R for register). This addressing mode makes it possible to add a variable index (contained in an address or data register) to an address register and also an eight bit signed displacement. The variable index may be either word or longword. Both the index and displacement are sign extended before they are added to the address register. E.g.: Instruction Before After MOVE.L 8(A1,A0.L),D0 d0=ffffffff d0=01234567 a1=00001000 a1=00001000 a0=00078000 a0=00078000 address $79008 contains 01234567 MOVE.L 8(A1,A0.W),D0 d0=ffffffff d0=01234567 a1=00001000 a1=00001000 a0=00078000 a0=00078000 *** a0.w=8000 -> sign-extend gives ffff8000 *** address $ffff8008 contains 01234567 MOVE.W 8(A1,D0.L),D0 d0=0001fffe d0=00010123 a1=00001000 a1=00001000 *** 00001000 (contents of a1) 0001fffe (contents of d0.l) 00000008 (sign-extended byte displacement) --------- 00021006 address $21006 contains 01234567 MOVE.L 8(A1,D0.W),D0 d0=0001fffe d0=01234567 a1=00001000 a1=00001000 *** 00001000 (contents of a1) fffffffe (sign-extended contents of d0.w) 00000008 (sign-extended byte displacement) --------- 00001006 address $1006 contains 01234567 9. ABSOLUTE SHORT ADDRESSING Assembler syntax: x (x is a 16 bit constant) With absolute short addressing it is only possible to specify a 16 bit constant. At execution time the 68000 sign extends the word into a long address, meaning that only addresses 0 to 7fff and ffff8000 to ffffffff can be addressed using this form. This addressing mode can be compared with zero-page addressing on the 6502 and direct-page addressing on the 6809.Like on the 6502 and 6809 this mode is faster than any other mode. This addressing mode can be compared with zero-page addressing on the 6502 and direct-page addressing on the 6809. By the way, on the Atari ST, the lower 32 K of memory can only be accessed in supervisor-mode (the S-bit in SR is set, see part I). E.g.: Instruction Before After MOVE.L $1234,D0 d0=ffffffff d0=01234567 address 1234 contains 01234567 ( the $ sign is used to denote a hex digit) MOVE.L $8000,D0 d0=ffffffff d0=76543210 address $ffff8000 contains 76543210 10. ABSOLUTE LONG ADDRESSING Assembler syntax: l (l is 32 bit constant) With this addressing mode a long address is supplied. It is very similar to absolute short addressing. E.g.: Instruction Before After MOVE.L $12345678,D0 d0=ffffffff d0=01234567 address $00345678 contains 01234567 Note that since the address bus is only 24 bits wide the upper byte of the address is ignored by the 68000. 11. PROGRAM COUNTER WITH DISPLACEMENT Assembler syntax: x(PC) (x is a 16 bit constant) This addressing mode is in fact the same as address register indirect with displacement. The only difference is that the address register is replaced with the PC (the PC is in fact also an address register). E.g.: Instruction Before After MOVE.L 8(PC),D0 d0=ffffffff d0=01234567 pc=00001000 pc=00001000 address $1008 contains 01234567 12. PROGRAM COUNTER WITH INDEX Assembler syntax: b(PC,Rn.L) or b(PC,Rn.w) (b is 8 bits) This mode is in fact the same address register indirect addressing with index. E.g.: Instruction Before After MOVE.L 8(PC,A0.L),D0 d0=ffffffff d0=01234567 pc=00001000 pc=00001000 a0=00078000 a0=00078000 address $79008 contains 01234567 MOVE.L 8(PC,A0.W),D0 d0=ffffffff d0=01234567 pc=00001000 pc=00001000 a0=00078000 a0=00078000 *** a0.w=8000 -> sign-extend gives ffff8000 *** address $ffff8008 contains 01234567 MOVE.W 8(PC,D0.L),D0 d0=0001fffe d0=00010123 pc=00001000 pc=00001000 *** 00001000 (contents of pc) 0001fffe (contents of d0.l) 00000008 (sign-extended byte displacement) --------- 00021006 address $21006 contains 01234567 MOVE.L 8(PC,D0.W),D0 d0=0001fffe d0=01234567 pc=00001000 pc=00001000 *** 00001000 (contents of pc) fffffffe (sign-extended contents of d0.w) 00000008 (sign-extended byte displacement) --------- 00001006 address $1006 contains 01234567 13. IMMEDIATE ADDRESSING Assembler syntax: #x (x is byte, word or longword) The data for the operation is the value x. Programmers of the 6502 and 6809 will recognize this addressing mode. For example (6502 and 6809) LDA #$21. E.g.: Instruction Before After MOVE.L #$A03B4C11,D0 d0=00000000 d0=a03b4c11 14. STATUS REGISTER ADDRESSING Assembler syntax: SR or CCR This mode is used to control the contents of this register. See part I of this course for the individual meanings of the bits contained in this register. Changes to the SR can only be made when in user-mode. Changes to the CCR can be made in any mode. E.g.: Instruction Before After MOVE.W SR,D0 d0=87654321 d0=87652700 sr=2700 sr=2700 MOVE.W #$0500,SR sr=2700 sr=0500 Notice that the 68000 was in supervisor mode before executing the instruction but after completion it is in user mode!! This operation isn't possible the other way around. To conclude this part, I will give you a summary of the addressing modes of the 68000. SYNTAX NAME ----------------------------------- Dn | Data register direct An | Address register direct (An) | Address register indirect (An)+ | Address register indirect with post-increment -(An) | Address register indirect with pre-decrement w(An) | Address register with displacement b(An,Rn) | Address register with index w | Absolute short l | Absolute long w(PC) | PC with displacement b(PC,Rn) | PC with index #x | Immediate SR or CCR | Status register b is a byte constant w is a word constant l is a long constant x any of b, l or w n is a register number ranging from 0 to 7 R is a register specifier, either A or D If you have any comments on these courses, please let me know! 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. MC 68000 MACHINE LANGUAGE COURSE PART IV by Mark van den Boer What a pity!! You missed the mega-surprise of part 3. Next time better luck! I am gonna take that holiday to Hawaii myself! This time I will discuss the Integer Arithmetic Instructions. The syntax used is of course the same as in part 3, so when in doubt refer to part 3. This class of instructions is used to do mathematical calculations. This group is very often used by assembly language programmers, especially the instructions for adding and subtracting. Integer Arithmetic Instructions Instruction: ADD Syntax: ADD Dn, ADD ,Dn Data sizes: byte, word, long Condition codes affected: X, C set by carry out of the most significant bit N set if the result was negative, cleared otherwise Z set if the result was zero, cleared otherwise V set if the result overflowed, cleared otherwise Addressing modes: Source: (destination is Dn) Dn An (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Add source to destination and put the result in destination. Examples: Instruction Before After ADD.W d0,d1 d0=00000011 d0=00000011 d1=0000FFFA d1=0000000B XNZVC=00000 XNZVC=11001 ADD.L (a0),d0 d0=00000022 d0=00000027 a0=12345678 a0=12345678 12345678 contains 5 XNZVC=00000 XNZVC=00000 Instruction: ADDA Syntax: ADDA ,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) # Destination: An Function: Add a value to an address register. This operation does not change any of the condition code values. Note that most operations that have an address register as a destination does not change the condition codes. Example: Instruction Before After ADDA.L a0,a0 a0=00000002 a0=00000004 Notice that this instruction has the same effect as multiplying the address register with two (if this was possible). Instruction: ADDI Syntax: ADDI #, This instruction has exactly the same characteristics as the ADD instruction, except that the source can only be a constant. Instruction: ADDQ Syntax: ADDQ #, Same story as for ADDI, except that the immediate values in the source field can only range from 1 to 8. Q stands for Quick, since this instruction is the fastest way to add a number from 1 to 8 to a destination operand. A note on ADD, ADDI, ADDQ: Most assemblers accept the following instruction: ADD #1,Dn and will translate it automatically to ADDQ #1,Dn thus saving a few bytes of object code and some clock cycles execution time. Instruction: ADDX Syntax: ADDX Dn,Dn ADDX -(An),-(An) Data sizes: byte, word, long Condition codes affected: see ADD Function: Add X-bit and source to destination and store the result in destination. This instruction is used for multiple precision operations and is therefore only available with the two addressing modes mentioned. Example: Instruction Before After ADDX.B -(a0),-(a1) a0=10001001 a0=10001000 a1=10002001 a1=10002000 10001000 contains AA the same 10002000 contains 5A 10002000 contains 4 X=0 X=1 ADDX.B -(a0),-(a1) a0=10001000 a0=10000fff a1=10002000 a1-10001fff 10000fff contains 0 the same 10001fff contains 0 10001fff contains 1 X=1 X=0 In this example the word that begins at 10000fff is added to the word that begins at 10001fff. If one should try to do this with two ADD.W instruction an address error would occur since words always must be aligned to even addresses. This instruction can be compared to the ADC instruction of the 6502 and 6809. Instruction: CLR Syntax: CLR Data sizes: byte, word, long Condition codes affected: N always cleared Z always set V always cleared C always cleared Addressing modes: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Set an effective address to zero. You will have noticed that you can't CLR an address register. However, most assemblers allow the programmer to CLR an address register by substituting CLR a0 with SUB.L a0,a0 . This instruction has exactly the same result. Example: Instruction Before After CLR.W d0 d0=ffffffff d0=00000000 NZVC=1011 NZVC=0100 Instruction: CMP Syntax: CMP ,Dn Data sizes: byte, word, long Condition codes affected: NZVC (X is not affected) Addressing modes (source): Dn An (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Function: compare an effective address with a data register. In fact all condition codes are set as if Dn- was performed. So CMP is kind of a subtraction which only affects the conditon codes. Example: Instruction Before After CMP.L d0,d1 d0=00000001 d0=00000001 d1=00000002 d1=00000002 NZVC=1111 NZVC=0000 Instruction: CMPA Syntax: CMPA ,An Data sizes: word, long Function: This instruction differs only from CMP in that the second operand is an address register and that byte isn't allowed as a data size. Instruction: CMPI Syntax: CMPI #,Dn Function: Yes, it is nearly exactly the same as compare but now the first operand must be a constant. Instruction: CMPM Syntax: CMPM (An)+,(An)+ Function: Again, nearly exactly the same as CMP, but now both the source and destination operand must be (An)+. This instruction is used to compare areas of memory. For those of you who have a working knowledge of C: strcmp can be programmed easy with this instruction. Note on all CMPx instructions. Most assemblers accept instructions like: CMP.W (a0)+,(a1)+ CMP.L #3,d0 Substitution of CMPM, CMPI and CMPA are automatically performed by the assembler. Instruction: DIVS Syntax: DIVS ,Dn Data sizes: word Condition codes affected: N behaves normal; undefined on overflow Z behaves normal; undefined on overflow V behaves normal C always cleared Addressing modes (source): Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # Function: Guess what? This instruction performs a division between two signed numbers. The destination register is always a longword and the source operand is always a word. After the division the destination operand contains the result. The quotient is always in the lower word and the remainder is always in the high order word of the data register! This way a modulo operation is also performed, you just SWAP the data register and you have your result in the lower word of the data register. Overflow occurs when you attempt to divide a large number by a small number e.g. ffffff divided by 1, the result doesn't fit in a word. Another error occurs when attempting to divide by zero. In this case the 68000 generates an exception and will trap to a special routine which handles division by zero erros. On the Atari you must set up this routine yourself. E.g. FLOYD (a machine language monitor) responds to a division by zero with the following sentence "The answer is 42". Remember, don't panic when you see such an answer. Example: Instruction Before After DIVS #3,d0 d0=0000000B d0=00020003 NZVC=1111 NZVC=0000 Instruction: DIVU Function: Nearly exactly the same as DIVS, only this time both operands are assumed to be unsigned. Instruction: EXT Syntax: EXT Dn Data sizes: word, long Condition codes affected: N behaves normal Z behaves normal V always cleared C always cleared Function: turn a byte into a word, or turn a word into a long. This instruction provides a convenient way to turn a word into a long and still have the same value for that register. If the high order bit of the data register is 0, so the data register is positive, zeroes are padded in, otherwise ones are padded in. Example: Instruction Before After EXT.W d0 d0=000000ff d0=0000ffff EXT.L d0 d0=ffff0000 d0=00000000 Instruction: MULS Syntax: MULS ,Dn Data sizes: word Condition codes affected: N behaves normal Z behaves normal V always cleared C always cleared Addressing modes (source): Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # Function: Ah! another very handy instruction. This instruction performs a multiplication of the source and destination operand, putting the result in the destination operand. Example: Instruction Before After MULS #3,d0 d0=0000000B d0=00000021 NZVC=1111 NZVC=0000 Instruction: MULU Function: Nearly exactly the same as MULUS, only this time both operands are assumed to be unsigned. Instruction: NEG Syntax: NEG Data sizes: byte, word, long Condition codes affected: XNZVC (all behave normal) Addressing modes: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: negate an effective address operand. In a high level language it would look like this: a = -a Example: Instruction Before After NEG.L d0 d0=00000001 d0=ffffffff Instruction: NEGX Syntax: NEGX Data sizes: byte, word, long Condition codes affected: XNZVC (all behave normal) Addressing modes: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: negate an effective address operand and add the X-bit to the result. This is another instruction which provides a way to handle multi-precision (e.g. 8-byte integers). Example: Instruction Before After NEGX.L d0 d0=00000001 d0=00000000 X=1 X=1 Instructions: SUB, SUBA, SUBI, SUBQ, SUBX All these instruction perform subtractions. They only differ in that way from from the ADD instructions, all other characteristics are the same. Instruction: TAS Syntax: TAS Data sizes: byte Condition codes affected: N evaluated before setting the byte Z evaluated before setting the byte V always cleared C always cleared Addressing modes: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: First test the operand and set the condition codes, then set the high-order bit to 1. People who know what semaphores (in programming of course...) are, immedia- tely will love this instruction. For those who don't know what semaphores are: M. Ben Ari has written a good book on the subject called "Principles of Concurrent Programming". Never, I repeat never, read a book on this subject written by a certain Ir. E.H.H. Dijkstra (not the famous Dijkstra, this Dijkstra will never be famous). Example: Instruction Before After TAS $436 $436=00 $436=80 NZVC=1111 NZVC=0100 TAS $436 $436=FF $436=FF NZVC=1111 NZVC=1000 Instruction: TST Syntax: TST Data sizes: byte, word, long Condition codes affected: N behaves normal Z behaves normal V always cleared C always cleared Addressing modes: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: test an effective address operand. This instruction can be seen as CMP ,d0 where d0 is 0. TST is nearly always followed by a branch instruction (more on these later) MACHINE LANGUAGE COURSE PART V by Mark van den Boer Logical Operations Instruction: AND Syntax: AND ,Dn AND Dn, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Source: (destination is Dn) Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Destination: (source is Dn) (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a boolean bitwise AND from source to destination. Examples: Instruction Before After AND.B d0,d1 d0=33333333 d0=33333333 d1=ffffffff d1=ffffffcc AND.W d0,d1 d0=33333333 d0=33333333 d1=ffffffff d1=ffffcccc AND.L d0,d1 d0=33333333 d0=33333333 d1=ffffffff d1=cccccccc Instruction: ANDI Syntax: ANDI #, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l CCR, SR Function: Perform a boolean bitwise AND from source to destination. Examples: Instruction Before After ANDI.B #7,d0 d0=33333333 d0=33333330 ANDI.W #$ff00,SR SR=ffff SR=ff00 Instruction: EOR Syntax: EOR Dn, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise exclusive or from source to destina- tion. You will notice that this instruction can only take a data register as the source, unlike the AND and OR instructions. I think the designers of the 68000 should have mode addressing modes more orthogonal. Examples: Instruction Before After EOR.L d0,d1 d0=ffffffff d0=ffffffff d1=f0f0f0f0 d1=0f0f0f0f Instruction: EORI Syntax: EORI #, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l CCR, SR Function: Perform a bitwise exclusive or from source to destination. Examples: Instruction Before After EORI.B #$ff,d0 d0=33333330 d0=333333cf EORI.W #$00ff,SR SR=ff32 SR=ffcd Instruction: NOT Syntax: NOT Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise not to the effective address operand. Note that NOT.W d0 is the same as EORI.W #$ffff,d0. Examples: Instruction Before After NOT.B #$ff,d0 d0=ffffff78 d0=ffffff87 Instruction: OR Syntax: OR ,Dn OR Dn, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Source: (destination is Dn) Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Destination: (source is Dn) (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a boolean bitwise OR from source to destination. Examples: Instruction Before After OR.B d0,d1 d0=ffffffff d0=ffffffff d1=33333333 d1=333333ff OR.W d0,d1 d0=ffffffff d0=ffffffff d1=33333333 d1=3333ffff OR.L d0,d1 d0=ffffffff d0=ffffffff d1=33333333 d1=ffffffff Instruction: ORI Syntax: ORI #, Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V,C always cleared Addressing modes: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l CCR, SR Function: Perform a boolean bitwise OR from source to destina- tion. Examples: Instruction Before After ORI.B #7,d0 d0=33333330 d0=33333333 ORI.W #$00ff,SR SR=ff00 SR=ffff ASSEMBLY LANGUAGE COURSE PART VI by Mark van den Boer Shift and Rotate Operations Instruction: ASL Syntax: ASL #,Dn (the immediate operand always modulo 8) ASL Dn,Dn (the first operand always modulo 8) ASL Data sizes: byte, word, long except for ASL which only allows word and long as data sizes. Condition codes affected: X set to the last bit shifted out N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V set if the most significant bit is changed during the operation C see the X-bit Addressing modes allowed with the ASL instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a shift left of the destination operand. This instruction can be used as a fast form of multiplying an operand with a power of two. On a processor like the 6502 this instruction is the only way to perform a multiply operation. The lower bit of the destination is always set to zero. Examples: Instruction Before After ASL.L d0,d1 d0=33333333 d0=33333333 d1=00000005 d1=00000028 ASL.W $4ee $4ee=0009 $4ee=0012 Instruction: ASR Syntax: ASR #,Dn (the immediate operand always modulo 8) ASR Dn,Dn (the first operand always modulo 8) ASR Data sizes: byte, word, long except for ASR which only allows word and long as data sizes. Condition codes affected: X set to the last bit shifted out N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V set if the most significant bit is changed during the operation C see the X-bit Addressing modes allowed with the ASR instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a shift right of the destination operand. This instruction can be used as a fast form of dividing an operand with a power of two. On a processor like the 6502 this instruction is the only way to perform a divide operation. The upper bit (sign bit) is always repeated. Examples: Instruction Before After ASR.L d0,d1 d0=33333333 d0=33333333 d1=00000005 d1=00000002 ASR.W $4ee $4ee=8009 $4ee=c004 Instruction: LSL See the ASL instruction. The LSL instruction is exactly the same. At the moment I haven't got the machine codes for the ASL and LSL operations but I think that even the machine codes are the same. E.g. on the 6809 both ASL and LSL exist but translate to the same machine code. Instruction: LSR Syntax: LSR #,Dn (the immediate operand always modulo 8) LSR Dn,Dn (the first operand always modulo 8) LSR Data sizes: byte, word, long except for LSR which only allows word and long as data sizes. Condition codes affected: X set to the last bit shifted out N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V set if the most significant bit is changed during the operation C see the X-bit Addressing modes allowed with the LSR instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a shift right of the destination operand. This instruction differs from ASR in that the high order bit is always cleared. Examples: Instruction Before After LSR.L d0,d1 d0=33333333 d0=33333333 d1=00000005 d1=00000002 LSR.W $4ee $4ee=0009 $4ee=0004 Instruction: ROL Syntax: ROL #,Dn (the immediate operand always modulo 8) ROL Dn,Dn (the first operand always modulo 8) ROL Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V always cleared C set to the last bit shifted out the operand Addressing modes allowed with the ROL instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise rotate left of the destination operand. Examples: Instruction Before After ROL.L d0,d1 d0=00000001 d0=00000001 d1=88000001 d1=10000002 (C bit set) ROL.W $4ee $4ee=8009 $4ee=0012 Instruction: ROR Syntax: ROR #,Dn (the immediate operand always modulo 8) ROR Dn,Dn (the first operand always modulo 8) ROR Data sizes: byte, word, long Condition codes affected: X not affected N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V always cleared C set to the last bit shifted out the operand Addressing modes allowed with the ROR instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise rotate right of the destination operand. Examples: Instruction Before After ROR.L d0,d1 d0=00000001 d0=00000001 d1=88000001 d1=c4000000 (C bit set) ROR.W $4ee $4ee=8009 $4ee=c004 Instruction: ROXL Syntax: ROXL #,Dn (the immediate operand always modulo 8) ROXL Dn,Dn (the first operand always modulo 8) ROXL Data sizes: byte, word, long Condition codes affected: X set to the last bit shifted out the operand N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V always cleared C set to the last bit shifted out the operand Addressing modes allowed with the ROXL instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise rotate left of the destination operand. There is very little difference with the ROL instruction. By the way, it is very handy to have a wordprocessor with cut/paste and find/replace facilities. All I did was cut out the complete ROL instruction and replaced all ROL's by ROXL's. Examples: Instruction Before After ROXL.L d0,d1 d0=00000001 d0=00000001 d1=88000001 d1=10000002 ROXL.W $4ee $4ee=8009 $4ee=0012 Instruction: ROXR Syntax: ROXR #,Dn (the immediate operand always modulo 8) ROXR Dn,Dn (the first operand always modulo 8) ROXR Data sizes: byte, word, long Condition codes affected: X set to the last bit shifted out the operand N set to the most significant bit of the result Z set if the result is zero, cleared otherwise V always cleared C set to the last bit shifted out the operand Addressing modes allowed with the ROXR instruction: Destination: (An) (An)+ -(An) w(An) b(An,Rn) w l Function: Perform a bitwise rotate right of the destination operand. There is very little difference with the ROR instruction. By the way, it is very handy to have a wordprocessor with cut/paste and find/replace facilities. All I did was cut out the complete ROXL instruction and replaced all ROXL's by ROXR's. Examples: Instruction Before After ROXR.L d0,d1 d0=00000001 d0=00000001 d1=88000001 d1=10000002 ROXR.W $4ee $4ee=8009 $4ee=0012 MC 68000 MACHINE LANGUAGE COURSE PART VII by Mark van den Boer I would like to dedicate this part to Willeke, who gives Richard sleepless nights and the inspiration to write even more exciting issues of ST NEWS. I only saw Willeke on photograph, but she must be a fine girl. In my opinion there are three qualities which a girl must have, to qualify as a fine girl. These are: 1) like Queensr˜che, 2) like ST NEWS (no, she doesn't have to like this particular machine language course). Now, you're all anxious to know the third quality, aren't you? If you think you know the third one, send your answer to ST NEWS. A bottle of wine will be raffled among the persons who gave the right answer. There will be another bottle for the most original answer! Bit Manipulation instructions Instruction: BTST Syntax: BTST Dn, or BTST #, Data sizes: only byte when is an address. Only long when is a data register. Condition codes affected: X not affected N not affected Z set if the result is zero, cleared otherwise V not affected C not affected Addressing modes allowed: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # (only when source is Dn) Function: Test a single bit of an effective address operand. Bits are numbered from 0 to 31, where 0 is the least significant bit (you could use this instruction to test if a number is odd). This instruction is useful when specific bits of an operand have to be checked. E.g. when reading joystick information one could test with a single instruction whether the fire-button was pressed or not. Compared to the 6502 and 6809 this instruction (in fact all bit manipulation instructions) are a step forward, since with these older processors one had to put the data in a register first, then filter the bit with an AND-operation and then the Z-bit in the status register was at last set. Viva el 68000!! Since this instruction has the rather odd property of only working on byte and long operands it is important that you remember what I wrote in a previous part about specifying data sizes. Examples: Instruction Before After BTST.B #5,$345678 $345678 $345678 contains contains $78 $78 Z-bit is 1 BTST.L d0,d1 d0=0 d0=0 d1=$12345678 d1=$12345678 Z-bit is 0 Instruction: BCLR Syntax: BTST Dn, or BTST #, Data sizes: only byte when is an address. Only long when is a data register. Condition codes affected: X not affected N not affected Z set if the result is zero, cleared otherwise V not affected C not affected Addressing modes allowed: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # (only when source is Dn) Function: Bit test and CLeaR. First tests the bit to be cleared and sets the Z-bit accordingly, then clears the specified bit. Examples: Instruction Before After BCLR.B #5,$345678 $345678 $345678 contains contains $78 $58 Z-bit is 1 BCLR.L d0,d1 d0=0 d0=0 d1=$12345678 d1=$12345678 Z-bit is 0 Instruction: BSET Syntax: BSET Dn, or BSET #, Data sizes: only byte when is an address. Only long when is a data register. Condition codes affected: X not affected N not affected Z set if the result is zero, cleared otherwise V not affected C not affected Addressing modes allowed: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # (only when source is Dn) Function: Bit test and SET. First tests the bit to be set and sets the Z-bit accordingly, then sets the specified bit. This instruction and the BCLR instruction can be used as alternatives to the TAS-instruction. Examples: Instruction Before After BSET.B #5,$345678 $345678 $345678 contains contains $78 $78 Z-bit is 1 BSET.L d0,d1 d0=0 d0=0 d1=$12345678 d1=$12345679 Z-bit is 0 Instruction: BCHG Syntax: BCHG Dn, or BCHG #, Data sizes: only byte when is an address. Only long when is a data register. Condition codes affected: X not affected N not affected Z set if the result is zero, cleared otherwise V not affected C not affected Addressing modes allowed: Destination: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # (only when source is Dn) Function: Bit test and CHanGe. First tests the bit to be changed and sets the Z-bit accordingly, then changes the specified bit. Examples: Instruction Before After BCHG.B #5,$345678 $345678 $345678 contains contains $78 $58 Z-bit is 1 BCHG.L d0,d1 d0=0 d0=0 d1=$12345678 d1=$12345679 Z-bit is 0 Binary Coded Decimal (BCD) instructions To understand this instructionclass we must first know what a BCD- digit is. It is a representation of decimal digits in an array of bytes (array may be of length 1 or greater). In every byte the decimal number 0 to 99 can be represented. This is done as follows: a byte can be divided into two four-bit parts, called nibbles. In every nibble, one decimal digit is represented. This implicates that the binary combination 1010 can never occur in BCD representation, since it isn't in the decimal range from 0 to 9. The BCD-representation is especially convenient when printing such a digit, since it doesn't take much calculation to convert it to a printable character. A disadvantage of the BCD-representation is that one doesn't use the full storage capacity of a byte or word. The 68000 has three special BCD-artithmetic instructions. Instruction: ABCD Syntax: ABCD Dn,Dn or ABCD -(An),-(An) Data sizes: byte Condition codes affected: X set by carry out of most significant BCD-nibble, cleared otherwise N undefined Z set if the result is zero, cleared otherwise V undefined C same as X-bit Function: Add two BCD-digits. The predecremeting addressing mode has been provided for computations with multiple precision BCD-numbers. This implies that the most significant BCD-numbers must be stored in the lower memory addresses. Examples: Instruction Before After ABCD.B d0,d1 d0=$53 d0=$53 d1=$32 d1=$85 Instruction: SBCD Syntax: SBCD Dn,Dn or SBCD -(An),-(An) Data sizes: byte Condition codes affected: X set by carry out of most significant BCD-nibble, cleared otherwise N undefined Z set if the result is zero, cleared otherwise V undefined C same as X-bit Function: Subtract two BCD-digits. Examples: Instruction Before After ABCD.B d0,d1 d0=$53 d0=$53 d1=$32 d1=$21 Instruction: NBCD Syntax: NBCD Data sizes: byte Addressing modes allowed: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l Condition codes affected: X set by borrow out of most significant BCD-nibble, cleared otherwise N undefined Z set if the result is zero, cleared otherwise V undefined C same as X-bit Function: Negate a BCD-number. How it functions can be best described with an example. Let's negate $23. The NBCD operation yields $77. Now, how did we get this result? It's easy, just subtract $23 from $99 and you've got it. Examples: Instruction Before After NBCD.B d0 d0=$43 d0=$56 This is the end of part seven. Next time I will deal with all program flow instruction, such as branches and jumps. MC 68000 ASSEMBLY LANGUAGE COURSE PART VIII by Mark van den Boer Program Control Instructions This class of instructions enables a programmer to create loops and IF-THEN-ELSE like decisions. That's why it's the most important group of instructions and every programmer should have a thorough knowledge of this group. This class of instructions are specifically meant to affect the program counter. Instructions: Bcc (cc stands for Condition Code) Syntax: Bcc
Data sizes: Byte or word. This implicates that the branch- instructions can branch in an area of 32K. When using a branch with a byte offset you can put a .S suffix behind the instruction e.g. BEQ.S . When using a branch with a word offset you can put a .W suffix behind the instruction e.g. BEQ.W . Most assemblers will determine if the short or word form is needed. Also most assemblers will optimize word-branches to byte-branches whenever possible. Condition codes affected: None Function: Test a combination of the NZVC-flags in the status- register and conditionally perform a branch to another address. If the testing of the condition codes is true, then the branch will be taken, in the other the instruction immediately following the Bcc instruction will be executed. A total of 15 possible variations of this instruction are listed below. BCC: where CC stands for Carry Clear. The branch is taken if the C-bit is 0. This instruction is often used in combination with shift and rotate instructions. BCS: where CS stands for Carry Set. The branch is taken if the C-bit is 1. This instruction is the counterpart of the BCC-instruction. BEQ: where EQ stand for EQual. The branch is taken if the Z-bit is 1. This instruction is often used after a TST-instruction or CMP-instruction. BNE: where NE stands for Not Equal. The branch is taken if the Z-bit is 0. This instruction is the counterpart of the BNE-instruction. BPL: where PL stands for PLus. The branch is taken if the N-bit is 0. This instruction is often used after a TST-instruction or CMP-instruction. BMI: where MI stands for MInus. The branch is taken if the N-bit is 1. This instruction is the counterpart of the BPL-instruction. BVC: where VC stands for oVerflow Clear. The branch is taken if the V-bit is 0. This instruction is often used after an Integer Arithmetic instruction like ADD, SUB, MUL etc. BVS: where VS stands for oVerflow Set. The branch is taken if the V-bit is 1. This instruction is the counterpart of the BVC-instruction. BRA: where RA stands for bRanch Always. This instruction is often used at the end of a loop to go back to the beginning of the loop. Branches often used after an arithmetic operation on two's complement numbers. BGE: where GE stands for Greater or Equal. This branch is taken if the N and V-bits contain the same value. BGT: where GT stands for Greater Than. This branch is taken in the following cases: - N is 1, V is 1, Z is 0 - N is V is Z is 0 BLE: where LE stands for Lower or Equal. This branch is taken in the following cases: - Z is 1 - N and V-bits contain different values BLT: where LT stands for Less Than. This branch is taken if the N and V-bits contain different values. Brances often used after an arithmetic operation on unsigned numbers. BHI: where HI stands for HIgher. This branch is taken if the N and V-bits contain the same value. BLS: where LS stands for Lower or Same. This branch is taken if the C and Z-bits contain different values. Example: This shows a piece of a C-program and an equivalent piece of a PASCAL-program which are translated into assembler. (variabele is signed) C: if (variable == 1 || variable > 4) variable = 5; else var *= 3; PASCAL: if (variable == 1) or (variable > 4) then variable := 5 else variable := variable * 3 * Most assemblers will optimize the branch-instructions * to the short forms CMP.W #1,variable BEQ L10000 CMP.W #4,variable BLE L2 L10000: MOVE.W #5,variable BRA L3 L2: MOVE.W variable,R0 MULS #3,R0 MOVE.W R0,variable L3: Instructions: DBcc (cc stands for Condition Code) Syntax: DBcc Dn,
Data sizes: byte or word. This implicates that the branch- instructions can branch in an area of 32K. Dn is considered to contain a word. Condition codes affected: None Function: The group of Decrement and Branch (DBcc) instructions provide an efficient way of creating loops. They are nearly always placed at the end of a loop. First the condition is tested, then the dataregister is decremented. The branch is taken in the following cases: - Dn is -1; - The condition cc in DBcc is satisfied. There are 16 possible variations of this instruction. They all are nearly the same as the Bcc-instructions, with two exceptions. These are: DBF or DBRA: This loop can only be terminated by count since the other condition can never be satisfied. DBT: Only performs a decrement on the dataregister and never branches. To me this seems a pretty useless instruction, which is only there to make the DBcc series logically complete. Example: This piece of code is an efficient implementation of the strcpy-function of the C-language. A0 contains the address of the source string and A1 contains the address of the destination string. In C the end of a string is marked by a byte containing 0. MOVE.W #$ffff,D0 LOOP: MOVE.B (A0)+,(A1)+ DBEQ D0,LOOP This piece of code can easily be transformed into the strncpy-function by loading D0 with the appropriate value. Instructions: Scc (cc stands for Condition Code) Syntax: Scc
Data sizes: byte. Condition codes affected: None Function: Sets a byte to $ff if the condition codes satisfie. If the condition is not satisfied the byte is set to 0. This group of 16 instructions is rarely used. Nearly all forms are the same as the DBcc group except for the following two instructions: SF: the same as a CLR.B instruction ST: the same as a MOVE.B #$ff,
Example: Be inventive, invent one yourself! Instruction: BSR, JSR Syntax: BSR
JSR
Data sizes: none Condition codes affected: none Addressing modes allowed (only for JSR): Destination: (An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Function: The BSR (Branch to SubRoutine) and JSR (Jump to SubRoutine) instructions are used for calling subroutines. BSR can branch in a range of 32K. JSR should be used when a jump out of the 32K range is needed. Some assemblers optimize JSR into BSR instructions whenever possible, since BSR is more efficient than JSR. When executing a BSR/JSR instruction, the 68000 first pushes the PC (program- counter) on the stack and then load the PC with the new address. See below for the RTS (ReTurn from Subroutine) instruction. Instruction: RTS Syntax: RTS Data sizes: none Condition codes affected: none Function: Counterpart of BSR/JSR instructions. Reloads the PC with the value on top of the stack. This value will nearly always have been put on top of the stack by a BSR/JSR instruction. Example: * the strcpy function discussed before STRCPY: MOVE.W #$FFFF,D0 LOOP: MOVE.W (A0)+,(A1)+ DBEQ D0, LOOP RTS * some other code BEGIN: MOVE.L #SOURCE,A0 MOVE.L #DEST,A1 JSR STRCPY RTS * the strings are put in a data area .DATA * 80 bytes for every string SOURCE .DS.B 80 DEST .DS.B 80 * .DS.B means Define Storage Byte * so 80 bytes are define as storage for each string Instruction: JMP Syntax: JMP Data sizes: none Condition codes affected: none Addressing modes allowed: Destination: (An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) Function: Transfer program control to another address. The PC is loaded with the specified address. In fact this is a variant of the MOVE instruction. In this case the destination register is inherently defined, namely the PC-register. Therefore we could translate JMP to MOVE.L ,PC . Instruction: RTR Syntax: RTR Data sizes: none Condition codes affected: none Function: ReTurn and Restore. Counterpart of BSR/JSR instructions. Reloads the PC with the value on top of the stack. This value will nearly always have been put on top of the stack by a BSR/JSR instruction. The only difference with the RTS is that with this instruction also the CCR is reloaded. This instruction is rarely used but comes in handy when one doesn't want a subroutine to influence the condition codes. Before the JSR instruction you should use the instruction: MOVE.B CCR,-(A7) which pushes the CCR on the stack Next time: The last part of the instruction set. These are the instructions which can only be executed when supervisor-mode is active. ASSEMBLY LANGUAGE COURS PART IX by Mark van den Boer System Control instructions In this part of the course the last group of instructions will be explained. This group of instructions deals with the supervisor- mode and are therefore sometimes referred to as system control instructions. To remind you: the S-bit in the SR (status register) of the 68000 determines whether the 68000 is in supervisor-mode or not. Many of these instructions deal with so called exceptions. Exception is another word for interrupt and these are used to force program control immediately to a specific routint exception handler routine. Exceptions are used to detect situations that are urgent and need to be handled directly. Therefore every exception has a vector assigned to it. This vector is a pointer to a routine which performs some action which should be taken when such an exception occurs. The exception vectors are located in the first 256 longwords of memory. Instruction: CHK Syntax: CHK ,Dn Data sizes: word Condition codes affected: X not affected N Set if Dn is less than zero, cleared if less than Dn, in all other cases undefined Z V C always undefined Addressing modes allowed: Source: Dn (An) (An)+ -(An) w(An) b(An,Rn) w l w(PC) b(PC,Rn) # Destination: Dn Function: Compares the contents of the effective address operand with the data-register. If the data register is less than zero (the data register is always considered to be a signed word) or greater than the contents of , then an exception occurs. The pointer to this exception-routine is located at address $18. This instruction is used to check if a data register is within a range. It is often used by high-level languages such as PASCAL to perform array-bound checking. Examples: Instruction Before After CHK #50,D0 D0=45 D0=45 No exception occured, if D0 had been 51 or greater then an exception would have occured. Instruction: MOVE USP (privileged instruction) Syntax: MOVE USP,An or MOVE An,USP Data sizes: long Condition codes affected: X N Z V C not affected Addressing modes allowed: See syntax Function: As you all should know, the 68000 has in fact two A7 registers. One A7 register is used when in supervisor- mode, the other when in usermode (this is: not in supervisor-mode. It is sometimes desirable for a program which is executing in supervisor mode to know the value of the usermode A7-register. This instruction provides a way to obtain and change the value of A7 usermode-register. Example: Instruction Before After MOVE USP,A6 A7user=$12345678 A7user=$12345678 A6 =$00000000 A6 =$12345678 A7sup =$87654321 A7sup =$87654321 Instruction: RESET Syntax: RESET (privileged instruction) Data sizes: none Condition codes affected: X N Z V C not affected Function: Reset all external devices. A device can be a chip like the 6850. Instruction: RTE (privileged instruction) Syntax: RTE Data sizes: none Condition codes affected: none Function: Every exception is terminated by this instruction. It can be compared to RTS. The only difference is that RTE will restore the SR in addition. Note that an exception-routine has the responsibility to save registers if this is important. Instruction: STOP (privileged instruction) Syntax: STOP # Data sizes: word Condition codes affected: All set as a direct result of the operand Addressing modes allowed: Source: # Function: Stop execution of a program until an exception occurs. The operand stored in the SR. Note that with the operand a minimum interrupt level can be determined. With this instruction it is possible to wait for a videochip interrupt to occur. Example: STOP #%0010011000011111 Wait for an exception with a priority of 6 or 7 to occur and set the XNZVC-bits. Instruction: TRAP Syntax: TRAP # Data sizes: # must be >=0 and <=15 Condition codes affected: X N Z V C not affected Function: This instruction generates an exception. The operand indicates an exception number. The vectors for the exceptions are located at addresses $80 to $BC. This instruction is mainly used to allow programs that execute in user-mode to call supervisor-mode routines. This way a user can be given a number of specific functions. In the ST trap vectors 2, 14 and 15 are used for GEM, BIOS and XBIOS functions. In the case of the ST the TRAP-instructions is preceded by instructions that put function numbers and parameters for these functions on the stack. This way it is possible to assign groups of functions to one trap-vector. Note that when calling a TRAP in user-mode the stackpointers change (supervisor-mode and user-mode, remember??). Thus, the MOVE USP instruction can be used to retrieve parameters that had been put on the stack. Instruction: TRAPV Syntax: TRAPV Data sizes: none Condition codes affected: none Function: When the V-bit is set an exception occurs. The exception vector is located at address $1C. When the V- bit is clear nothing happens. This instruction can be used by high-level languages to inform the user that an overflow error has occured. MC 68000 ASSEMBLY LANGUAGE COURSE PART X by Mark van den Boer Now all instructions of the 68000 have been explained it's time to bring this knowledge into practice. This last part of the course will deal with the subject of translating high-level constructs to the equivalent assembler constructs. The C program- ming language will be used as the high-level language which has to be translated to assembler. A note to those of you who are more familiar with Pascal or BASIC: litte imagination is needed to deduct the similar constructs in Pascal and BASIC. What now follows is a C-program which containing several commonly used data- and control structures. The examples show you how to translate these structures into assembler. There should also be a file called M68000.DOC on your ST NEWS disk. This file contains a quick-reference card containing all instructions and allowed addressing modes. This reference card has been made by Trustware, Inc. (an unregistered trademark of Victor Langeveld). I am very grateful to Victor for allowing me to include this card, since it's a rather tedious job to put together such a card. One thing's for sure: this card is one of the better of its kind and it's the most compact reference card for the 68000 I've ever seen. /* A function. (Called a procedure or function in Pascal and a subroutine in BASIC) Note how parameters are passed in the assembly language translation. Als pay attention to how local variables are stored. */ int function (number, pointer) int number; char *pointer; { register int i, j; char *c; i = number - 1; c = pointer; c = "new Queensryche album: Operation Mindcrime"; /* Note how a string is stored */ return i; /* Note how a value is returned */ } .text function: * offset of number = 8 * offset of pointer = 10 LINK A6,#-4 * save registers MOVEM.L D6-D7,-(sp) * sp = A7 * i in D7 * j in D6 * offset of c = -4 * i = number - 1 MOVE.W 8(A6),D7 SUB.W #1,D7 * c = pointer MOVE.L 10(A6),-4(A6) * c = "new Queensryche album: Operation Mindcrime" .data L2: .dc.b 'new Queensryche album: Operation Mindcrime',0 MOVE.L #L2,-4(A6) * D0 is used for resulting values from functions * return i; D0 is always used for the result of a function MOVE.W D7,D0 * restore registers MOVEM.L (sp)+,D6-D7 UNLK A6 * } RTS * global variables .bss * int i; i: .ds.w 1 * char character character: .ds.b 1 * int *i_pointer i_pointer: .ds.l 1 * int i_array[10][5] i_array: .ds.w 10*5 * one struct is in fact 3 bytes long, but for every structure * 4 bytes are reserved. This is because the 68000 can only * address words at even addresses. * struct { /* this is the equivalent of a record in PASCAL */ * int i; * char c; * } structure[5]; structure: .ds.b 4*5 main() { /* assignment of a constant to a variable */ i = 9; /* assignment of a constant to a variable */ character = 'c'; /* assignment of a constant to a variable */ i_pointer = &i; /* watch how indexing of array is done */ /* integer is 2 bytes, so the address of array-element [3][4] is: (3 * 5 (the length of i_array[3]) + 4) * 2 (size of an integer) = 38. So the integer should be stored at i_array + 38. */ i_array[3][4] = *i_pointer; /* Now the distance in bytes from the beginning of the array must be computed during program execution, in contrary to the previous example. */ i_array[i][i - 1] = 2; /* Assignments to arrays of structures */ structure[1].i = 3; structure[i].c = character; /* expression evaluation and assignment */ i = i_array[0][0] * i_array[0][1] + i_array[0][2] / i_array[0][3]; /* conditional statement */ if (i < i_array[i][i]) i = 1; else i = 2; /* while loop */ while (i <= 10) i++; /* continue and break statements */ while (i++ <= 10) { if (i != 4) continue; else break; } /* for loop */ for (i = 4; i >= 0; i--) i_array[i][i] = i; /* do loop */ do i++; while (i < 10 && i != 5); /* switch statement; watch the application of a jump-table. Pay special attention to how 'case 4' which must 'default' is solved. */ switch (i) { case 0: i = 0; break; case 1: i = 5; break; case 2: case 3: i = 7; break; case 5: i = 1; break; default: i = 2; break; } /* switch statement; watch how 'case 999' has destroyed the jumptable-optimization. */ switch (i) { case 0: i = 0; break; case 1: i = 5; break; case 2: case 3: i = 7; break; case 5: i = 1; break; case 999: /* This case should be tested seperately so the assembler code can be more efficient. */ i = 100; break; default: i = 2; break; } /* manipulating bits */ i = i & 0x2345; i = i | 0x2345; i = i ^ 0x2345; i = ~i; i <<= i; /* using the result of a function */ i = function(5, &character); } .text main: * Reserve 4 bytes. This way, when the first parameter for a * function is pushed onto the stack, no pre-decrementing of sp * has to be done. This 'trick' is used by the DRI-C-compiler. LINK A6,#-4 * i = 9 MOVE.W #9,i * character = 'c' MOVE.B #'c,character * i_pointer = &i MOVE.L #i,i_pointer * i_array[3][4] = *i_pointer MOVE.L i_pointer,A0 MOVE.W (A0),38+i_array * i_array[i][i - 1] = 2 MOVE.W i,D0 * compute byte offset from first element MULS #10,D0 MOVE.W i,D1 SUB.W #1,D1 ASL.W #1,D1 * multiply by 2 because an int is 2 bytes EXT.L D1 ADD.L D1,D0 ADD.L #i_array,D0 MOVE.L D0,A0 * move computed address to address-reg MOVE.W #2,(A0) * structure[1].i = 3 MOVE.W #3,4+structure * structure[i].c = character MOVE.W i,A0 ADD.L A0,A0 ADD.L A0,A0 * Two ADD operations are faster than a MUL and a MOVE ADD.L #structure,A0 MOVE.B character,2(A0) * i = i_array[0][0] * i_array[0][1] + * i_array[0][2] / i_array[0][3]; MOVE.W i_array,D0 MULS 2+i_array,D0 MOVE.W 4+i_array,D1 EXT.L D1 DIVS 6+i_array,D1 ADD.W D1,D0 MOVE.W D0,i * if (i < i_array[i][i]) i = 1; * else i = 2; MOVE.W i,D0 MULS #10,D0 MOVE.W i,D1 ASL.W #1,D1 EXT.L D1 ADD.L D1,D0 MOVE.L D0,A0 MOVE.L #i_array,A1 MOVE.W 0(A0,A1.L),D0 CMP i,D0 BLE L4 * i = 1 MOVE.W #1,i BRA L5 L4: * i = 2 MOVE.W #2,i L5: BRA L8 * while (i <= 10) i++; * This loop has been optimized: * one BRA instruction was saved by putting the test after the * do-part. The label L5: BRA L8 takes care that the while * condition is executed first at the beginning of the loop L7: ADD.W #1,i L8: CMP.W #10,i BLE L7 * while (i++ <= 10) { * if (i != 4) continue; * else break; * } L6: BRA L11 L10: CMP.W #4,i BNE L11 BRA L9 L11: CMP #10,i MOVE.W SR,D0 * save condition codes ADD.W #1,i MOVE D0,CCR * and restore BLE L10 * for (i = 4; i >= 0; i--) i_array[i][i] = i L9: MOVE.W #4,i BRA L14 L15: MOVE.W i,D0 MULS #10,D0 MOVE.W i,D1 ASL.W #1,D1 EXT.L D1 ADD.L D1,D0 ADD.L #i_array,D0 MOVE.L D0,A0 MOVE.W i,(A0) L13: SUB.W #1,i L14: TST i BGE L15 L12: * do i++; while (i < 10 && i != 5); L18: ADD.W #1,i L17: CMP.W #10,i BGE L10000 CMP.W #5,i BNE L18 L10000: * switch (i) { * case 0: * i = 0; * break; * case 1: * i = 5; * break; * case 2: * case 3: * i = 7; * break; * case 5: * i = 1; * break; * default: * i = 2; * break; * } L16: MOVE.W i,D0 BRA L20 L21: CLR.W i BRA L19 L22: MOVE.W #5,i BRA L19 L23: L24: MOVE.W #7,i BRA L19 L25: MOVE.W #1,i BRA L19 L26: MOVE.W #2,i BRA L19 L20: * Test if i is in case-range * if not goto default * if in range compute address to jump to CMP.W #5,D0 BHI L26 ASL.W #2,D0 MOVE.W D0,A0 ADD.L #L27,A0 MOVE.L (A0),A0 JMP (A0) .data L27: * jumptable .dc.l L21 .dc.l L22 .dc.l L23 .dc.l L24 .dc.l L26 .dc.l L25 .text L19: * switch (i) { * case 0: * i = 0; * break; * case 1: * i = 5; * break; * case 2: * case 3: * i = 7; * break; * case 5: * i = 1; * break; * case 999: * /* This case should be tested seperately so * the assembler code can be more efficient. * */ * i = 100; * break; * default: * i = 2; * break; * } MOVE.W i,D0 BRA L29 L30: CLR.W i BRA L28 L31: MOVE.W #5,i BRA L28 L32: L33: MOVE.W #7,i BRA L28 L34: MOVE.W #1,i BRA L28 L35: MOVE.W #100,i BRA L28 L36: MOVE.W #2,i BRA L28 BRA L28 L29: EXT.L D0 MOVE.L #L37,A0 MOVE.W #6,D1 L38: CMP.L (A0)+,D0 DBEQ D1,L38 MOVE.L 24(A0),A0 JMP (A0) .data L37: * table of case values .dc.l 0 .dc.l 1 .dc.l 2 .dc.l 3 .dc.l 5 .dc.l 999 .dc.l 0 * jump table .dc.l L30 .dc.l L31 .dc.l L32 .dc.l L33 .dc.l L34 .dc.l L35 .dc.l L36 .text L28: * i = i & 0x2345 ANDI.W #$2345,i * i = i | 0x2345 ORI.W #$2345,i * i = i ^ 0x2345 EORI.W #$2345,i * i = ~i NOT.W i * i <<= i MOVE.W i,D1 MOVE.W D1,D0 ASL.W D1,D0 MOVE.W D0,i * i = function (5, &character) MOVE.W #51,(sp) MOVE.L #character,-(sp) ADDQ.L #4,sp MOVE.W D0,i L3: UNLK A6 RTS Hope you had much fun with this course and that you learnt a lot! Read the other articles too....