-
-
[下载]68000的指令集(英文版的)
-
发表于: 2009-5-15 11:44 11150
-
赞赏
|
|
---|---|
|
The Guide to 68000 Assembly Language
From Atari Forum Wiki Jump to: navigation, 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......: [email]yarin@acc.umu.se[/email] 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- |
|
历史
摩托罗拉公司于1976年启动MACSS项目(Motorola Advanced Computer System on Silicon,摩托罗拉硅晶高级计算机系统),打算开发一款与以前产品完全不兼容的全新微处理器。根据计划,新CPU应该是对当时摩托罗拉主流8位CPU6800的一个高端互补产品,而不会考虑两者间的兼容性。不过,当68000设计出来后,它还是被保留了一个可兼容6800外设的总线协议模式,并且专门有8位数据总线的产品被生产出来。当然,设计人员还是更在意于其向后兼容性,这为68000确立在32位CPU领域的领先优势奠定了基础。比如,68000使用32位寄存器和内部总线,尽管其本身的结构很少直接操作长字。小型计算机诸如PDP-11和VAX—二者采用了类似的微编码—对68000的设计有深刻的影响。 在20世纪70年代中期,8位微处理器生产商纷纷竞争导入下一代16位CPU。国家半导体在1973年到1975年间首先开发出了IMP-16和PACE,但其速度并不理想。英特尔公司于1977年推出8086,迅速受到欢迎。此时,为确保竞争上的领先,摩托罗拉认识到其MACSS项目必须跳过16位系统,而直接推出16/32位混合型CPU。到1979年,摩托罗拉68000,即MC68000,才告姗姗来迟。由于比8086晚两年,其晶体管数目更多,并因其易用性得到了好评。 最初的MC68000使用3.5微米HMOS技术(即高性能N通道金属氧化物半导体,CMOS的前身)制造。1979年发布了工程样品,次年产品型面世,速度有4、6、8、10兆赫兹多种。最快的16.67MHz版本到80年代末才面市。 MC68000在早期得到了很多高端产品的青睐。在升阳公司的Sun workstation等多种Unix工作站中,MC68000一度占统治地位。市场领先的其他一些计算机,包括Amiga(阿米加)、Atari ST(雅达利ST)、Apple Lisa (苹果Lisa)和 Macintosh(麦金托什),以及第一代激光打印机,如苹果公司的LaserWriter,都使用MC68000。1982年,摩托罗拉进一步更新了MC68000的指令集以支持虚拟内存,并使其能够满足由Popek和Goldberg于1974年提出的虚拟化标准。 为支持低成本系统和使用较少内存的应用,摩托罗拉于1982年还推出了面向8位外部数据总线的MC68008。1982年以后,摩托罗拉开始把更多的注意力投向68020和88000。 其他制造商 由日立公司设计,1985年两公司联合推出了使用CMOS技术的68HC000。68HC000的速度有8到20MHz多个版本。尽管除了使用CMOS电路,68HC000与基于HMOS的MC68000完全一致,但正是因此其能耗得到大幅下降。MC68000在25摄氏度环境下能耗大约为1.35瓦,而8MHz的68HC000则为0.13瓦,较高频率的版本则能耗也相应提高(HMOS技术则不同:其在CPU空闲时仍会耗电,所以功耗与频率基本无关)。后于1990年摩托罗拉又推出了MC68008的CMOS版本,并将其改进为可兼容8/16位两种总线模式。 其他HMOS版68000的生产商包括:Mostek、Rockwell(洛克维尔)、Signetics、Thomson(汤姆逊)和东芝。东芝也生产CMOS版68000(TMP68HC000)。 应用 68000首先被应用于许多高端产品中,如多用户微型计算机WICAT 150及阿尔法微系统的一些早期计算机等。单用户工作站如惠普公司的HP 9000/200、太阳微系统的Sun-1;图形终端如DEC的VAXstation 100和Silicon Graphics的IRIS 1000均使用68000。许多Unix系统也开始使用68K系列CPU。 在80年代中期,68000又成为首先应用于个人/家庭计算机的CPU。先后有苹果的Apple Lisa与麦金托什、Amiga的海军准将(Commodore)、雅达利ST及夏普的Sharp X68000采用68000。 68000最主要的成功在于控制器领域。早在1981年Imagen公司就把68000用作其激光打印机Imprint-10外部控制器的CPU。惠普于1984年发布的第一款LaserJet打印机亦使用一片8MHz的68000作为内置控制器。类似的基于68000的整合控制器也被广泛用在其他多款打印机中。到90年代,68000仍在许多低端打印机中被使用。 除了传统商业和家用计算应用,68000在工业控制系统中也取得了巨大成功。Allen-Bradley、德州仪器及西门子公司生产的可编程逻辑控制器(PLC)即使用68000。一般来说,这类工业系统的用户更重视产品的可用性,而不是向家庭用户一样过于在意其是否过时。所以,仍有许多使用68000的系统,在被安装二十多年后,在生产一线提供着持续而可靠的服务。 随着技术的进步,68000在计算机单机市场渐被淘汰,但其应用仍活跃于消费和嵌入式领域。游戏机制造商使用68000作为许多街机和家用游戏机的处理器。雅达利在1983年推出的Food Fight便是使用68000的代表街机游戏。世嘉的System 16、卡普空的CPS-1和CPS-2以及SNK的Neo Geo也都使用68000。到了90年代,尽管街机游戏开始使用更加强大的CPU,68000仍被用作声音控制器。 在80年代末到90年代初,一些游戏机厂商使用68000作为家用游戏平台的中央处理器。这包括世嘉的Mega Drive(MD)和Neo Geo家用版。后来,68000还在世嘉的32位CPU游戏机Sega Saturn中用作声音控制器。 基于68000的683XX系列微控制器则广泛应用于许多应用领域中,包括网络和电话设备、电视机机顶盒、实验室与医疗设备等。思科、3com等公司曾在他们生产的通讯设备中使用MC68302及其衍生产品。Palm公司曾使用DragonBall系列CPU(68K系列的后续)作为其PDA的处理器,直到基于RISC的ARM处理器开始统治PDA市场。此外,AlphaSmart公司在其便携式文字处理器中使用DragonBall。 德州仪器在一些高端图形计算器,如TI-89和TI-92中,使用68000。这些设备早期使用以68EC000为内核的专门化微控制器,后来则改用封装好的MC68SEC000。 作为微控制器内核 在被纯32位CPU取代后,68000开始被用作许多微控制器的内核。1989年,摩托罗拉发布了MC68302通讯处理器。两年后又推出独立处理器芯片MC68EC000。1996年的MC68SEC000便使用了这款芯片。 1996年摩托罗拉停产HMOS MC68000和MC68008,但其分离出来的半导体部门,飞思卡尔公司,仍在生产MC68HC000等68K家族系列产品。68000架构的后代,680x0、CPU32以及Coldfire系列,也仍在生产。 架构 地址总线 68000地址总线为24位,故支持16MB最大物理内存。在使用32位长字对地址进行存储和计算时,高位的一个字节会被自动忽略。这种设计使得其具备相当的向前兼容性,可以直接运行为后续的纯32位CPU编写的软件。也因此,根据现今的定义,68000应称得上是一款32位CPU。摩托罗拉使用32位内部总线的目的在于希望能够在68000上编写可以被将来的后续产品直接使用的软件,而相关指令不必作位数上的调整。 然而,编程人员还是有可能编写出无法与后续产品兼容的软件。倘若这种24位软件丢弃高位字节,或将该字节用作寻址以外的目的,它就有可能在32位68K系列CPU上运行失败。这就是说,对于希望支持向前兼容的软件,必须始终使用32位长字寻址,并且将最高位字节置零。 内部寄存器 68000包含8个32位通用寄存器(D0-D7),及8个32位地址寄存器(A0-A7)。最后一个地址寄存器,即A7,也作为标准栈指针使用,在编程中可以使用SP作为同义词。这组寄存器在规模上恰到好处:既可以对中断快速反应(只有十多个寄存器要保存),也有足够的寄存器来进行快速计算。 尽管两种寄存器并存有时会比较麻烦,但在实践中并非难于掌握。据称,这还使得CPU的设计者们可以通过对地址寄存器组使用辅助计算单元,从而实现较高程度的并行机制。 存储内容高位字节在前(Big Endian模式),与x86相反。 状态寄存器 68000比较、算术和逻辑操作会在状态寄存器SR的低端字节(又称CCR)中设置一些标志位,以供之后的条件跳转使用。这些标志位是:得零(Z)、进位(C)、溢出(V)、扩展(X)、负数(N)。尽管许多时候值是相同的,X与C依然是两个不同的标志位。这就允许算术、逻辑和移位操作的多余位与逻辑控制/连接造成的进位区别开。 指令集 68000的指令集基本上是正交的。大部分指令被划分成操作和地址模式两部分,并且大部分地址模式都对几乎全部指令可用。这种近似正交性在编程人员当中毁誉参半。 编程者会清楚地发现,他/她所书写的指令可能被汇编成几种不同的二进制操作码。这实际上是一种不错的妥协:一方面,在便利性上与纯粹的正交指令系统相仿;一方面,CPU设计者可以有更多的自由来设计操作码表。 对于一台16位时代的机器而言,由56条指令构成的最小指令集仍显巨大。此外,许多指令和寻址模式会在指令后边加入地址/寻址模式码。 许多设计者确信MC68000体系结构应基于成本考量使用较精简的指令码,特别是使用编译器自动生成时。这种认识为对其设计上的成功加分不少,并且使之成为一种经久不衰的体系结构。这一信条持续地保证了整个系列指令集的设计优势,直到ARM体系结构引入同样精简的Thumb指令集。 特权级 68K系列CPU包含两个特权级。超级用户(supervisor)模式和用户(user)模式。后者相比于前者只是禁用了中断级控制。中断总会使CPU进入超级用户态。超级用户标志位存储于状态寄存器SR中,并对用户可见。 超级用户态下会有一个分离的栈指针用于中断处理。 中断 68000可以识别7级中断,从级别1到级别7。7级中断严格按优先级排列,一个高级中断总是能嵌套于一个低级中断。可以使用专门的特权指令在SR内设置最小中断级别,从而屏蔽所有小于此级别的中断。但如果设置为0,表示不接受中断。级别7不可被屏蔽,即NMI。级别1总是可以被高级中断打断。 硬件中断源将中断信号以编码方式通过三条输入线传送给CPU。一般会使用专门的中断控制器来汇总各外部设备,并将中断信号按级编码与CPU硬连。中断控制器可以使用简单如74LS148优先级编码器,复杂如MC68901多功能外设(支持可编程中断控制、通用异步收发装置、定时器及并行输入输出等)等各种电路模块。 在内存低1K位置存储中断向量表,共支持256条中断向量。部分中断向量有特殊用途:向量1为初始栈地址;向量2为初始代码地址;向量3到15用于错误报告,包括总线错误、寻址错误、非法指令、除零异常、优先权违反等。从向量24起处理真正的中断,包括伪中断、针对级别1到级别7的默认处理向量,多达15个自陷向量,以及用户定义向量。 由于必须在重启时保证向量1和2的内容有效,所以68000系统通常包含在地址底部使用非易失性存储器(如ROM)来存储一些例程向量和启动代码。但是,一个通用计算机的操作系统会期望在运行时改变向量内容。解决办法是将ROM内的向量指向RAM的分支表,或使用早期在8位CPU中广泛使用的换页技术(Bank switching)。 由于包含一条非特权指令MOVE from SR,允许一般用户只读地访问某些特权状态,68000并未完全满足波佩克与戈德堡虚拟化需求。该需求指出了为构建某一CPU之等价虚拟机而对CPU提出的若干要求。 MC68000对虚拟内存缺乏方便的支持。一款支持虚拟内存的CPU应能在内存访问失败后自陷并恢复。不过,68000确实提供了一个总线错误异常来使CPU自陷,尽管还不能保存足够的状态信息以便于异常处理之后的恢复。为此,一些Unix工作站通过使用两块68000来解决虚拟内存问题。两块CPU的运行时钟存在相位差。当第一块遇到寻址异常后,特殊的硬件会设法向第二块发出中断,以防止其也访问错误地址。中断例程在第二块CPU上处理完内存换页后,会按之前的状态重启第一块CPU,从而再次使两CPU同步。 不过,以上这些问题在MC68010被彻底解决。在MC68010中,总线异常和地址错误均会使大量状态信息压入系统栈,以便于之后的恢复。MOVE from SR也被修正为特权指令。原本用于访问SR低端字节的代码可由新指令MOVE from CCR取代。 指令集细节 标准寻址模式 68000提供多种寻址模式,并统称为有效寻址(EA)。在CPU参考手册中,经常会有诸如MOVE <ea>,<ea>这样的表记方式。这表示在目的操作数和源操作数上可分别使用一种(但通常不是全部)有效寻址。 寄存器直接寻址 数据寄存器直接寻址,如D0。 地址寄存器直接寻址,如A0。通常不使用A7。 寄存器间接寻址 简单间址,如(A0)。先取得A0所存储的地址,再在内存中该地址处取出数据。 自增间址,如(A0)+。只能用于源操作数域。先取得A0所存储的地址,再在内存中该地址处取出数据,然后A0的内容(地址)自增一定长度(因指令后缀而定)。这个操作其实相当于x86中的出栈指令POP(注意栈的方向和内存方向相反)。在这里,A0被用作一个用户自定义的栈指针,与系统使用的A7/A7'不同。 自减间址,如-(A0)。只能用于目操作数域。先取得A0所存储的地址,再在内存中该地址处存入数据,然后A0的内容(地址)自减一定长度(因指令后缀而定)。这个操作其实相当于x86中的入栈指令PUSH。 偏移间址,如2AFF(A0)。前边的偏移量为16位。实际取得的地址为(A0)+2AFF。 加索引的偏移间址,如E3(A0, D0)。前边的偏移量为8位。实际取得的地址为(A0)+(D0)+E3。 程序计数器位移 长位移,如2AFF(PC)。前边的偏移量为16位。PC变为(PC)+2AFF。 短位移,如E3(PC, D0)。前边的偏移量为8位。PC变为(PC)+(D0)+E3。 绝对内存寻址 直接使用内存地址值,如$4000,表示目标地址在内存地址为4000处。注意$表示后边所跟数字为16进制,%表示2进制。 在实际编程中,可以使用代码中的标号来充当内存地址值。汇编器会自动翻译为数字地址。 注意不应与立即数混淆。使用立即数时应在值前再加一个#。$4000表示16进制地址4000;#$4000表示16进制立即数4000;4000表示10进制地址4000;#4000表示10进制立即数4000。 指令后缀 大部分指令都有表示操作长度的后缀:.B、.W或.L,分别表示这一操作在字节(8比特)上、字(16比特)上或长字(32比特)上进行。运算的过程和结果都会受到后缀的影响。在运算过程中,只有属于操作长度范围的部分才会参与运算。比方说,执行MOVE.B D2,D1会把D1的最低一字节复制到D2的最低一字节处,而两者的其余字节均不受影响。对于CCR,各标志位的值会由操作长度的最高有效位决定。如果某次ADD.B使得结果的第7Bit位为1,则CCR的N位会置1;如果某次ADD.L使得结果的第7Bit位为1,并且第15Bit不为1,则CCR的N位不会置1。在后一种情况下,CCR的N位只受第15Bit,即一个字的最高有效位影响。另一个例子是在自增/自减寻址中,自增/自减的长度因操作后缀而异。如果操作为MOVE.B,则自增/自减1;W为2;L为4。 常用指令 大部分68000的指令都是二元的。目的操作数在前,源操作数在后。 移动指令 MOVE:标准移动指令。另有一些其它移动指令供选择:MOVEA(移动到地址寄存器An,不会影响CCR,但后缀不可为.B)、MOVEQ(移动一个8位数到目标寄存器,因为可将数值直接写入指令故称快速移动)、MOVEM(移动寄存器组到指定堆栈,多用于中断/子程序处理的第一步)等。 LEA:移动一个地址值到目标寄存器。LEA $2000,A0表示将A0的值设为16进制的2000。应注意此时不加立即数标志#。 LINK/ULNK:建立/取消堆栈帧。这个指令用于翻译高级语言的函数调用。LINK An, #-x可将An作为函数栈指针,并SP所指向的用户栈内取得x大小的空间存储局部变量,之后SP仍将指向栈顶,而An指向栈顶+x的位置。x的值在编译时由编译器自动算出。 算数指令:ADD(加)、SUB(减)、MULU /MULS(无/有符号乘)、DIVU/DIVS(无/有符号除)、NEG (取补)、及CMP(类似于减但只会影响标志位而不改变操作数)。算数指令也多成组提供。对于ADD,还有ADDA(加地址,不会影响标志位)、ADDI(加立即数)、ADDQ(快速加,加数不大于8以便于直接放在操作码中,比x86的INC指令书写麻烦但功能更强)、ADDX(影响进位符,用于大数运算)等。 BCD码算数指令:ABCD(加)和SBCD(减)。 移位指令 逻辑移位(移位后用0补充):LSL(左移)、LSR(右移) 算数移位(移位后用原来最高/最低有效位补充):ASL(左移)、ASR(右移) 循环移位(移位后用所移动位补充):ROL(左移)、ROR(右移) 循环扩展移位(移位至CCR的X位,同时用之前的X位补充):ROXL(左移)、ROXR(右移) 位操作指令:BSET(置1)、BCLR (清0)和BTST (如果测试位在改变前为0则将CCR的Z设为1)。 多任务处理:TAS(测试并置位)。这个指令用于实现信号灯等同步机制。 流程控制:JMP(无责任跳转)、 JSR (跳转至子例程)、BSR (按相对地址跳转至子例程,多用于跳转至用户定义例程)、RTS (从子例程返回)、RTE (从异常/中断中返回)、 TRAP(自陷,即软中断)、CHK(检查地址是否越界,如是则触发异常)。 JMP指令只是纯粹跳转,不会将下一条指令地址压栈;JSR和BSR会将下一条指令压栈。 RTS将栈指针指向内容弹出给PC。 条件测试并跳转:Bcc系列指令。cc定义了所测试的条件位。常用的如: BNE:不等于时跳转。 BEQ:等于时跳转。 BRA:无条件跳转。 来自“http://zh.wikipedia.org/wiki/%E6%91%A9%E6%89%98%E7%BD%97%E6%8B%89_68000” |
|
支持一下。
在学校图书馆见到过这款CPU的资料,确实很有历史了。 90年代初的时候,世嘉游戏机还是游戏机的高端产品了。当时有款游戏叫“战斧”的,很喜欢。呵呵。 |
|
我也好喜欢SEGA MD5游戏
好佩服当时的游戏开发人员,在受限的平台上做出性能如此优秀的游戏。SONIC系列真是帅呆了 |
|
看到楼主提供的资料,想起了《浪潮之巅》中提到的复杂指令集和精简指令集之争,很有意思,推荐大家看看。
|
|
CISC和RISC架构各有优势,目前的趋势似乎是两者都在借鉴对方的一些思想来弥补自己的不足。
比如Intel的安腾系列处理器。其中很多设计思想都是从RISC架构中吸取的。 |
他的文章
- [下载]68000的指令集(英文版的) 11151
- [分享]有趣的批处理 10460
- [推荐]Palm TREO600 模拟器 TREO600 5505
谁下载
nig
小楼
Jan
CoffeeCat
liuStar
larblue
fileviewer
jackzxy
pcasa
woodyboy
pumo
zhenke
bozer
onbadday
lykonglong
postlhg
kxzkxz
jykotw
KuGong
evileric
xiaofancn
QYPGAD
driverox
panboduo
luzj
Flowing
dmarble
guahn
ygyl
pojie甲醚
KooJiSung
加百力
xiaoyuegu
幽灵阿呆
世嘉汉化
xujintian
创世主
yorkfeng
wswm
EastGeek
星河传奇
louisning
kejiyy
mylio
yexong
lizugeng
gout
sunhaibo
梦在南方
谁下载
nig
小楼
Jan
CoffeeCat
liuStar
larblue
fileviewer
jackzxy
woodyboy
pumo
zhenke
bozer
onbadday
lykonglong
postlhg
kxzkxz
jykotw
KuGong
evileric
xiaofancn
QYPGAD
driverox
panboduo
luzj
Flowing
dmarble
guahn
ygyl
pojie甲醚
KooJiSung
加百力
xiaoyuegu
幽灵阿呆
世嘉汉化
xujintian
创世主
yorkfeng
wswm
EastGeek
星河传奇
louisning
kejiyy
mylio
yexong
lizugeng
gout
sunhaibo
梦在南方
谁下载
nig
小楼
Jan
CoffeeCat
liuStar
larblue
fileviewer
jackzxy
pcasa
woodyboy
pumo
zhenke
bozer
onbadday
lykonglong
postlhg
kxzkxz
jykotw
KuGong
evileric
xiaofancn
QYPGAD
driverox
panboduo
luzj
Flowing
dmarble
guahn
ygyl
pojie甲醚
KooJiSung
加百力
xiaoyuegu
幽灵阿呆
世嘉汉化
xujintian
yorkfeng
wswm
EastGeek
星河传奇
louisning
kejiyy
mylio
yexong
lizugeng
gout
sunhaibo
梦在南方
谁下载
nig
小楼
okpj
Jan
CoffeeCat
liuStar
crdchen
fileviewer
jackzxy
pcasa
woodyboy
pumo
linxue
zhenke
ccgto
bozer
onbadday
loudy
lykonglong
postlhg
cffjfz
kxzkxz
qgmdyw
jykotw
KuGong
evileric
xiaofancn
QYPGAD
driverox
panboduo
luzj
Flowing
dmarble
guahn
ygyl
pojie甲醚
KooJiSung
加百力
破冰坚
xiaoyuegu
幽灵阿呆
世嘉汉化
xujintian
yorkfeng
wswm
风扫地
EastGeek
hendyj
zplusplus
星河传奇
louisning
kejiyy
fiiive
mylio
yexong
fonghotin
lizugeng
dshdio
gout
sunhaibo
梦在南方
wx_Sambty
看原图
赞赏
雪币:
留言: