Category:68000 Assembly: Difference between revisions

Content added Content deleted
(redid the section and cut out a bunch of fluff)
Line 112: Line 112:
MOVEA.W #$7FFF,A3 ;A3 = #$00007FFF</lang>
MOVEA.W #$7FFF,A3 ;A3 = #$00007FFF</lang>


==The Vector Table==
==Traps==
Certain memory locations have special meanings to the 68000 CPU. Most of these are used for system calls or exception handling. Sixteen of them can be accessed with the <code>TRAP #?</code> command, which takes an immediate constant ? ranging from 0 to 15 as an operand. This effectively equates to a <code>JSR</code> to the address stored at <code>$00000080 + (4*?)</code>. For the most part, what each <code>TRAP</code> does depends on the system's firmware and so you'll need to read the documentation. This feature is not usable on every system; on the Sega Genesis for example, they all become null pointers regardless of what you actually put there.
Traps are the equivalent of <code>INT</code> in [[8086 Assembly]]/[[x86 Assembly]] or <code>SVC</code>/<code>SWI</code> in [[ARM Assembly]]. The 68000 only supports 17 of these in total. A trap is very similar to a subroutine call, except it can also occur automatically if certain conditions are met, such as dividing by zero. This saves the trouble of having to do the following:


The 68000's vector table contains more than this, but to keep things simple there will be a few things omitted.
<lang 68000devpac>;this is an example of how NOT to do it!
* Address $00000000 contains the initial value of the stack pointer. You never need to <code>MOVE.L (0),SP</code>, the CPU does this automatically.

* Address $00000004 contains the program start. The CPU will JMP to the address stored in $00000004 (note that it doesn't jump TO $00000004, it loads the 4 bytes stored there and makes that the new program counter value.)
CMP.L #0,D0
* The next 8 longwords are the hardware traps. Each represents the memory location of a function or procedure meant for a hardware error (the 68000 doesn't have segmentation faults but it's a similar concept. Among them include handlers for division by zero, signed overflow, etc.)
BEQ DivideByZeroError
* Interrupt requests and user-defined traps go here as well.
DIVU D0,D1
RTS
DivideByZeroError:
; put your error handler here</lang>

This is completely unnecessary, as the <code>DIVU</code> and <code>DIVS</code> use a trap to handle a divide by zero automatically. If the CPU would attempt to divide by zero, the processor automatically calls the relevant trap (Trap 5 in this case). The return address and processor flags are saved, and execution jumps to the address specified in the trap list (a table of pre-defined memory addresses, stored at $000080 and going up. The standard 16 traps are stored here, with a 17th stored at $00001C.

===Hardware-Defined Traps===
Certain traps have specific meanings as defined by the 68000 itself:
* Trap 4 occurs if the <code>ILLEGAL</code> command is executed. This is similar to <code>BRK</code> on [[6502 Assembly]]. If you're programming on a system or emulator with no built-in debugger, it's a handy way of seeing if execution is arriving at a certain point. If Trap 4 is pointed to a system reset or a hexdump routine you created, you'll know in an instant if the code before it is bugged. This (admittedly contrived) example will show the basic concept.
<lang 68000devpac>;trying to see if this routine works properly
TestRoutine:
CMP.L D0,D1 ;programmer expects these to always be equal
BEQ weShouldGoHere
ILLEGAL
weShouldGoHere:

;rest of routine which depends on D0 and D1 being equal.</lang>

* Trap 5 occurs if a <code>DIVU</code> or <code>DIVS</code> instruction attempts to divide by zero.

* Trap 6 detects if a value is out of bounds for a desired range. The <code>CHK</code> command takes a numeral, data register, or memory address (either explicit or pointed to by an address register) and compares it to a data register containing the upper bound. If the first operand is greater than the upper bound, trap 6 will be called. Otherwise execution will resume as normal.
<lang 68000devpac>MOVE.L #500,D3 ;our maximum range
CHK D0,D3 ;if D0 > D3 then Trap 6 will occur.</lang>

* The 17th trap is called the "Overflow Trap" and can only be called with the <code>TRAPV</code> instruction, which calls it <i>if the overflow flag is set.</i>

===Kernel-Defined Traps===
Depending on the hardware, certain traps are built-in to perform certain tasks, such as reading a keyboard or mouse, or are user-defined. To create your own trap routine, you'll need to first write the routine, then store its address in the corresponding trap number. Trap 0 is stored at $000080, Trap 1 at $000084, and so on. The overflow trap is stored at address $00001C. If your assembler supports labels, you can simply specify the label at the trap data block.

<lang 68000devpac>org $000080
DC.L Trap0
DC.L Trap1
DC.L Trap2
DC.L Trap3
DC.L IllegalInstructionHandler
DC.L DivideByZeroHandler</lang>
etc.

Keep in mind that this table is very tightly packed. There is no room for any code here- just the memory addresses where your routines are stored. To my knowledge, the CPU can't "remember" what trap was called after doing so. Therefore you can't just point all traps to the same error handler, you'll need a slightly different one for each.


==Alignment==
==Alignment==