Research / Megadrive Programming / Compares, branches...

Yay, finally got some time to write another lesson (it's almost 12pm).
Anyway, we'll learn about compares, branches and subroutines. But
first, here's some additional info to the previous lesson:



There are few types of MOVE. There's MOVEA, MOVEM, MOVEP and MOVEQ. Usually the compiler chooses the right one, but you sometimes have to choose the correct one (assemblers aren't very smart ;).




MOVEA moves an address into an address register. The syntax:



	movea	address,a0-a7


As I said before, don't use a7. Just wait =) The address is an effective address (can be a register, immediate value etc.) Here are some examples:
        movea    #$12346,a0     ;moves address $12346 to a0

movea -(a1),a5 ;moves address at value at pointer
;in a1 to a5, decrements a1 before instruction
movea d0,a3 ;moves d0 to a3


I'll introduce the labels now :) Remember BASIC and goto function? Labels are similiar:



	somecode


bra Label

somecode

Label:
somecode



BRA goes (jumps) to a label. Bcc instructions can branch on certain conditions, but they can be made with the CMP instruction. This means a bunch of new instructions ;) Here's the example code:
	game code

game code

bsr LifesSub

game code
game code


LifesSub:
cmp.w #$0102,($FFFFFE10).w
bne TheLevelIsNot0102
add.b #1,($FFFFFE12).w
TheLevelIsNot0102:
rts



Oh my, so many new things. We created label 'LifesSub'. It's called by BSR, what's that? BSR means Branch to SubRoutine.
Subroutines are like functions in C (or other programming languages).
You can call them whenever you want. There is one important thing
though, after the end of subroutine you have to put rts, which returns to the state before subroutine calling. Example:

	bsr	Foo

bsr Foo
bsr Foo

...


Foo:

code

rts


Now, when Genny sees BSR (8 or 16 bit instruction, relative address) or JSR (32 bit absolute address, I'll tell about it later), it copies the next insruction PC
(Program Counter - register which stores info about the current
instruction location in ROM, like where the code is now, it's hard to
explain ;) state to stack.
I promised before that I'll tell you what the hell stack is. Stack is a reserved section in RAM (CAN be in SRAM, but it isn't tested yet ;) for temporary things, like our PC state. Now you see why RTS is important. RTS copies the PC state back from stack.




So, what's the CMP thingy? It COMPARES two values. It's not exactly if...else statement like in C. BNE means 'Branch if Not Equal'. So if $FFFFFE10 (level) isn't $0102 (these two values are the same, equal), it branches. If it isn't, it doesn't. Simple, huh? There are many Bcc instructions, one of them being BEQ (Branch if EQual) which works opposite to BNE. I mentioned JSR some lines before. It is like BSR,
but it doesn't branch, but jumps to a subroutine. What's the
difference? Branch instruction is small (1 byte if branch is between
-127...127 and 2 bytes if it's between -32 768...32 768) but it's
limited. Some games like Sonic 3 & Knuckles use RAM for... code.
Yeah, small parts of code that can be edited at any time. You can't
branch to RAM, that's first. Second, the limitation. $8000 back or
forth is not very big. There's the JSR. The instruction is longer (4 or
6 bytes, depending on the type), but it's an absolute address (you can
make a relative jsr insruction, but I've already told enough
new things today...), so you can jump to any address in 68000 memory.
For 68k memory map, see additional info. Examples:

	jsr	$FFFFFFF0

jsr Label
jsr a0


The absolute equivalent of BRA is JMP, which jumps to an absolute address without puting the PC on the stack.



The last two things we're gonna learn today are MOVEQ and MOVEM.


MOVEQ is similar to MOVE, but it means MOVE Quick. It's a faster (and smaller - 1 byte) instruction. You can only move 1 byte. Example:
	moveq	#0,d0

Clears ENTIRE d0, because when you moveq into a register, it sets the ENTIRE register.



It clears the register! Move.l would take 6 bytes (hey, in old times space was worth more than gold), when moveq only 1.

You can also use ADDQ and SUBQ (they can also change values in ram)



Now, the last thing. MOVEM (MOVE Multiple).
It can copy more than one register to a location in RAM or in reverse
(RAM to more than one register). As I said before A7 is the stack
pointer. So you can use stack, too! The reason why MOVEM was
created are subroutines. Subroutines are called in many different
places in ROM. And subroutines often use registers. Now if you don't
want to change some important registers inside a subroutine, you should
backup these registers before the subroutine and copy them back after.
Don't get it? Look at the example:


	move.b	#$10,d0

bsr Subroutine
move.b d0,d1

...

Subroutine:

...

moveq #0,d0

...

rts


Take a look at that code. We set d0 to $10, then the subroutine clears d0. After the subroutine, we move d0 to d1. That's not exactly what we wanted (it'll set d1 to 0, we wanted it to be $10). To fix that we can use movem:


move.b #$10,d0
bsr MovemSub
move.b d0,d1

...

MovemSub:

movem d0-d2,-(sp)

...

moveq #0,d0

...

movem (sp)+,d0-d2
rts


Now it'll work! the SP is the stack pointer. You could use A7 (it's the same), but I use sp. We decremented sp, because if we didn't, we would change some important data in SP. and after that, we increment SP back to its state. The register list can be different. Eg.



d0-d5 - d0, d1, d2, d3, d4, d5

a5-a6 - a5, a6
d1-d3/d6-d7 - d1, d2, d3, d6, d7
d6-a1/a5-a6 - d6, d7, a0, a1, a5, a6


There are many different possibilites... If you don't understand MOVEM,
just skip it, and come back to it when you will know more about ASM. It
took me 4 tries to understand that thing XD (and I didn't have any
nifty guides *shot*)



That's all folks! In next lesson I'll introduce some more Bcc instructions and maybe some bit operations? G'night.

Back | Printer friendly
<< 2. Let's start | 4. Logical operations >>

© 2004, 2005 drx, www.hacking-cult.org. Don't copy without permission yadda yadda yadda.