Category:68000 Assembly

From Rosetta Code
Revision as of 10:53, 10 September 2021 by Puppydrum64 (talk | contribs)
This page is a stub. It needs more information! You can help Rosetta Code by filling it in!
Language
68000 Assembly
This programming language may be used to instruct a computer to perform a task.
See Also:


Listed below are all of the tasks on Rosetta Code which have been solved using 68000 Assembly.

68000 assembly is the assembly language used for the Motorola 68000, or commonly known as the 68K. It should not be confused with the 6800 (which predates it). The Motorola 68000 is a big-endian processor with full 32-bit capabilities (despite most systems that use it being considered 16-bit.) It was used in many computers such as the Amiga or the Canon Cat, as well as game consoles such as the Sega Genesis and Neo Geo.


Architecture Overview

Data Registers

There are eight 32-bit data registers on the 68000, numbered D0-D7. As the name implies, these are designed to hold data. Similar to the ARM processor, each one is identical in terms of which commands it can use. A command that can be used for D0 can be used for any other D-register.

<lang 68000devpac>MOVE.B #$FF,D0 ;move the hexadecimal value 0xFF into the bottom byte of D0. ADD.W #$8000,D4 ;add hexadecimal 0x8000 to the value stored in D4.</lang>

Address Registers

There are eight of these as well, numbered A0-A7. A7 is reserved as the stack pointer, and is commonly referenced as SP in assemblers. The others are free to use for any purpose. Although these registers are 32-bit, the 68000's address space is 24-bit (ranges from 0x000000 to 0xFFFFFF), so the leftmost byte is ignored. You can do simple math involving these registers but more complicated commands like multiply or divide can only be used with data registers. Address registers are used to contain addresses and extract the values stored within.

Loading From Memory

<lang 68000devpac>MOVEA.L #$200000,A2 ;usually these are loaded from a label.

The hex dump of address $200000
44 55 66 77

MOVE.L #$00000000,D0 MOVE.B (A2),D0 ;load the byte stored at $200000 into D0. D0 = #$00000044 MOVE.W (A2),D0 ;load the word stored at $200000 into D0. D0 = #$00004455 MOVE.L (A2),D0 ;load the long stored at $200000 into D0. D0 = #$44556677 MOVE.L D2,(A5) ;store the contents of D2 into the memory address pointed to by A5.</lang>


Post-Increment

The post-increment mode is specified by adding a + to the end of parentheses. This means that after the command is done, the address stored in the address register (not the value stored at that address) is increased by the byte length of the command (1 for .B, 2 for .W, 4 for .L). <lang 68000devpac> MOVEA.L #$00240000,A4 ;load the address $240000 into A4 MOVE.W (A4)+,D0 ;move the word stored at $240000 into D0, then increment to #$240002 MOVE.L (A4)+,D1 ;move the long stored at $240000 into D1, then increment to #$240006 MOVE.L (SP)+,D3 ;pop the top value of the stack into D3</lang>

Pre-Decrement

The pre-decrement mode is specified by typing a - before the parentheses. This means that before the command is done, the address stored in the address register is decreased by the byte length of the command. <lang 68000devpac> MOVEA.L #$0024000A,A4 ;load the address $24000A into A4 MOVE.W -(A4),D0 ;move the word stored at $240008 into D0 MOVE.L -(A4),D1 ;move the long stored at $240004 into D1 MOVE.L D2,-(SP) ;push the contents of D2 onto the stack</lang>

Length

The 68000 can work with 8-bit, 16-bit, or 32-bit values. Some commands only work with specific lengths but most work with all three. To specify which length you are using, the command ends in a different suffix:

  • .B for byte length (8 bit)
  • .W for word length (16 bit)
  • .L for long length (32 bit)

If you don't specify a length with your command, it usually defaults to word length, but ultimately it depends on the command you are using. (Some commands cannot be used at word length.)

Bytes and words moved into a register are always stored on the right-hand side. For example: <lang 68000devpac>MOVE.L #$FFFFFFFF,D7 MOVE.B #$00,D7 ;D7 contains #$FFFFFF00 MOVE.W #$2222,D7 ;D7 contains #$FFFF2222</lang>

As you can see, the rest of the register is unchanged. (On the ARM, it would turn to zeroes.) This is very important to remember. If your code is doing something unexpected it might be due to the "old" value of the register corrupting another function.

If the given constant is smaller than the length provided, the value is padded to the left with zeroes. <lang 68000devpac>MOVE.W #$FF,D3 ;D3 = #$xxxx00FF, where x is the previous value of D3. MOVE.L #0,D3 ;D3 = #$00000000</lang>

Loading immediate values into address registers is different. You can only move words or longer into address registers, and if you move a word, the value is sign-extended. This means that if the top nibble of the word is 8 or greater, the value gets padded to the left with Fs, and is padded with zeroes if the top nibble is 7 or less. It's best to always move longs into address registers. That way you know what you're getting.

<lang 68000devpac>MOVEA.W #$8000,A4 ;A4 = #$FFFF8000. Remember the top byte is ignored so this is the same as #$00FF8000. MOVEA.W #$7FFF,A3 ;A3 = #$00007FFF</lang>

Traps

Traps are the equivalent of INT in 8086 Assembly/x86 Assembly or SVC/SWI 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:

<lang 68000devpac>;this is an example of how NOT to do it!

CMP.L #0,D0 BEQ DivideByZeroError DIVU D0,D1 RTS DivideByZeroError:

put your error handler here</lang>

What actually happens is that the processor automatically calls the relevant trap (Trap 5 in this case) if the divisor is zero. 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.

Certain traps have specific meanings as defined by the 68000 itself:

  • Trap 4 occurs if the ILLEGAL command is executed. This is similar to BRK 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. This (admittedly contrived) example will show the basic concept. If the ILLEGAL routine is executed, the programmer now knows that the code leading up to TestRoutine is bugged.

<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 DIVU or DIVS instruction attempts to divide by zero.
  • Trap 6 detects if a value is out of bounds for a desired range. The CHK 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 TRAPV instruction, which calls it if the overflow flag is set.

Citations

  1. 'Akuyou', Keith. Learn Multiplatform Assembly Programming with Chibiakumas! Las Vegas, NV. Self-published, 05 April 2021.
  2. [ChibiAkumas Motorola 68000 Tutorial]
  3. [68000 Tricks and Traps]


It has been suggested that this language be merged with M680x0 . See that page's talk page

Subcategories

This category has the following 2 subcategories, out of 2 total.

Pages in category "68000 Assembly"

The following 106 pages are in this category, out of 106 total.