68k asm madness

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
KanedaFr
Administrateur
Posts: 1139
Joined: Tue Aug 29, 2006 10:56 am
Contact:

68k asm madness

Post by KanedaFr » Thu Oct 07, 2010 11:09 am

Hi,

I'm actually disasm a game and I'm stuck on some instructions:

Code: Select all

    move    #$2700,sr
    movea.w #$FFFE,sp
    movea.w #$B000,a0
loc_1730A: 
    clr.l   (a0)+
    cmpa.w  #$D03E,a0
    blt.s   loc_1730A
I'm pretty sure this one clean RAM from FFD000 to FFD03E but, so, why
it's movea.w and not movea.l #$FFB000, a0 ? could someone explain it to me ? ;)
is it because of the movea.w #$FFFE,sp ?


Code: Select all

bra *+4
I know I already asked about it but I'm unable to find it...
what does it exactly do ?!


The best one for the last

Code: Select all

bsr.w drawTiles
dc.w 6
dc.b $FF
dc.b 0
dc.b 2
dc.b 0
clr.w d0
...
rts
...
...
drawTiles:
 move.l  a1,-(sp)
 movea.l 4(sp),a1
 bsr.w   writeText       ; A1 = text info
 move.l  a1,4(sp)
 movea.l (sp)+,a1
 rts
actually this one seems to call drawTiles, which uses the data following the call, then comes back to code after the data (clr.w d0)
why is it done this way ?!
i found some others func call using this method, how could I know where it exactly jump back ?
perhaps, like for my first question, it's because I'm misunderstanding sp use ?

thanks for any hints, as usual ;)

GManiac
Very interested
Posts: 92
Joined: Thu Jan 29, 2009 2:05 am
Location: Russia

Post by GManiac » Thu Oct 07, 2010 11:57 am

movea.w #$B000,a0 is equal to movea.l #$FFFFB000,a0
movea.w #$FFFE,sp = movea.l #$FFFFFFFE,sp
cmpa.w #$D03E,a0 = cmpa.l #$FFFFD03E,a0
Remember that 68k has 24 bit address wire, so decoding address from a0 will give you $00FFB000 and so on.
bra *+4
What disasm do you use? IDA? I never saw such instruction. What hex-code has it?
bsr.w drawTiles
...
I don't see any strangenesses in drawTiles function, maybe a1 is set after calling writeText function to new value, then you RTS to other address. You'd better to debug this code to understand it.

KanedaFr
Administrateur
Posts: 1139
Joined: Tue Aug 29, 2006 10:56 am
Contact:

Post by KanedaFr » Thu Oct 07, 2010 2:40 pm

GManiac wrote:movea.w #$B000,a0 is equal to movea.l #$FFFFB000,a0
movea.w #$FFFE,sp = movea.l #$FFFFFFFE,sp
cmpa.w #$D03E,a0 = cmpa.l #$FFFFD03E,a0
Remember that 68k has 24 bit address wire, so decoding address from a0 will give you $00FFB000 and so on.
on some other line, I saw thing like
movea.l #$F8BF4,a0

does it mean that if I see a movea.l #addr, a0 it mean addr is loaded in a0 (whatever addr is) and when I see movea.l #addr, a0 it mean 0xFFFFaddr is loaded in a0 (whatever addr is) ?
I don't understand how the 68k does this...
for me, loading a word to a0...a7/sp will result to 0000word, not FFFFword....perhaps it's my mistake ?
bra *+4
What disasm do you use? IDA? I never saw such instruction. What hex-code has it?
yeah, IDA ;) really like it ;)
hex is 60 00 00 02
also find a beq *+4 => 67 00 00 02
bsr.w drawTiles
...
I don't see any strangenesses in drawTiles function, maybe a1 is set after calling writeText function to new value, then you RTS to other address. You'd better to debug this code to understand it.
this kind of code ( movea.l 4(sp), a1 ) seems to mean move a long from after the PC...
sp is not pc....so I'm very confused...
how could you, in asm say to jump some bytes after the caller call from the callee (...err...hope you understand!) ?
jsr func1

func1:
do stuff
rts + 4 bytes ?!!!!

I see nothing strange in writeText

Code: Select all

writeText:
                 move.w  (vdpFlags).w,-(sp)
                 bset    #2,(vdpFlags).w
                 movem.l d0-d3/a0/a2,-(sp)
....
                 movem.l (sp)+,d0-d3/a0/a2
                 move.w  (sp)+,(vdpFlags).w
                 rts

GManiac
Very interested
Posts: 92
Joined: Thu Jan 29, 2009 2:05 am
Location: Russia

Post by GManiac » Thu Oct 07, 2010 3:59 pm

KanedaFr wrote:movea.w #$B000,a0 is equal to I don't understand how the 68k does this...
for me, loading a word to a0...a7/sp will result to 0000word, not FFFFword....perhaps it's my mistake ?
Did you read M68k Programmer's Manual? Do you know about sign-extension? It means that if you extend operand to more bytes, its sign-bit (msb) is copied to all older bits of new operand:
+5 in 4 bits = 0101
+5 in 8 bits = 0000 0101

-5 in 4 bits = 1011
-5 in 8 bits = 1111 1011
So, to save sign during extension you need to copy msb to all older bits. It's called sign-extension.
All opertaions with addrress registers like MOVEA, LEA, ADDA, SUBA, CMPA are sign-extended.
So,
LEA $4000.w, a0 = LEA $0000 4000.l, a0
LEA $C000.w, a0 = LEA $FFFF C000.l, a0

This let you to address upper half of RAM FFFF8000-FFFFFFFF (which will be realle 00FF8000-00FFFFFF) with word-sized addressed.

hex is 60 00 00 02
It's simple BRA 4(pc)
Example:
0008: 6000 0040 BRA $40(pc)
will jump to 8 + 2 + $40 = $4A.
We add 2 becuase after reading opcode BRA "6000" pc will be already 000A, and THEN we add displacement.

You can use my own disasm:
http://shedevr.org.ru/ghost/segadasm.rar

3. What the game is? I'd like to debug it. I saw such strange routines in Landstalker, but they were understandable.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Thu Oct 07, 2010 4:04 pm

Code: Select all

bsr.w drawTiles
dc.w 6
dc.b $FF
dc.b 0
dc.b 2
dc.b 0
clr.w d0
...
rts
...
...
drawTiles:
 move.l  a1,-(sp)
 movea.l 4(sp),a1
 bsr.w   writeText       ; A1 = text info
 move.l  a1,4(sp)
 movea.l (sp)+,a1
 rts
The bsr drawTiles pushes the return address, which points to the data following the bsr. drawTiles saves a1, then loads a1 with the return address, which points to the data. It then calls writeText which uses the data in a1, leaving a1 pointing to just past the data (which is more code). drawTile then saves this a1 over top the return address so that it returns to the code following the data after the bsr drawTiles, restores the original a1, then returns.

So think of bsr drawTiles as having a BIG immediate data following it before the code continues normally. This type of subroutine is actually pretty common for 68000 code where you have fixed data for a subroutine like printing. Just remember that the data MUST be even or you get an address error.

GManiac
Very interested
Posts: 92
Joined: Thu Jan 29, 2009 2:05 am
Location: Russia

Post by GManiac » Thu Oct 07, 2010 4:16 pm

maybe a1 is set after calling writeText function to new value, then you RTS to other address.
Here:

Code: Select all

writeText: 
                 move.w  (vdpFlags).w,-(sp) 
                 bset    #2,(vdpFlags).w 
                 movem.l d0-d3/a0/a2,-(sp) 
.... 
                 movem.l (sp)+,d0-d3/a0/a2 
                 move.w  (sp)+,(vdpFlags).w 
                 rts
But you missed this code behind ellipsis.

HardWareMan
Very interested
Posts: 745
Joined: Sat Dec 15, 2007 7:49 am
Location: Kazakhstan, Pavlodar

Post by HardWareMan » Fri Oct 08, 2010 1:52 am

I early 90's, when I programmed under the i8080, I often used this design:

Code: Select all

call PrintString
db   'Hello world!', 0
call PrintString
db   'Another string!', 0
*
PrintString:
pop  h
push psw
PrintLoop:
mov  a, m
ora  a
jz   PrintExit
call PrintSymbol
inx  h
jmp  PrintLoop
PrintExit:
pop  psw
inx  h
push  h
ret
As you can see, I use the return address as a pointer to the data. The usual method, and do not require labels to text strings.

KanedaFr
Administrateur
Posts: 1139
Joined: Tue Aug 29, 2006 10:56 am
Contact:

Post by KanedaFr » Fri Oct 08, 2010 7:28 am

GManiac wrote:Did you read M68k Programmer's Manual? Do you know about sign-extension? It means that if you extend operand to more bytes, its sign-bit (msb) is copied to all older bits of new operand:
+5 in 4 bits = 0101
+5 in 8 bits = 0000 0101

-5 in 4 bits = 1011
-5 in 8 bits = 1111 1011
So, to save sign during extension you need to copy msb to all older bits. It's called sign-extension.
All opertaions with addrress registers like MOVEA, LEA, ADDA, SUBA, CMPA are sign-extended.
So,
LEA $4000.w, a0 = LEA $0000 4000.l, a0
LEA $C000.w, a0 = LEA $FFFF C000.l, a0

This let you to address upper half of RAM FFFF8000-FFFFFFFF (which will be realle 00FF8000-00FFFFFF) with word-sized addressed.
ooooooooooh!!! i knew about sgn extension but using ext
I didn't know about the automatique sign extension on operation with aX, thanks to pointing me this!
useful trick for any RAM access beyon FF8000 so...



You can use my own disasm:
http://shedevr.org.ru/ghost/segadasm.rar
thanks but IDA is so usefull to comment, rename, etc...
I can't do disasm with something else LOL
I use it for PC, Arcade rom, GB rom and MD rom ;)
3. What the game is? I'd like to debug it. I saw such strange routines in Landstalker, but they were understandable.
Take any EA game....they are insane!
If I remember, RoadRash serie is the best one...;)

KanedaFr
Administrateur
Posts: 1139
Joined: Tue Aug 29, 2006 10:56 am
Contact:

Post by KanedaFr » Fri Oct 08, 2010 7:32 am

Chilly Willy wrote:The bsr drawTiles pushes the return address, which points to the data following the bsr. drawTiles saves a1, then loads a1 with the return address, which points to the data. It then calls writeText which uses the data in a1, leaving a1 pointing to just past the data (which is more code). drawTile then saves this a1 over top the return address so that it returns to the code following the data after the bsr drawTiles, restores the original a1, then returns.
thanks for these clear details!
I didn't know 4(sp) was the return address...it seems I missed this (other) point on the 68k ASM guide :oops:

Did I say I'm not very good at ASM ? :lol:
I'm able to read and understand lot of stuff...but not these tricky one (at least, for me)

thanks you for your help to increase my level :wink:

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Oct 08, 2010 5:26 pm

As you continue to use asm, you'll get better. Especially if you go through code like this and see how others use it - you start to pick up all the little tricks programmers have used. The 68000 is a good CPU to start with asm on since it's not nearly as bad as other cpus, like the x86. While you don't need to memorize the manual, you should probably read through it once to get an idea of what you can do. You will find things like the automatic sign extension of address registers or address (word) constants. There's good reasons why the Genesis uses the rom at 0 and the ram at 0xFF0000.
8)

Post Reply