News
Documents
Source Code
Downloads
Message Board


Sega Megadrive Assembly Programming Basics

Copyright, Lewis Bassett, December 2005


Chapter 4 - Assembly Language

Section 1 - Move Instructions

Move instructions tend to make up the majority of a normal Megadrive program. As I mentioned earlier, move instructions actually copy data from one location to another. The most commonly used move instruction is 'move.x', where 'x' is either: 'l' (longword), 'w' (word) or 'b' (byte).

	move.b	#$d0,	d0;
The above instruction copies the hex value d0 (note 'd0' is a hex value, not a regisers, because it has '#' and '$' before it) into data regiser d0.

The 'move' instruction can move data into and from regisers or memory locations.

	move.w	d0,	$ff0000;
This instruction moves the contents of regiser d0 into memory address $ff0000. As we previously copied the hex value $d0 into regiser d0, memory address $ff0000 also holds the value of hex number $d0.

As I explained earlier, address registers can be used to point to an address that holds information. This is done by copying an address into an address regiser.

	move.l	#$00ff0000,	a1;
Register a1 now holds the value of $00ff0000. Notice that this is the location of the general purpose RAM. I've padded the six digits out to eight, as this is good practise. I've also put a '#' before the address, otherwise the processor would copy the contents of address $ff00000 into a1, instead of the actual address.

Now, whenever I would want to copy information into RAM, I can use the register a1, which now points to address $ff0000. This is done by refering to register a1 with parentheses, ie, (a1).

	move.b	#21,	(a1);
This instruction moves the value '21' into address $ff0000, as this is what register a1 points to.

Now that an address is stored in an address register, we can use the program to alter the address as it runs, making our address a variable. Consider these lines of code:

	move.l	#$00ff0000,	a1;
	move.b	#$13,		d0;
	move.b	d0,		(a1);
	move.l	#$00ff0004,	a1;
	move.b	d0,		(a1);
Using address registers we can use the same lines of code to move different data, into different addresses. Imagine the possibilities. In theory, a programmer could use the same function for completly different purposes by using registers to hold data and addresses.

Another very useful feature of address regiseters is that we can increment or decrement addresses. What do I mean by this? Let's say I want to copy the number 10 into memory loads and loads of times, right next to eachother, starting at address $ff0010.

	move.b	#01,		d0;
	move.l	#$00ff0010,	a1;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
	move.b	d0,		(a1)+;
You'll notice that '(a1)', which is used to refer to whatever a1 points to, has changed to '(a1)+'. This means, write to whatever register a1 points to, then increment the value of a1, so it points to the next bit. The very useful thing about this instruction, is that the processor takes the '.b' that is suffixed to move, and uses it to determine how much to increment a1 by.
	move.l	d0,		(a1)+;
With this instruction, the processor recognises the '.l' and increments the value of a1 by four bytes (one longword). A1 now points to memory address $ff0014 ($ff0010 + 4).
	move.w	d0,		(a1)-;
Here, the processor uses the '.w' after 'move', and the '-' after '(a1)' to decrement the address stored in A1. A1 now points to address $ff0012 ($ff0014 - 2).

Indirect addressing can also be used on the source operand, aswell as the destination. Consider the following small program.

	move.l	$ff00f0,	a1;
	move.l	$ff0000,	a2;
	move.w	(a1)+,		(a2)+;
	move.w	(a1)+,		(a2)+;
	move.w	(a1)+,		(a2)+;
	move.w	(a1)+,		(a2)+;
	move.w	(a1)+,		(a2)+;
First, I put the addresses $ff00f0 and $ff0000 into registers a1 and a2. Then, I used indirect addressing on the source and destination operands, and told the processor to increment the addresses in both registers after each instruction. This small program copies five words starting at address $ff00f0 into the beginning of the Megadrive's free-use RAM. As you'll find out later, this method of using address registers, called indirect addressing, is very very useful.


Movem - Move Multiple

'Movem' (MOVE Multiple) is a useful variation on the move instruction. It is used when data from multiple registers needs to be moved.

	movem.l	d0/d1/d2/d3, d4/d5/d6/d7;
This instruction moves the contents of registers d0, d1, d2 and d3 into registers d4, d5, d6 and d7. Notice how each different register is seperated by a forward slash ('/'). The same instruction can also be written using a hyphen to specify a range of registers.
	movem.l	d0-d3, d4-d7;
Movem is most commonly used for storing the contents of registers onto the stack, often before a subroutine, so that the registers can be used for something else. The register values can then be taken back off the stack and restored. As I mentioned before, register a7 is used to point to the stack.
	movem.l	d0-d7/a0-a4, -(a7);
Notice that I've told the processor to decrement the address stored in a7 (the stack), rather than increment it. The stack uses a LIFO (Last In First Out) data structure that means that data is stored backwards.

To restore the data from the stack, we simply do the reverse, we take the data from the stack and increment the pointer.

	
	movem.l	(a7)+, d0-d7/a0-a4;
Programmers will often set up their own stack by using, most often, register a6. To do this, we first need to point a6 to an address in memory when we want to store the stack. Remember, anything from address $ff0000 to $ffffff is general use RAM. The following code sets up a stack at memory address $ff00a0 and saves and restores the contents of all the other registers.
	move.l	#$00ff00a0,	a6;
	movem.l	d0-d7/a0-a5,	-(a6);
	
	[ Some more code ]
	
	movem.l	(a6)+,		d0-d7/a0-a5;
In theory, the only limit to the ammount of stacks a programmer can use is the size of memory. However, there are only 7 general purpose address registers which could point to them. Often, it's a good idea to set up a seperate dedicated stacks for different specific tasks, especially in larger and more complicated programs.


Moveq - Move Quick

One last instruction we'll use is 'moveq' (MOVE Quick). Moveq works like the move instruction, but it can only work with one byte at a time. The advantage is that it is much faster than the move instruction.

	moveq	#$f1,	d0;
Moveq can only be used to move numbers into data registers. Address registers and memory cannot be used.

In section 2, I'll explain about the most important arithmetic instructions.



Chapter 4 Contents Chapter 4 - Section 2


Designed & maintained by Lewis AS Bassett
SEGA, Megadrive, Genesis, Sonic the Hedgehog, etc are all owned by Sega Enterprises Ltd