Another great doc for the budding assembly langage programmers. Part 6-10 of of the 68000 Machine Language Course Brought to you by Sewer Software 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!