The Guide to 68000 Assembly Language
Jump to navigation
Jump to search
66666 88888 00000 00000 00000 6666666 8888888 0000000 0000000 0000000 666 666 888 888 000 000 000 000 000 000 666 888 888 000 000 000 000 000 000 666 888 888 000 000 000 000 000 000 66666666 8888888 000 000 000 000 000 000 666666666 888 888 000 000 000 000 000 000 666 666 888 888 000 000 000 000 000 000 666 666 888 888 000 000 000 000 000 000 6666666 8888888 0000000 0000000 0000000 66666 88888 00000 00000 00000 THE GUIDE TO 68000 ASSEMBLY LANGUAGE FOR FARGO PROGRAMMERS VERSION 1.1.1 by Jimmy Mardell <yarin@acc.umu.se> ----------------------------------------- 0.0 ADMINISTRIVIA ----------------------------------------- ---------------- 0.01 CONTENTS ---------------- 0.00 ADMINISTRIVIA 0.01 Contents 0.02 Read this first! 1.00 ABOUT MOTOROLA 68000 1.01 Registers 1.02 Flags 1.04 Some information about the instructions 1.05 Effective address 1.06 The stack 1.07 How to use the libraries 1.08 How to address variables 1.09 Handles 1.10 Common errors 2.00 INSTRUCTION SUMMARY 2.01 How the summary is structured 2.02 Data movement 2.03 Integerarithmetic 2.04 Logical operations 2.05 Shift and rotation 2.06 Bitmanipulation 2.07 BCD-instructions 2.08 Programcontrol 2.09 Systemcontrol 2.10 Other instructions 3.00 PROGRAMMING STUFF 3.01 The video memory 3.02 Highscores etc 3.03 Arrays 4.00 MISCELLANEOUS 4.01 Version history 4.02 Greetings 4.03 How to contact me ---------------------- 0.02 READ THIS FIRST! ----------------------- This guide can be used alone if you allready know some assembly programming. In this case, this instruction set and fargo doc is enough. If you are new to assembly programming, it could be usefull to read the guide: tutorial.zip available at ticalc.org. Please, note that a few sections were removed from version 1.0 so that this guide is a better complement to the tutorial.zip guide. All reference done to other files not belonging to fargo distribution are reference to some files included in tutorial.zip. This guide is NOT for newbies. It almost requires that you know something (much something) about another assembly language (Z80, x86 etc). If you just know a few high level languages (such as Pascal, Basic, C/C++) you could of course learn from this guide (it isn't THAT cryptict) but I recommend that you read some stuff about low level language programming. I assume you know what binary, hexadecimal, two complement, register, flags, stack are and all other basic things that you MUST KNOW when programming in a lowlevel language. If you think that anything important is missing, mail me! See 4.03 How to contact me for more information. And when contacting me, PLEASE tell me which version of this guide you have!! If you got an old version and ask a question that have been fixed in the current version, misunderstandings may arise. Now over to the guide... ----------------------------------------- 1.0 ABOUT MOTOROLA 68000 ----------------------------------------- --------------- 1.01 REGISTERS --------------- The 68000 has 16 register, 8 data registers (D0-D7) and 8 address registers (A0-A7) and they are all longword, ie 32 bit. No data or address register is different from any other. That means whenever you can use D0, you can always use D1-D7 also, the D0 register isn't a "main register", as the A register is on a Z80, or the registers on a x86 where all registers are made for different purposes (AX - accumulator, CX - counter, SI,DI - pointers etc). The only real difference between the registers is data regs vs the address regs. One important thing is that if you have a longword stored in a data register and you move a byte into it, the most significant three bytes are still there! This may cause problems when you later add or multiplicate the register, you MUST clear the most significant part! The 68k also has a PC, Program Counter, as most CPU have. Works the same way too (it is a 24 bit reg). The stack pointer is actually the A7 register, so maybe you should say that A7 works differently compared to A0-A6, but it doesn't really. You could use A6 as stack pointer, except that all ROM routines and the CPU itself ( see Bsr and Jsr ) use A7 as SP so it wouldn't be a good idea... ------------ 1.02 FLAGS ------------ Then we have the flags. They're stored in the status register (SR), a 16 bit register. It's divided into two parts, the systembyte (bit 15-8) and the userbyte (or flagregister) (bit 7-0). Here's a description over the whole SR register: Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ------------------------------------------------- | T| -| S| -| -| I2,1,0 | -| -| -| X| N| Z| V| C| - the status register ------------------------------------------------- * The Systembyte Bit 15: T - The trace bit. If it's set an interrupts will be called after each instruction. Often used in debuggers. Bit 13: S - Supervisor bit. When this bit is set, you have more "access" to some instructions and also to the systembyte. The reason for this is that it prevents programs to disturb the OS with some instructions that you shouldn't use if you're not writing an OS. Is enabled when interruptions are generated. Bit 8-10: The interrupt mask The I0, I1 and I2 bits of the system register are used to set the interrupt mask: in fact, it means that they are set to an interupt level: if the trap generated has a level higher than the interrupt mask, then the trap is executed. Otherwise it is ignored. ( ignoring a trap generally means that another interrupt, with a higher priority is beeing treated ) Here is how these bits are set: | I2 | I1 | I0 | level 0 | 0 0 0 | ---------> lowest priority level 1 | 0 0 1 | level 2 | 0 1 0 | level 3 | 0 1 1 | level 4 | 1 0 0 | level 5 | 1 0 1 | level 6 | 1 1 0 | level 7 | 1 1 1 | ---------> highest priority Note: #0=%000; #1=%001; #2=%010; etc... One should refer to the \system.txt file and \lesson\lesson_3.txt for more on interruptions. * The flagregister - C-flag (Carry). Works as carry is used to work. If you add two 8 bit numbers, the C-flag will be the 9th bit. Also used with shift and rotation. - V-flag (oVerflow). Will be set if a result can't be represented. For example, when you add $7F and $01, $80 can't be stored since that means -128 in two complement. - Z-flag (Zero). Is set if the result of an operation is zero. - N-flag (Negative). If the highest bit in the result is set (in two complement it means the sign bit), N will be set. - X-flag (eXtended). This flag is a copy of the carry-flag, but it won't be changed in all operations where C is changed. This allows you to first make a check (that will set C and X), then some other instructions that will change the C flag but not the X flag, and THEN you can make the branch according to the flags, which means you can use the X flag. --------------------------------------- 1.03 HOW DATA IS STORED IN THE MEMORY --------------------------------------- The 68000-processor supports two different datatypes: binary and BCD Float numbers are not supported. One needs a coprocessor. I don' t know whether there exist one for the 68000 processor. Data is stored the "Big Indian" way: The Z80 and x86 stores binary numbers with the LSB in the first byte, ie $12345678 is stored $78,$56,$34,$12 in the memory. The 68k stores it the other way around, $12,$34,$56,$78. That way to store numbers in the memory is called "Big Indian". ---------------------------------------------- 1.04 SOME INFORMATION ABOUT THE INSTRUCTIONS ---------------------------------------------- Most instructions on the 68k have a suffix that shows how much data should be used in the instructions. This can be a byte (.B), a word (.W) or a longword (.L). Another very important thing is that all instructions are backwards (compared to most CPUs). With that I mean that the source of the instruction is the first arg and the destination is the last arg. For example: MOVE.W D0,D1 moves (actually, copies) the first 16 bits (a word) from D0 to D1. ------------------------ 1.05 EFFECTIVE ADDRESS ------------------------ The 68000s have 14 different ways to address things in the memory. This example will use the instruction MOVE (LD on Z80, MOV on x86) to demonstrate how they work. Later, in the instruction summary, you'll see that when an instruction has <ea> (effective address) as an arg, it doesn't mean it can use all 14 ways to address. It almost always has restrictions. 1) IMMEDIATE ADDRESSING WITH DATA REGISTERS Syntax: Dn (where n is 0-7) Example: MOVE.L D1,D0 copies the contents of D1 to D0. When the instruction is executed, both registers will contain the same information. When moving a byte or a word, the upper part of the register will remain unchanged. 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 | -------------------------------------------- 2) IMMEDIATE ADDRESSING WITH ADDRESSREGISTERS Syntax: An (n is 0-7) Example: MOVE.L A1,D0 copies whole A1 to D0. After the instruction, both registers contain the same information. When transfering with addressregisters you must use word or longword. When a word is transfered TO an address register, bit 15 (the sign bit) will be copied trough the whole upper word (bit 16-31). If it wasn't so, a negative number would become positive. 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 | -------------------------------------------- |MOVE.W D0,A1 | D0=0000FFFF | D0=0000FFFF | | | A1=00000000 | A1=FFFFFFFF | -------------------------------------------- 3) INDIRECT ADDRESSING WITH ADDRESSREGISTERS Syntax: (An) (n is 0-7) Example: MOVE.L (A0),D0 copies the longword stored at address location A0 (you say A0 points to the longword). If you refer to a word or a longword, the address in the address register must be an even number. THIS CAN CAUSE BIG PROBLEMS AND UNEXCEPTED ERRORS!! Instruction Before After --------------------------------------------------- |MOVE.L (A1),D0 | D0=FFFFFFFF | D0=01234567 | | | A1=00001000 | A1=00001000 | | | $1000=01234567 | $1000=01234567 | --------------------------------------------------- 4) INDIRECT ADDRESSING WITH ADDRESSREGISTERS WITH AFTERINCREASMENT Syntax: (An)+ (n is 0-7) Desc.: Works as the previous addressing mode, except that after the instruction, An will be increased with the size of the operation. A special case is when you use A7 and transfer a byte, because A7 will be increased with 2 instead of 1, because A7, as stack pointer, must be an even number. Example: MOVE.L (A1)+,D0 copies the longword which A1 points to to D0, and increases A1 with 4. Instruction Before After ---------------------------------------------------- |MOVE.L (A1)+,D0 | D0=FFFFFFFF | D0=01234567 | | | A1=00001000 | A1=00001004 | | | $1000=01234567 | $1000=01234567 | ---------------------------------------------------- 5) INDIRECT ADDRESSING WITH ADDRESSREGISTERS WITH PREDECREAMENT Syntax: -(An) (n is 0-7) Desc.: Works as the previous addressing mode, except that An will first be decreased with the operand size (with the exception of A7), then the data will be transfered. Example: MOVE.L -(A1),D0 first decreases A1 with 4, then copies the longword stored at A1 to D0. Instruction Before After ---------------------------------------------------- |MOVE.L (A1)+,D0 | D0=FFFFFFFF | D0=01234567 | | | A1=00001004 | A1=00001000 | | | $1000=01234567 | $1000=01234567 | ---------------------------------------------------- 6) INDIRECT ADDRESSING WITH ADDRESSREGISTER WITH SHIFTING Syntax: x(An) (x is 16 bit, n is 0-7) Desc.: The location pointed at x+An is the one that will be copied. Example: MOVE.L 4(A1),D0 copies the longword stored at A1+4 to D0. A1 will, after the instruction, remain unchanged. Note that if x is bigger than $7FFF, it means a negative value. It's because of the sign extension. Instruction Before After ---------------------------------------------------- |MOVE.L 4(A1),D0 | D0=FFFFFFFF | D0=01234567 | | | A1=00001000 | A1=00001000 | | | $1004=01234567 | $1004=01234567 | ---------------------------------------------------- 7) INDIRECT ADDRESSING WITH ADDRESSREGISTER WITH SHIFTING Syntax: x(An,Dn.L) (x is 8 bit, n is 0-7) x(An,Dn.W) x(An,An.W) x(An,An.L) Desc.: Works as the previous addressing mode, except that another register also will be added (if it's a word, a sign extension will be made before, so it will be a subtraction). When working with words or longwords, the generated address must be an even address. Example: MOVE.L 4(A1,A2.L),D0 copies the longword stored at A1+A2+4 to D0. A1 and A2 will after the instruction remain unchanged. Note that if x is bigger than $7F, it means a negative value. It's because of the sign extension. Instruction Before After --------------------------------------------------------- |MOVE.L 4(A1,A2.L),D0 | D0=FFFFFFFF | D0=01234567 | | | A1=00001000 | A1=00001000 | | | A2=00001000 | A2=00001000 | | | $2004=01234567 | $2004=01234567 | --------------------------------------------------------- 8) ABSOLUTE ADDRESSING (NEAR) Syntax: x (x is a 16 bits constant) Desc.: The address will be sign extensioned before it's used, but the MSB is ignored (don't bother about that). The sign extension means that near addressing can only be used on the first 32Kb. Example: MOVE.L $1000,D0 copies the longword stored at $1000 to D0. Note that there is no parentheses! If you mean an immediate value, you put a # before the value (see below). However, adding the parentheses is not a bad idea: the assembler will accept it and it will add in readability to the source. Instruction Before After ---------------------------------------------------- |MOVE.L $1000,D0 | D0=FFFFFFFF | D0=01234567 | | | $1000=01234567 | $1000=01234567 | ---------------------------------------------------- 9) ABSOLUTE ADDRESSING (FAR) Syntax: x (x is a 32 bits constant) Desc.: Works EXACTLY as the above move, except that x is a 32 bits value (the instruction is two bytes longer also). Example: MOVE.L $10000,D0 copies the longword stored at $10000 to D0. Instruction Before After ------------------------------------------------------- |MOVE.L $10000,D0 | D0=FFFFFFFF | D0=01234567 | | | $10000=01234567 | $10000=01234567 | ------------------------------------------------------- 10) PROGRAMCOUNTER WITH SHIFTING Syntax: x(PC) (x is a 16 bits constant) Desc.: The word (x) that follows the instruction will be added to the programcounter to get the memory location. The word will be sign extensioned before (meaning that the limits are -32768 to +32767). The value used for the programcounter is the address to x, not to the instruction (don't bother). Example: MOVE.L $100(PC),D0 copies the longword stored at PC+$102 (102 because the value $100 is stored 2 bytes after the instruction) to D0. Instruction Before After ------------------------------------------------------- |MOVE.L $100(PC),D0 | D0=FFFFFFFF | D0=01234567 | |(assuming PC=$1000)| $1102=01234567 | $1102=01234567 | ------------------------------------------------------- 11) PROGRAMCOUNTER WITH INDEX Syntax: x(PC,Dn.L) (x is 8 bits, n is 0-7) x(PC,Dn.W) x(PC,An.W) x(PC,An.L) Desc.: Works as the previous one except that a dataregister or an an address register is added (with sign extension). Similiar to addressing mode 7. Example: MOVE.L $10(PC,A1.L),D0 copies the longword stored at PC+A1+$12 to D0. Instruction Before After ----------------------------------------------------------- |MOVE.L $10(PC,A1.L),D0 | D0=FFFFFFFF | D0=01234567 | |(assuming PC=$1000) | $2102=01234567 | $2102=01234567 | | | A1=00001000 | A1=00001000 | ----------------------------------------------------------- 12) IMMEDIATE ADDRESSING Syntax: #x (x is 8, 16 or 32 bits) Desc.: Uses the immediate value x. Example: MOVE.L #$10002000,D0 copies $10002000 to D0. Note that if you copy a word to an addressregister, the word will be sign extensioned. Instruction Before After --------------------------------------------------- |MOVE.L #$10002000,D0 | D0=01234567 | D0=10002000 | | | | | --------------------------------------------------- 13-14) ADDRESSING WITH THE STATUSREGISTER Syntax: SR CCR Desc.: The only instructions that are allowed to use this addressing mode are: ANDI (AND immediate), EORI (exclusive OR immediate) and ORI (OR immediate). If the length is a byte, the flag register is changed. If it's a word, both the flag register and the systembyte are changed (but then the supervisor bit, 13, must be set). The assembler recognize both SR (that means both flags and system-byte) and CCR (only flag register), so you don't have to specify the length. Example: The instruction ORI #5,CCR sets both the carryflag (C) and the zeroflag (Z). The other flags remains unchanged. Note: #5=#%00000101 Instruction Before After ------------------------------------ |ORI #5,CCR | CCR=0000 | CCR=0005 | ------------------------------------ ---------------- 1.06 THE STACK ---------------- As mentioned earlier, A7 works as stack pointer. The stack ( user and system stack ) is stored in the "system memory": you should not bother about the size: it should allways be more than enough... You may have noted one thing if you jumped to the instruction summary at once: there are no push/pop instructions! That's because they're not necessary, MOVE will do the job for us. For example, if we want to push D0.W (with this I mean D0, the lower 16 bits) we just MOVE.W D0,-(A7). And to pop it back, just MOVE.W (A7)+,D0. Remember that when popping a word, the upper 16 bits in D0 is still there. When you want to push many registers at once, for example in the beginning of a subroutine, it may be a bit boring to type all the move instruction (and it will take a lot of bytes also). There is a shortcut: MOVEM. With this instruction you can push (or just copy) many registers at once. If you want to push D0-D4 and A0-A2 for example, you just movem d0-d4/a0-a2,-(a7) and then movem (a7)+,d0-d4/a0-a2 Very handy... Another way to put things on the stack is with the PEA instruction. It pushes an effective address on the stack, used when pushing pointers. This will decrease A7 with 4 (the size of a pointer). ------------------------------- 1.07 HOW TO USE THE LIBRARIES ------------------------------- In most libraries, you just store the in paramters in some registers (read the .h file for each library), then call it with jsr library_name::lib_label, for example: jsr flib::idle_loop. That library call hasn' t any in parameters, but when you've pressed a key (idle_loop waits until a key is pressed), D0 will contain the character code of the key pressed. Before using a library function, you should check out the parameters, since it's not good if some important registers get destroyed in a library. Some libraries will push all registers that will be changed and pop them back at the end, with the exception of the out paramters of course. Most of the tios routines will destroy some registers. -------------------------------- 1.08 How to address variables -------------------------------- How do we address things? How do I copy the word stored at var1 to D0? It's very simple, just move.w (var1),d0 Note, ( ) is not needed. And, as usual, the upper 16 bits are unaffected. And, how to make A0 point at str1? Also easy, lea str1(PC),a0 You MUST type (PC) after the label, else it won't work! This is just a way to address a label (see 1.05 Effective Address) After loading A0 with the pointer to str1, you can get the first byte with move.b (a0)+,d0 This copies the first byte ('H' = 72) to D0 and increases A0 with one, thus pointing to the next character. Now you must use parantheses since else it would mean copy A0, not the byte stored at A0, to D0. --------------- 1.9 Handles --------------- You should read HANDLES.TXT that comes with Fargo to find out what they are, but here is how to use them. If you want to create a big array, for example a map or something else that is more than 10-20 bytes, you should create a handle to make your program shorter, since all temporary variables are stored inside the program. Lets say we want to create a table of 128 words. Then we should use the following code: move.l #$0100,-(a7) ; 128 words = 256 byte = $0100 bytes jsr tios::HeapAlloc ; Call the rom function add.l #$04,a7 ; Restore the stack pointer move.w d0,table_handle ; Store the handle number in a var tios::DEREF d0,a0 ; Get the address to the handle move.l a0,table_addr ; And store the address in another var . . . table_handle dc.w 0 ; Here is the handle number for the table table_addr dc.l 0 ; And here is that address As you see, you should push the size onto the stack, and you must push it as a longword, else it won't work. The routine will return the handle number in D0.W, which you MUST store in a variable, because you'll need it when you later must destroy the handle. Now, when you got the handle number, you also need to know WHERE in the RAM the handle is, ie at which address. To get this address, you should use a macro in tios.h (needs to be included) called tios::DEREF. It's a simple macro, it just looks up a table in the system memory (better explained in HANDLES.TXT or \system.txt, section IV.1). Anyway, the macro has two parameters, the first is the given handle number and the second is which address register the address should be returned into. The address is, of course, an even number so we can address it with (An). The address should also be saved in a variable. You could of course use the macro whenever you want the address, but although it's a simple macro (3 rows) it's a bit slower and takes some more bytes, so it's better to define a longword and store the address there, because the address won't change during the program execution. Before you exit the program, you MUST destroy all created handles. I don't know what will happen if you don't, memory corruption and calculator crashes at least. Here is how to do that: move.w table_handle(PC),-(a7) jsr tios::HeapFree lea 2(a7),a7 When creating handles, you should also check if the operation succeded. It won't succed if you're out of handles (don't worry about that...) or if you're out of memory (this you MUST check, else CRASH)! For example, when you're working with grayscale graphics, you need almost 4k free! If the user don't know that, he/she won't be happy. The HeapAlloc routine will return D0.L=0 if the operation didn't succed, so it's easy to check. Then you should exit the program without trying to destroy the handle (since you didn't get any handle number). ----------------------- 1.10 Common mistakes ----------------------- "If anything can go wrong, it will. If it can't, it will anyway." You get some strange errors messages at the top of the screen when running your program? Calculator crashes? And you don't know what's wrong? Cool down, that's very common :-) But finding the errors in the source can be hard, VERY hard, sometimes. There are some common mistakes though if you've programmed other assembly languages (like me) before. Those are * You MUST put a # before an immediate value!! There are exceptions, for example LEA 10(A7),A7, but when using MOVE, CMP and other instructions it can be a fatal error. For example, MOVE.B $10,D0 means move the byte stored at address $10 to D0! This can cause protected memory error or something like that. Always check so you've not missed any #! * The first operand is the source, the second the destination! This is also a very usual error in the beginning. We should not speak of what it could do, but instead of getting things from imporant places in the RAM (like, the interrupt vector), you store some trash there! Nooot good! Check all instructions with two operands! Most instructions have two operands. * Since the upper part of the register will remain there until you move another longword to the register, it may cause big problems! For example, when getting a byte from somewhere in the memory, and then you want to multiplicate it, you MUST be sure that the upper part of the byte is cleared out, since you don't specify any operation size (.B, .W or .L) when multiplicating. To do this, use either CLR or EXT (see 2.0 Instruction summary). * All tables and other variables you'll address with (An) must be at an even address. If you have defined one byte before the table, it will cause the table to start at an odd address, which will probably cause in a calculator crash. To avoid this, move all such tables/arrays at the beginning of the variable section (I think, or at least it seems so, all instructions have the size 2, 4, 6...). You may also use the "even" assembly directive which allign the table on a longword boundary. * Be sure you've destroyed all handles when exiting. If you still don't find the error, you should use db92 to pinpoint the error. Be aware that when programming an assembly language, most of the time (>50%) you're sitting and correcting bugs... ----------------------------------------- 2.0 INSTRUCTION SUMMARY ----------------------------------------- ------------------------------------ 2.01 How the summary is structured ------------------------------------ The instructions are divided into 8 classes depending on how they work and what they do. Here is a short description of all instructions the Motorola 68000 will understand: DATA MOVEMENT ------------- These instructions moves data from one place to another. EXG (EXchanGe) The contents of two registers will be exchanged. LEA (Load Effective Address) Calculates a memory location and store it in an address register. LINK Allocates a stackframe. MOVE Copies the contents in one register/memory location to another register or another memory location. MOVEA (MOVE Address) Same as MOVE except that the destination is an address- register. MOVEM (MOVE Multiple) transfers many registers to or from the memory. MOVEP (MOVE Peripheral) transfers data to or from an 8 bits peripheralunit. MOVEQ (MOVE Quick) puts a constant in a dataregister. PEA (Push Effective Address) calculates a memory address and stores it on the stack. SWAP Swaps the word in a dataregister. UNLK (UNLinK) removes a stackframe INTEGERARITHMETIC ----------------- These instructions perform simple twocomplement operations on binary data. ADD, ADDA, ADDI, ADDQ, ADDX Different kinds of addition. CLR Clears an operand. CMP, CMPA, CMPI, CMPM Compares two operands DVIS, DIVU Integer division, signed and unsigned. EXT Makes a sign extension, byte to word or word to longword MULS, MULU Multiplication, signed and unsigned. NEG, NEGX Twocomplements a number. SUB, SUBA, SUBI, SUBQ, SUBQ Different kinds of subtraction. TAS (Test And Set) used to synchronise more than one processor TST Compares an operand with 0. LOGICAL OPERATIONS ------------------ These operations perform logical operations on binary numbers. A logical operation is either "true" (1) or "false" (0). AND, ANDI Logical AND on two binary integers OR, ORI Logical OR EOR, EORI Exclusive OR (XOR) NOT Returns the operans onecomplement (0 -> 1, 1 -> 0) SHIFT AND ROTATION ------------------ These instructions perform arithmetical and logical shift and rotation with or without extra carry. ASL, ASR Arithmetic shift left resp right. LSL, LSR Locigal shift left resp right. ROL, ROR Rotation left resp right without extra carry. ROXL, ROXR Rotation left resp right through extra carry. BITMANIPULATION --------------- These instructions affect single bits in a byte. All instructions test the bit before affecting it. BTST Tests a bit BSET Tests a bit, then set it (1) BCLR Tests a bit, then reset it (0) BCHG Tests a bit, then invert it (0 -> 1, 1 -> 0) BCD-INSTRUCTIONS ---------------- These operations work with BCD-numbers. ABCD BCD addition SBCD BCD subtraction NBCD BCD negate PROGRAMCONTROL -------------- These instructions contain branches, jumps, calls. Bcc A group of 15 instruction that branches depending on the flags. DBcc 15 instructions that perform loops. Scc 16 instructions that will set/reset a byte depending on the flags. BSR, JSR Subroutine calls. RTS Return from a subroutine. JMP Absolute jumps. RTR Pops the PC and the flags from the stacks. SYSTEMCONTROL ------------- These instructions changes the state of the 68000 processor. They require that the supervisor bit (in the system byte) is set. I haven't used these, so don't blame me if I've written something wrong. MOVE USP Gives a program in supervisor mode access to the stackpointer in user mode RESET Restores the peripheral units. RTE Returns from an interrupt. STOP Stops the execution until a given interrupt occurs. CHK, TRAPV Finds fatal program errors. TRAP 16 instructions that give a program in usermode the possibility to call antoher program in supervisor mode. OTHER INSTRUCTIONS ------------------ ILLEGAL Causes an interrupt (Illegal instruction) NOP Does nothing :-) (No OPeration) All instructions are divided into 5 parts: a description, addressmethods, datalength, flags and syntax. The addressmethods shows which operands are allowed. Often you can't combine different addressmethods with each other, but that is explained in the description. In datalength you can see if you can use longwords, words or maybe only a byte. Some instructions can use words if you choose one addressmethod, but you can use byte or longword if you choose another addressmethod. The flags part shows how the flags are set after the instruction has been executed. It can either be one of the following symbols S - Standard setting - see below 0 - The flag is always cleared 1 - The flag is always set undef - undefined, you can't be sure how the flag will be set U - unaffected, the flag hasn't changed during the instruction. or a longer description, if it's a bit special. The Z, N and V flags are often set the same way (standard setting). The Z flag is usually set if the destination register (or the result) is zero, else the flag is cleared. The N flag is usually set if the most significant bit of the result is set (the most significant bit is the sign bit and shows if the number is negative or positive). The V flag is often set if the instruction resulted in an overflow (there weren't enough bits to store the answer in). Many instructions don't change any flags, then you'll see "Unaffected" directly after FLAGS. The syntax shows how the instructions can look like. Often, letters (x and y) is shown where there should be numbers between 0-7. ------------------------------------ 2.02 Data movement ------------------------------------ *** EXG *** Lets two data- or addressregister swap contents with each other. You can swap a dataregister with an addressregister. ADDRESSMETHODS: Dn, An DATALENGTH: Longword FLAGS: Unaffected SYNTAX: EXG Rx,Ry *** LEA *** Loads an effetive address into an addressregister. LEA is often used when writing code that must be independent of the position in the memory (which all Fargo programs are). It's often used with the addressmethods x(PC) or x(PC,xr.s). LEA also adds a constant to an addressregister without changing the flags, and/or also an index with x(An,xr.s). ADDRESSMETHODS: (An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) DATALENGTH: Longword FLAGS: Unaffected SYNTAX: LEA <ea>,An *** LINK *** The instruction LINK creates a stackframe, a temporary allocated memory on the stack. The instruction is often used in highlevel languages when allocating memory for local variables in procedurs. When the procedure is desactivated, the variables disappear which saves memory. LINK has two operands. The first is an addressregister and the second is a twocomplement value, which is the size of the frame (often negative since the stack grows backwards). When the instruction is executed, the address- register is pushed onto the stack and the newly updated A7 is copied to the addressregister. The immediate value is added to the Stack register ( A7). The local memory is accessed with negative shifting from the addressregister. That way you can use local variables without bothering about other data that is pushed or popped from the stack provided you keep in the range you specified while calling the LINK opcode. The instruction UNLK removes the stackframe and restores the stackpointer. ADDRESSMETHODS: None DATALENGTH: - FLAGS: Unaffected SYNTAX: LINK An,#<shifting> Note that the use of LINK allows Reentrant programs. *** MOVE *** The instruction MOVE copies a byte, a word or a longword from an effective address to another. The flags are set according to the data moved. ADDRESSMETHODS (for the source): Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x ADDRESSMETHODS (for the dest.>: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l The addressmethod An can only be used when the datalength is word or longword. FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: MOVE <ea>,<ea> The instruction MOVEA moves data to an addressregister (An is as you may have noticed missing in addressmethods for the destination). Most assemblers choose MOVEA is you have an addressregister as an operand. *** MOVE to CCR *** If you specify CCR as the destination, the lower byte in a word is copied to the flagregister (CCR). The flags doesn't change according to the result, ie if you clear the flagregister the Z flag won't be set. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: Set according to the bits of the byte you moved to CCR. SYNTAX: MOVE <ea>,CCR *** MOVE to SR *** If you specify SR as the destination, a word is moved to the statusregister (ie the systembyte and the flagbyte). The instruction requires that bit 13 (the supervisor bit) is set in the beginning of the instructions. The instruction can be used to change the T-bit (trace), S-bit (supervisor), the interruptmask and the flags. Note that with fargo II, to get in supervisor mode, you should use the trap #1 . If you only want to change the flags, you should use MOVE to CCR instead, which also works if you are in user mode. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: Set according to the lower bits in the word you moved to SR. SYNTAX: MOVE <ea>,SR *** MOVE from SR *** This instruction copies the whole statusregister to an operand with the size of a word. It requires that you are in supervisor mode (the S-bit in SR must be set). ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Word FLAGS: Unaffected SYNTAX: MOVE SR,<ea> *** MOVEA *** The instruction MOVEA copies an operand given by an effective address to an addressregister. Only words and longwords are used, and all 32 bits in the destination are affected (sign extension if word). ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Longword FLAGS: Unaffected SYNTAX: MOVEA <ea>,An Most assemblers choose MOVEA if you use MOVE with an addressregister as destination *** MOVEM *** The instruction MOVEM (MOVE Multiple) makes it possible to fast transfer a group of registers to or from the memory. The operation can only work with word or longword. When you move words to register, the words are signextended so all 32 bits are affected. The instruction is most often used to push registers on the stack, so you can temporary use those register to other things and later restore the original values. Very useful in the beginning and the end of subroutines that change a lot of registers. ADDRESSMETHODS: (An), -(An), x(An), x(An,xr.s), x.w, x.l (register to memory) ADDRESSMETHODS: (An), (An)+, x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) (memory to register) DATALENGTH: Word, longword FLAGS: Unaffected SYNTAX: MOVEM <registerlist>,<ea> MOVEM <ea>,<registerlist> The registerlist is a serie of registers separated by a slash ("/"). You can also use one or many intervalls (shown with a "-"). For example, D0-D5/A0-A2 means the registers D0, D1, D2, D3, D4, D5, A0, A1, A2. *** MOVEP *** The instruction MOVEP (MOVE Peripheral) transfers a word or a longword in a dataregister to or from every second memoryaddress. The MSB in the dataregister transfers to or from the address x(An), - the only addressmethod - the next byte to or from x+2(An) and so on. If the first address was odd all MOVEP transfers will use the lowest byte in the 68000:s databus. Even addresses use the highest byte. This instruction is mainly used when you use 8 bits databuses connected with the 16 bits databus in the 68k. Since this is never done on the TI-92 (am I right here??) this instruction won't be used that way. ADDRESSMETHODS: x(An) DATALENGTH: Word, longword FLAGS: Unaffected SYNTAX: MOVEP Dn,x(An) MOVEP x(An),Dn *** MOVEQ *** The instruction MOVEQ (MOVE Quick) is used to put small immediate data in a dataregister. The instruction is two bytes long and can handle constanst in the range -128 and +127 (decimal). All 32 bits in the register are affected If you used MOVE.L the instruction would take 6 bytes. DATALENGTH: Longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: MOVEQ #<data>,Dn Many assemblers automatically change a MOVE to a MOVEQ if possible. *** PEA *** The instruction PEA calculates an effective address and pushes it on the stack. The address is always a longword. ADDRESSMETHODS: (An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) DATALENGTH: Longword FLAGS: Unaffected SYNTAX: PEA <ea> *** SWAP *** The instruction SWAP swaps the upper word with the lower word in a dataregister (bit 31-16 is exchanged with bit 15-0). ADDRESSMETHODS: Dn DATALENGTH: Word FLAGS: X - U N - Same as bit 31 in the dataregister Z - Set if all 32 bits are zero, else cleared C - 0 V - 0 SYNTAX: SWAP Dn *** UNLK *** The instruction UNLK (UNLinK) removes a stackframe that earlier was set by the instruction LINK (see LINK). It works like this: The given addressregister (usually the framepointer... :) ) is stored in the stackpointer. Then the original state of the frame pointer is restored by getting the first longword on the stack. This is the opposite of what LINK does. UNLK works correctly no matter what has been pushed or popped on the stack between the instructions LINK and UNLNK but it requires that you popped your variables from the frame pointer or updated the frame pointer to its initial value ( by adding the size of the variables to the frame pointer for exemple ) ADDRESSMETHODS: - DATALENGTH: - FLAGS: Unaffected SYNTAX: UNLK An ------------------------------------ 2.03 Integerarithmetic ------------------------------------ *** ADD *** Adds two binary operands and stores the result in the destination operand. Two different methods allowed: 1. Add an effective address to a dataregister. 2. Add a dataregister to an effective address. ADDRESSMETHODS: 1) Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x ADDRESSMETHODS: 2) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword When using an addressregister as destination, byte is not allowed. FLAGS: X - Set if carry from the most significant bit, else cleared. N - S Z - S C - Same as X V - S SYNTAX: ADD Dn,<ea> ADD <ea>,Dn *** ADDA *** Binary addition to an addressregister. To make it possible to mix addressoperations with dataoperations, this instruction won't affect any flags. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x The effective address must be the source. DATALENGTH: Word, longword ADDA affects always all 32 bits in the destination addressregister. FLAGS: Unaffected SYTNAX: ADDA <ea>,An *** ADDI *** Adds a constant to an effective address. The source operand must be immediate. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - Set if carry from the most significant bit, else cleared. N - S Z - S C - Same as X V - S SYNTAX: ADDI #x,<ea> Most assemblers automatically choose ADDI if the source operand to an ADD instruction is immediate. *** ADDQ *** This instruction adds a three bit immediate value to an effective address. The instruction is very quick and much shorter than the usual ADD. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword When using an addressregister as destination, byte is not allowed. FLAGS: X - Set if carry from the most significant bit, else cleared. N - S Z - S C - Same as X V - S No flags are affected if the destination operand is an addressregister. SYNTAX: ADDQ #<data>,<ea> #<data> is a constant between 1 and 8. *** ADDX *** The instruction ADDX (ADD eXtended) works as ADD but the X flag is also added. This makes it possible to add big numbers stored in many bytes. The instruction has two methods: 1. Add a dataregister to a dataregister. 2. Add a memory location to another memory location. You must use -(An) on both operands then. ADDRESSMETHODS: Dn, -(An) DATALENGTH: Byte, word, longword FLAGS: X - Set if carry from the most significant bit, else cleared. N - S Z - S C - Same as X V - S The Z flags works in another way now, making it possible to check if a big number (much bigger than 32 bits) is zero. You must set the zero flag before making the addition though, shorter than comparing a register with itself. SYNTAX: ADDX Dy,Dx ADDX -(Ay),-(Ax) *** CLR *** This instruction (CLeaR) clears an operand specified with an effective address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - 0 Z - 1 C - 0 V - 0 SYTNAX: CLR <ea> *** CMP *** CMP (CoMPare) compares a dataregister with an effective address. The flags are affected the same way as if the effective address was substracted from the dataregister. None of the operands are changed. Often used with the Bcc instruction. An example: CMP D0,D1 BGT X1 The program will branch to X1 if D1 is greater than D0, else the program will continue. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Byte, word, longword Byte can't be used when comparing to an addressregister. FLAGS: X - U N - S Z - S C - Set if a borrow was needed when subtracting, else cleared V - S SYNTAX: CMP <ea>,Dn There are four CMP instructions, CMP, CMPA, CMPI and CMPM. The compiler often choose the right instruction, so you can write CMP all the time if you want. *** CMPA *** CMPA (CoMPare Address) compares an addressregister with an effective address. The flags are affected the same way as if the effective address was subtracted from the dataregister. None of the operands are changed. Often used with the Bcc instruction. An example: CMP A0,A1 BGT X1 The program will branch to X1 if A1 is greater than A0, else the program will continue. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word, longword FLAGS: X - U N - S Z - S C - Set if a borrow was needed when substracting, else cleared V - S SYNTAX: CMPA <ea>,An There are four CMP instructions, CMP, CMPA, CMPI and CMPM. The compiler often chooses the right instruction, so you can write CMP all the time if you want. *** CMPI *** CMPI (CoMPare Immediate) compares an immediate value with an effective address The flags are affected the same way as if the effective address was substracted from the dataregister. None of the operands are changed. Often used with the Bcc instruction. An example: CMP #<data>,D0 BGT X1 The program will branch to X1 if D0 is greater than the immediate value. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - Set if a borrow was needed when subtracting, else cleared V - S SYNTAX: CMPI <ea>,Dn There are four CMP instructions, CMP, CMPA, CMPI and CMPM. The compiler often chooses the right instruction, so you can write CMP all the time if you want. *** CMPM *** CMPM (CoMPare Memory) compares two memory locations with each other with after-increament. The flags are affected the same way as if the source was subtracted from the destination. None of the operands are changed. ADDRESSMETHODS: (An)+ DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - Set if a borrow was needed when subtracting, else cleared V - S SYNTAX: CMPM (Ay)+,(Ax)+ There are four CMP instructions, CMP, CMPA, CMPI and CMPM. The compiler often chooses the right instruction, so you can write CMP all the time if you want. *** DIVS *** DIVide Signed. The instruction divides a signed (twocomplement) dataregister with an operand specified as an effective address. The dataregister is 32 bits and the effective address is a word. The result is stored in the lower 16 bits of the dataregister and the remainder in the upper 16 bits. Two errors can arise with DIVS: 1. If you try to divide with 0 an interrupt will occur. 2. If the result doesn't fit in 16 bits the dataregister will remain unchanged and the V-flag will be set (overflows). ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: X - U N - S, undef if overflow Z - S, undef if overflow C - 0 V - S SYNTAX: DIVS <ea>,Dn *** DIVU *** DIVide Unsigned. The instruction divides an unsigned dataregister with an operand specified as an effective address. The dataregister is 32 bits and the effective address is a word. The result is stored in the lowest 16 bits of the dataregister and the remainder in the upper 16 bits. Two errors can arise with DIVU: 1. If you try to divide with 0 an interrupt will occur. 2. If the result doesn't fit in 16 bits the dataregister will remain unchanged and the V-flag will be set (overflows). ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: X - U N - S, undef if overflow Z - S, undef if overflow C - 0 V - S SYNTAX: DIVS <ea>,Dn *** EXT *** The instruction EXT (Sign EXTend) makes a sign extension, byte to a word or a word to a longword. If you extend a byte to a word, bit 7 is copied to bit 15-8. If you extend a word to a longword, bit 15 is copied to bit 31-16. ADDRESSMETHODS: Dn DATALENGTH: Word, Longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: EXT Dn *** MULS *** The instruction MULS (MULtiply Signed) multiplies a 16 bits operand in a dataregister with a 16 bits operand specified as an effective address. The result is a 32 bits value that is stored in the dataregister. All operands are signed (twocomplement). ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: MULS <ea>,Dn *** MULU *** The instruction MULS (MULtiply Unsigned) multiplies a 16 bits operand in a dataregister with a 16 bits operand specified as an effective address. The result is a 32 bits value that is stored in the dataregister. All operands are unsigned. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: MULU <ea>,Dn *** NEG *** The instruction NEG returns the twocomplement of an operand given as an effective address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - Clear if the result is zero, else set N - S Z - S C - Same as X V - S SYNTAX: NEG <ea> *** NEGX *** The instruction NEGX (NEGate with eXtend) returns the twocomplement from a binary number with multiprecision. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - Set if loan, else cleared N - S Z - Set if the result is not zero, else unaffected C - Same as X V - S SYNTAX: NEGX <ea> *** SUB *** Subtracts two binary operands and stores the result in the destination operand. Two different methods allowed: 1. Subtract an effective address from a dataregister. 2. Subtract a dataregister from an effective address. ADDRESSMETHODS: 1) Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x ADDRESSMETHODS: 2) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword When using an addressregister as destination, byte is not allowed. FLAGS: X - Set if a loan was required from the most significant bit, else 0. N - S Z - S C - Same as X V - S SYNTAX: SUB Dn,<ea> SUB <ea>,Dn When an addressregister is the destination, you use SUBA. Many assemblers will automatically choose SUBA if you write SUB with an addressregister as destination. *** SUBA *** Binary subtraction from an addressregister. To make it possible to mix addressoperations with dataoperations, this instruction won't affect any flags. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x The effective address must be the source. DATALENGTH: Word, longword SUBA affects always all 32 bits in the destination addressregister. FLAGS: Unaffected SYTNAX: SUBA <ea>,An *** SUBI *** Subtracts a constant from an effective address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - Set if a loan was required from the most significant bit, else 0. N - S Z - S C - Same as X V - S SYNTAX: SUBI #x,<ea> Most assemblers automatically choose SUBI if the source operand to an SUB instruction is a constant. *** SUBQ *** This instruction subtracts a three bit constant from an effective address. The instruction is very quick and much shorter than the usual SUB. ADDRESSMETHODS: Dn, An, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword When using an addressregister as destination, byte is not allowed. FLAGS: X - Set if a loan was required from the most significant bit, else 0. N - S Z - S C - Same as X V - S No flags are affected if the destination operand is an addressregister. SYNTAX: SUBQ #<data>,<ea> #<data> is a constant between 1 and 8. *** SUBX *** The instruction SUBX (SUBtract eXtended) works as SUB but the X flag is also subtracted. This makes it possible to add big numbers stored in many bytes (multiprecision). The instruction have two methods: 1. Subtract a dataregister from a dataregister. 2. Subtract a memory location to another memory location. You must use -(An) on both operands then. ADDRESSMETHODS: Dn, -(An) DATALENGTH: Byte, word, longword FLAGS: X - Set if a loan was required from the most significant bit, else 0. N - S Z - Cleared if the result is not zero, else unaffected C - Same as X V - S The Z flags works in another way now, making it possible to check if a big number (much bigger than 32 bits) is zero. You must set the zero flag before making the addition though, shorter than comparing a register with itself. SYNTAX: SUBX Dy,Dx SUBX -(Ay),-(Ax) *** TAS *** The instruction TAS (Test And Set) examines a byte specified with an effective address. The most significant bit in the byte is set. The N- and Z-flags are set according to the bytes value before the operation. The instruction reads, modifies and sets and can't be interrupted. The instruction is used to synchronize if two or more MPU use the same memory area. Since TAS can't be interrupted a MPU can mark a location in the memory to be "busy" before another processor can examine it. If the operation was interuptable, two processor could examine the same byte at the same time, and both processor would think the byte was free to use, which would lead to an error. TAS guaranties that one processor wins and the other loses. TAS is used by high level langages to implement "Semaphors" ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l You can use TAS with a dataregister, but then it has nothing to do with syncronization. DATALENGTH: Byte FLAGS: X - U N - S (before the operation) Z - S (before the operation) C - 0 V - 0 SYNTAX: TAS <ea> *** TST *** The instruction TST examines an operand specified as an effective address, and finds out if it's zero or negative. The flags are set depending on the result. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: TST <ea> ------------------------------------ 2.04 Logical operations ------------------------------------ *** AND *** The instruction AND performs the logical operation "AND", bit for bit. 1. The source is and effective address, the destination is a dataregister. 2. The source is the dataregister and the destination is the effective address. ADDRESSMETHODS: 1) Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x 2) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: AND <ea>,Dn AND Dn,<ea> *** ANDI *** Same as AND except that the source is an immediate value. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, SR, CCR DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: ANDI #<data>,<ea> *** EOR *** EOR performs an exclusive OR between a dataregister and the memory. EOR gives the result (binary) 1 if one, and only one, of the operators are 1 (compare with OR). The dataregister must be the source and the effective address the destination. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENTGH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: EOR Dn,<ea> *** EORI *** EORI performs an exclusive OR between an immediate value and an effective address. EORI gives the result (binary) 1 if one, and only one, of the operators are 1 (compare with OR). The effective address must be the destination of course. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, SR, CCR Operations that uses the statusregister (SR) and the flagregister (CCR) can only work with word and byte. If you try to change SR you must be in supervisor mode, else an interrupt occurs. ( use trap #1 to change the mode ) DATALENTGH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 If the statusregister or the flagregister is the destination, the flags are set the same way as any other effective address. If an instruction clears all bits in the flagregister, the Z flag won't be set (as it should since the result was 0). SYNTAX: EORI #<data>,<ea> *** NOT *** Returns the onecomplement of an operand specified with an effective address. The onecomplement is the same as changing all bits in the operand. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: NOT <ea> *** OR *** The instruction OR performs the logical operation "OR", bit for bit. There are two ways to do this: 1. The source is an effective address, the destination is a dataregister. 2. The source is the dataregister and the destination is the effective address ADDRESSMETHODS: 1) Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s), #x 2) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: OR <ea>,Dn OR Dn,<ea> *** ORI *** Same as OR except that the source is an immediate value. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, SR, CCR When using SR, the S-bit must be set. DATALENGTH: Byte, word, longword FLAGS: X - U N - S Z - S C - 0 V - 0 SYNTAX: ORI #<data>,<ea> ------------------------------------ 2.05 Shift and rotation ------------------------------------ *** ASL *** Performs an arithmetic shift to the right on a dataregister or a memory location. Has three possibilites: 1. Shift a dataregister to the left. Number of steps is stored in another dataregister. You can shift 1-8 bits this way. 2. Shift a dataregister to the left. Number of steps is an immediate value. 3. Shift a word in the memory one bit to the left. ADDRESSMETHODS: 3) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - The last bit that was sent out of the operand. Unaffected if number of steps is 0. N - S Z - S C - Same as X V - Set if the most significant bit was changed during the operation. Cleared else. SYNTAX: ASL Dx,Dy ASL #<data>,Dy ASL <ea> *** ASR *** Performs an arithmetic shift to the right on a dataregister or a memory location. Has three possibilites: 1. Shift a dataregister to the right. Number of steps is stored in another dataregister. You can shift 1-8 bits this way. 2. Shift a dataregister to the right. Number of steps is an immediate value. 3. Shift a word in the memory one bit to the right. ADDRESSMETHODS: 3) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - The last bit that was sent out of the operand. Unaffected if number of steps is 0. N - S Z - S C - Same as X V - Set if the most significant bit was changed during the operation. Cleared else. SYNTAX: ASR Dx,Dy ASR #<data>,Dy ASR <ea> *** LSL *** Performs a logical shift to the left on a dataregister or a memory location. Has three possibilites: 1. Shift a dataregister to the left. Number of steps is stored in another dataregister. You can shift 1-8 bits this way. 2. Shift a dataregister to the left. Number of steps is an immediate value. 3. Shift a word in the memory one bit to the left. ADDRESSMETHODS: 3) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - The last bit that was sent out of the operand. Unaffected if number of steps is 0. N - S Z - S C - Same as X V - Set if the most significant bit was changed during the operation. Cleared else. SYNTAX: LSL Dx,Dy LSL #<data>,Dy LSL <ea> *** LSR *** Performs a logical shift to the right on a dataregister or a memory location. Has three possibilites: 1. Shift a dataregister to the right. Number of steps is stored in another dataregister. You can shift 1-8 bits this way. 2. Shift a dataregister to the right. Number of steps is an immediate value. 3. Shift a word in the memory one bit to the right. ADDRESSMETHODS: 3) (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, word, longword FLAGS: X - The last bit that was sent out of the operand. Unaffected if number of steps is 0. N - S Z - S C - Same as X V - Set if the most significant bit was changed during the operation. Cleared else. SYNTAX: LSR Dx,Dy LSR #<data>,Dy LSR <ea> *** ROL *** The instruction ROL rotates a dataregister or a memory operand to the left. There are three ways to do this: 1. Rotate a dataregister to the left. Number of steps is a constant. 2. Rotate a dataregister to the left. Number of steps is stored in another dataregister. You can rotate 1-8 bits this way. 3. Rotate e a word in the memory one bit to the left. The rotation is done without an extra bit (ie a 8, 16 or 32 bit rotation). The bit that is rotated from the highest position to the lowest will also be send to the carry flag. C <-- OPERAND <-- |____________| ADDRESSMETHODS: (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l (only when rotating a word in the memory) DATALENGTH: Byte, word, longword When rotating in the memory, you can only use word. FLAGS: X - U N - S Z - S C - Equal to the bit that was last moved from the operand. If steps is zero, the flag is cleared. V - 0 SYNTAX: ROL #<steps>,Dy ROL Dx,Dy ROL <ea> *** ROR *** The instruction ROR rotates a dataregister or a memory operand to the right. There are three ways to do this: 1. Rotate a dataregister to the right. Number of steps is a constant. 2. Rotate a dataregister to the right. Number of steps is stored in another dataregister. You can rotate 1-8 bits this way. 3. Rotate a word in the memory one bit to the right. The rotation is done without an extra bit (ie a 8, 16 or 32 bit rotation). The bit that is rotated from the lowest position to the highest will also be send to the carry flag. --> OPERAND --> C |____________| ADDRESSMETHODS: (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l (only when rotating a word in the memory) DATALENGTH: Byte, word, longword When rotating in the memory, you can only use word. FLAGS: X - U N - S Z - S C - Equal to the bit that was last moved from the operand. If steps is zero, the flag is cleared. V - 0 SYNTAX: ROR #<steps>,Dy ROR Dx,Dy ROR <ea> *** ROXL *** The instruction ROXL (ROtate Left with eXtend) rotates a dataregister or a memory operand to the left. There are three ways to do this: 1. Rotate a dataregister to the left. Number of steps is a constant. 2. Rotate a dataregister to the left. Number of steps is stored in another dataregister. You can rotate 1-8 bits this way. 3. Rotate e a word in the memory one bit to the left. The rotation is done with an extra bit (ie a 9, 17 or 33 bit rotation). The most significant bit is rotated to the carry flag and to the extra flag. The bit at the extra flag will be rotated to the least significant bit in the operand. C <-- OPERAND <-- | | |-> X ->-----| ADDRESSMETHODS: (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l (only when rotating a word in the memory) DATALENGTH: Byte, word, longword When rotating in the memory, you can only use word. FLAGS: X - The last bit that was rotated from the operand. Unaffected if rotation steps was zero. N - S Z - S C - Same as X V - 0 SYNTAX: ROXL #<steps>,Dy ROXL Dx,Dy ROXL <ea> *** ROXR *** The instruction ROXR (ROtate Left with eXtend) rotates a dataregister or a memory operand to the right. There are three ways to do this: 1. Rotate a dataregister to the right. Number of steps is a constant. 2. Rotate a dataregister to the right. Number of steps is stored in another dataregister. You can rotate 1-8 bits this way. 3. Rotate a word in the memory one bit to the right. The rotation is done with an extra bit (ie a 9, 17 or 33 bit rotation). The least significant bit is rotated to the carry flag and to the extra flag. The bit at the extra flag will be rotated to the most significant bit in the operand. -- OPERAND ----> C | | |----<- X <--| ADDRESSMETHODS: (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l (only when rotating a word in the memory) DATALENGTH: Byte, word, longword When rotating in the memory, you can only use word. FLAGS: X - The last bit that was rotated from the operand. Unaffected if rotation steps was zero. N - S Z - S C - Same as X V - 0 SYNTAX: ROXR #<steps>,Dy ROXR Dx,Dy ROXR <ea> ------------------------------------ 2.06 Bitmanipulation ------------------------------------ *** BCHG *** This instruction will change a bit in an operand specified by an effective address. The Z-flag (the only flag affected) will be set as the bit was before the change! The bit number is stored in a dataregister or is an immediate address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, longword FLAGS: Z - Set if the bit was 0 before the change, else cleared. All other flags unaffected. SYNTAX: BCHG Dn,<ea> BCHG #<data>,<ea> *** BCLR *** This instruction will clear a bit in an operand specified by an effective address. The Z-flag (the only flag affected) will be set as the bit was before the change! The bit number is stored in a dataregister or is an immediate address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, longword FLAGS: Z - Set if the bit was 0 before the operation, else cleared. All other flags unaffected. SYNTAX: BCLR Dn,<ea> BCLR #<data>,<ea> *** BSET *** This instruction will set a bit in an operand specified by an effective address. The Z-flag (the only flag affected) will be set as the bit was before the change! The bit number is stored in a dataregister or is an immediate address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte, longword FLAGS: Z - Set if the bit was 0 before the change, else cleared. All other flags unaffected. SYNTAX: BSET Dn,<ea> BSET #<data>,<ea> *** BTST *** This instruction will test a bit in an operand specified by an effective address. The Z-flag (the only flag affected) will be set as the bit was before the change! The bit number is stored in a dataregister or is an immediate address. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) DATALENGTH: Byte, longword FLAGS: Z - Set if the bit was 0 before the change, else cleared. All other flags unaffected. SYNTAX: BTST Dn,<ea> BTST #<data>,<ea> ------------------------------------ 2.07 BCD-instructions ------------------------------------ *** ABCD *** Adds two byte in BCD-form (Binary Coded Decimal). The destination operand is replaced with the sum of the source and the destination operand. ADDRESSMETHODS: Dn, -(An) Only two methods allowed: 1. Add dataregister to another dataregister (Dn to Dn) 2. Add memory to memory. This is used when you add BCD numbers stored in many bytes. You must start at the highest address (the least significant byte in the BCD number) and go upwards. The X flag is set if the addition results in a carry, which is added to the next byte. DATALENGTH: Byte FLAGS: X - Set if carry from the most significant BCD digit. N - undef Z - Cleared if the result is NOT zero. Unaffected else. C - Same as X V - undef SYNTAX: ABCD Dx,Dy ABCD -(Ax),-(Ay) *** NBCD *** The instruction NBCD (Negate BCD) negates a BCD-number. The method used is tencomplement. The tencomplement to 01 is 99 (1+99=10000), to 26 is 74 (26+74=100) and so on. The X flag is added to the tencomplement which is the loan from the previous BCD calculation (multiprecision). A normal serie of BCD instructions starts with the X flag cleared and the Z flag set. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte FLAGS: X - Set if a loan was required when subtracting, else cleared N - undef Z - Cleared if the result was 0, else unaffected C - Same as X V - undef SYNTAX: NBCD <ea> *** SBCD *** The instruction SBCD (Subtract BCD with extend) subtracts two bytes in BCD-form. The difference (destination - source - X flag) is stored in the destination register. ADDRESSMETHODS: Dn, -(An) There are two ways to use the instruction: 1. Subtract a dataregister from a dataregister (addressmethod Dn). The lower byte in the source register is subtracted from the lower byte in the destination register, where the answer is stored. 2. Subtract memory from memory. This way, you can subtract big numbers stored in many bytes. Since you only can use -(An) you must start on the highest byte (the least significant digits in the BCD number) and work down. If there is a carry, the X bit is set, which will be subtracted from the next byte. DATALENGTH: Byte FLAGS: X - Set if a loan was required from the most significant BCD digit. N - undef Z - Cleared if the result was 0, else unaffected C - Same as X V - undef The Z flag is cleared if the result is not 0. This way, you can see if the answer after a serie of subtractions is zero or not. First, you have to set the Z flag (easiest done by comparing a register with itself). Then do the subtractions, and if the Z flag is set, the BCD number is zero. SYNTAX: SBCD Dx,Dy SBCD -(Ax),-(Ay) ------------------------------------ 2.08 Programcontrol ------------------------------------ *** Bcc *** This instruction will cause a branch in the program if certain flags are set. There are fifteen ways of checking the flags. Each of them have a symbol on two letters which will replace the "cc" in "Bcc". BCC Branch Carry Clear - Branch if the C-flag is 0. BCS Branch Carry Set - Branch if the C-flag is 1. BEQ Branch EQual - Branch if the Z-flag is 1. BNE Branch Not Equal - Branch if the Z-flag is 0. BGE Branch Greater or Equal - Branch if N and V are equal. BGT Branch Greater Than - Branch if N and V are equal and Z=0. BHI Branch HIgher than - Branch if both C and Z are 0. BLE Branch Less or Equal - Branch if Z=1 or if N and V are different. BLS Branch Lower or Same - Branch if C=1 or Z=1. BLT Branch Less Than - Branch if N and V are different. BMI Branch MInus - Branch if N=1. BPL Branch PLus - Branch if N=0. BVC Branch V Clear - Branch if V=0 BVS Branch V Set - Branch if V=1. BRA BRanch Always Some conditions are pretty similiar. BGE, BGT, BLE, BLT should be used when using signed integers and BHI and BLS when using unsigned integers. ADDRESSMETHODS: No special. You specify a label, which the compiler will change to a relative address, byte or word depening on how far you will jump. DATALENGTH: Byte, word FLAGS: Unaffected SYNTAX: Bcc.B <label> Bcc.W <label> You don't have to (you shouldn't) add .B or .W, the compiler will choose the best syntax. *** BSR *** Branch to SubRoutine. This instruction will push the address to the next instruction on the stack, then branch to the label specified in the instruction (a relative address). Used to call subroutines in your own programs. ADDRESSMETHODS: No real addressmethod. The label is a relative address. DATALENGTH: Byte, word FLAGS: Unaffected SYNTAX: BSR.B <label> BSR.W <label> You shouldn't add .B or .W, the compiler will choose the best syntax. *** DBcc *** DBcc is an instruction that quits loops. The instruction is very similiar to Bcc (same conditions are used, see above for the different conditions) except that the first operand is a dataregister that will be decreased with one until is reached -1, then the loop stops. The loop can also quit if the flags are set correctly (specified with the condition). You often use DBRA (Never quit) that will quit the loop when the dataregister has reached -1. If you want the loop the be looped 10 times, you should set a dataregister to 9 (since it ends at -1, not 0). ADDRESSMETHODS: No real addressmethod. DATALENGTH: Word FLAGS: Unaffected SYNTAX: DBcc Dn,<label> *** JMP *** JMP (JuMP) is used to move the program control to an effective address. It really works as MOVE.L xxx,PC, since it changes the program counter to an effective address (calculated). ADDRESSMETHODS: (An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) DATALENGTH: - FLAGS: Unaffected SYNTAX: JMP <ea> Note that JMP should never be used in a fargo program. *** JSR *** JSR (Jump to SubRoutine) works as JMP except that before the jump is made, the address to the instruction after JSR is pushed to the stack, so you can return with the instruction RTS. ADDRESSMETHODS: (An), x(An), x(An,xr.s), x.w, x.l, x(PC), x(PC,xr.s) DATALENGTH: - FLAGS: Unaffected SYNTAX: JSR <ea> *** RTR *** The instruction RTR (ReTurn and Restore) pops the flags and the program- counter from the stack. First a word is popped from the stack and the lower byte of that word is stored in the flagregister. The higher byte is ignored. Then a longword is popped into the programcounter. The stackpointer will be increased with six. ADDRESSMETHODS: None DATALENGTH: - FLAGS: The flags is set according to the first word that is popped from the stack. SYNTAX: RTR *** RTS *** The instruction RTS (ReTurn from Subroutine) does the opposite to the instructions BSR (Branch to SubRoutine) and JSR (Jump to SubRoutine). The longword on top of the stack is stored in the programcounter. The instruction is used when ending a subroutine. The execution will return to the instruction that follows the last JSR- or BSR- instruction. ADDRESSMETHODS: None DATALENGTH: - FLAGS: Unaffected SYNTAX: RTS *** Scc *** This instruction sets all bits in a byte (effective address) if a condition is true, else all bits are cleared. The conditions can be CC,CS,EQ,GE,GT,HI,LE,LS,LT,MI,NE,PL,VC,VS (for these, check the Bcc instruction for what they mean), SF (always false), ST (always true). ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x.l DATALENGTH: Byte FLAGS: Unaffected SYNTAX: Scc <ea> ------------------------------------ 2.09 Systemcontrol ------------------------------------ *** CHK *** CHecK register against bounds. Is often used in high level languages to check if variables are in range. The lowest 16 bits of a dataregister are compared with an effective address. If the result is less than 0 (if bit 15 is 1) or greater than the limit, the result will be a CHK-interrupt. ADDRESSMETHODS: Dn, (An), (An)+, -(An), x(An), x(An,xr.s), x.w, x(PC), x(PC,xr.s), #x DATALENGTH: Word FLAGS: X - U N - Set if the dataregister is less than zero, cleared if the dataregister is greater than the higher limit. Else undefined. Z - U C - U V - U SYNTAX: CHK <ea>,Dn *** MOVE USP *** The instruction MOVE USP transfer the usermode stackpointer to or from an addressregister. The instruction requiers that you are in supervisor mode. Since the 68k processor has two stackpointers, this instruction is necessary when a supervisor program wants to access the usermode stackpointer. ADDRESSMETHODS: An DATALENGTH: Longword FLAGS: Unaffected SYNTAX: MOVE USP,An MOVE An,USP *** RESET *** This instruction restores all external units. ADDRESSMETHODS: None DATALENGTH: - FLAGS: Unaffected SYNTAX: RESET *** RTE *** The instruction RTE (ReTurn from Exception) is used to put data in both the statusregister and the program counter with the same instruction. This instruction is necessary when an operatingsystem that is working in supervisor mode must leave the control to an application in usermode. The new contents in the statusregister and the programcounter is popped from the stack. First, a word is popped into the statusregister, then a longword is popped into the programcounter. Thus, the stackpointer is increased with six. This instructions requires that the S bit is set in the statusregister when the instruction is executed. Since the statusregister is changed after the instruction, it's possible that the processor be in usermode then. ADDRESSMETHODS: None DATALENGTH: - FLAGS: All flags is popped from the stack. SYNTAX: RTE *** STOP *** This instruction enables interrupts and waits for an interrupt. The instruction requires that the processor works in supervisor mode. An immediate 16 bit data value is stored in the statusregister. Bit 13 in that data must be set (that will be the S bit after the instruction). Otherwise, an interrupt will occur since you're in usermode (you must be in supervisor mode before and after this instruction). ADDRESSMETHODS: - DATALENGTH: - FLAGS: The flags will be bit 0-5 in the immediate data SYTNAX: STOP #<data> *** TRAP *** The instruction TRAP pushes the programcounter and the statusregister on the supervisor stack, switches to supervisor mode and the programcounter is given a new value taken from one of the sixteen vectors, given by a four bit datavalue. The instruction is used in applications to call a supervisor program (an OS for example) without knowing exactly where in the memory the OS is. ADDRESSMETHODS: - DATALENGTH: - FLAGS: Unaffected SYNTAX: TRAP #<vector> The vector used by TRAP is stored at $80+4*vector (absolute address). *** TRAPV *** The instruction TRAPV examines if an overflow has arised. If it hasn't (the V flag is 0), nothing happens. If it has, the programcounter and the statusregister is pushed on the stack, and the programcounter will be given a new address, stored at the absolute address $1C. The MPU is set to supervisor mode. The instruction is often used by highlevel languages. ADDRESSMETHODS: - DATALENGTH: - FLAGS: Unaffected SYNTAX: TRAPV ------------------------------------ 2.10 Other instructions ------------------------------------ *** ILLEGAL *** This isn't a real instruction 68k instruction. It will cause an interrupt (Illegal instruction) on all 68k CPUs. Often used as breakpoint in debuggers. ADDRESSMETHODS: None DATALENGTH: - FLAGS: Unaffected SYNTAX: ILLEGAL *** NOP *** The instruction NOP (No OPeration) makes nothing during one instruction. Nothing happens except that the program counter is set to the next instruction. NOP is used to make small delays (VERY small delays, to let hardware parts to act) and to create empty space in the program which can later be used for changes. ADDRESSMETHODS: None DATALENGTH: - FLAGS: Unaffected SYNTAX: NOP ----------------------------------------- 3.0 PROGRAMMING STUFF ----------------------------------------- ----------------------- 3.01 THE VIDEO MEMORY ----------------------- Maybe the most important piece of information a game programmer wants: How do I do graphics!?!? Well, if you know how the video memory works on the TI-85, it'll be easy. It's stored the same way! 8 pixels/byte (since it's just black&white graphics, one pixel=one bit) and the top left corner is at tios::main_lcd. Then it goes from left to right, up to down. Each row takes 30 bytes (30*8=240) and since it's 128 rows the video memory is $0F00 bytes long, ie it ends at tios::main_lcd+$F00. You should be able to handle the flib functions for putting pixels and such. For grayscale graphics, there are examples for it. Looking in the source for gray4lib.asm should be enough though. It works just as if there were two video memories, ie two bit planes. This is cleanly explained in lesson_3.txt. ---------------------- 3.02 Highscores etc ---------------------- It's very simple to create highscores in games or other things that you want to be saved until you run the game/program the next time. Since Fargo programs doesn't have a checksum, you can change in the source (which you actually do all the time when changing the "temporary" variables) how much you like. This means it's easy to do a highscore table or so, just make a highscore label and store the highscore there. Just don't reset it when starting the game. However, you can' t create a handle for a highscore table (that would be good if the highscore had >10 entries where you could enter your name and so, since that will take at least 100 bytes) since when you destroy a handle, the content will be destroyed (or overwritten later), and you should NOT exit the program without destroying all created handles, see 1.10 Handles. See lesson_2.txt section II to get a clean routine for highscores... -------------- 3.03 Arrays -------------- Arrays, vectors, matrices, lookuptables. Call it what you want. It's the same thing. In highlevel languages it's very easy to use arrays, just but brackets after the variable and put an index inbetween. It's not that simple in assembly, but still simple when you know how to do. Let's say we want to have an one dimensional array with 100 elements, all words. At the end of the program in the variable declaration we declare it like this: table ds.w 100 There we have it, 200 bytes allocated for storaged. It's VERY important that the offset to the table is an even address, else the calc will crash when we try to read/store in the array. To be sure it is, put the table before all variables that are defined as bytes. ( or use the "even" assembler directive ) To store a word at a certain place in the table, here is the simpliest way: (d0 is the word to store, d1 is where in the array, 0-99) lea table(PC),a0 ; Now A0 points to the table lsl.w #1,d1 ; Since we use words, we must multiplicate the index ; with 2 (each element is two bytes) move.w d0,0(a0,d1) ; Store the word d0 at 0+a0+d1. Done! Simple. If you want to read a word from the array, just swap the two operands in the last move instructions. If we have a two dimensional array, it's a bit harder (not much). Let's say the array is 50x50, each element is a word. The table is declared as table ds.w 50*50 And here's the routine to store the word d0 at row d1, col d2: lea table(PC),a0 ; Let A0 point at the table mulu #100,d1 ; One row is 100 bytes (50 words). We must use ; MULU to get the right offset. If each row was ; 128 bytes, we could have shifted instead (faster). adda d1,a0 ; Add the rowoffset to the pointer lsl.w #1,d2 ; Multiplicate the column with 2 (same reason as above) move.w d0,0(a0,d2) ; And store the word When you use these routines, you MUST BE SURE that the upper word of D1 and D2 is cleared, else it won't work! To be sure about that, use EXT.L or load the row and col with MOVE.L (or MOVEQ if possible) to erase the upper word. ----------------------------------------- 4.0 MISCELLANEOUS ----------------------------------------- ----------------------- 4.01 Version history ----------------------- 0.5 - Section 2.0 Instruction Summary not finished (24 nov 96) 0.6 - All instructions to D finished (27 nov 96) 1.0 - Finally done! Instruction Summary finished, created 3.00 Programming Stuff and added some more sections, library & arrays (10 dec 96) 1.1 - Corrected to match fargo II file listing, corrected some errors (link and unlink mostly ). Added some stuff to the system byte section. (29 june 98) Corrections made by mathieu lacage <hmlacage@aol.com>. This guide is now distributed and designed to be distributed with "tutorial.zip" available at ticalc.org. 1.1.1- Corrected many spelling errors and small errors, added a few things Corrections made by mathieu lacage <hmlacage@aol.com>. (20 july 98) ----------------- 4.02 Greetings ----------------- * David Ellsworth, Rob Taylor & Dan Eble - FARGO!!! incl. sources, documents and more * Jonas Minnberg - Fantastic Fargo programs! * All Fargo coders - We're not many, but this guide will hopefully bring more people into the light... * Steve Williams - For the GREAT book, "Programming the 68000" (I've learned almost all 68k programming from it) * The ppl at #fargo + #calc-ti (EFnet) - For supporting me in writing this guide and chatting (and the telephone bill...) Many more to come... ------------------------- 4.03 How to contact me ------------------------- The quickest, the best, the safest (???) way: Email......: yarin@acc.umu.se The slowest way (but good when sending money :-) ): Snailmail..: Jimmy Mardell Plommonvagen 21 904 36 Umea SWEDEN The coolest way, and most "live" way: IRC........: Yarin EFnet: #ti (ex irc.gate.net) IRCnet: #synthare (ex irc.stealth.net) The sportiest (surfing) way: WEB........: http://www.acc.umu.se/~yarin/ ----------- 68000 GUIDE FOR FARGO PROGRAMMERS ------- LAST UPDATE: 98-07-20-
Back to Programming