Sonic and Sega Retro Message Board: Debugging misaligned read/write - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Loading News Feed...
 

Debugging misaligned read/write Or how to get your hack to work on Regen/Kega/real hardware

#1 User is offline flamewing 

  Posted 10 March 2011 - 08:45 AM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
Inside the spoiler tag below is the original post, which I am preserving; here is the new version.

An address error happens on real hardware (or in good emulators such as Regen) whenever a word- or long-sized read or write happens at an odd address. So, for example, if you try to read the contents of address $FFFF0001 as if it were a word or a long, an address error will happen. Sonic 1 displays a simple error message; Sonic 2 locks up; Sonic 3 and Sonic & Knuckles reset the game. None of these scenarios are useful for finding out what caused the error, which is usually what prevents hacks from working on real hardware.

I decided to include the bus error in the debugger solely because it has the same data available for debugging as an address error does; the changes were minor enough that I had no real reason not to include it, but I have doubts anyone will need it.

Here is the debugger: address/bus error debugger; I explain below how it is used. I have tried it with the Hg disassemblies of S2 and S&K; I think it will work on Xenowhirl's 2007 disassembly for all those masochistic enough to insist on using an outdated disassembly; if it doesn't, I would appreciate knowing what errors are printed when assembling so I can fix them. At present, only AS is supported.

To use the debugger, proceed as follows:

1) Extract all files to the base directory on your disassembly. At any point (for example, at the end of the disassembly), add the following line:
	include "Address Error.asm"

2) Find the label 'Vectors:' at the start of the disassembly:
S2 disassembly:
Find this:
;Vectors:
	dc.l System_Stack, EntryPoint, ErrorTrap, ErrorTrap; 4

and change it to this:
;Vectors:
	dc.l System_Stack, EntryPoint, BusError , AddressError; 4

S&K disassembly:
Find this:
Vectors:	dc.l Vectors, EntryPoint, ErrorTrap, ErrorTrap	; 0

and change it to look like this:
Vectors:	dc.l Vectors, EntryPoint, BusError, AddressError	; 0

3) Open the file "Address Error.asm". Locate the labels 'HackerName' and 'EMailmsg' and edit them to your heart's content; if 'EMailmsg' is empty, the entire line containing it will be eliminated (see image below). The text must be in all-capitals, and can include letters, numbers, spaces or the following symbols:
? @ [ ] \ ( ) + , - . / : ; # $ % & ! *

4) Find the 'Revision' equate and change the number. This is so you can give an internal identifier to any build of the hack.

5) When building the hack for testing, add '-g MAP' to the line invoking asw/asl. This will generate a file '*.map' file that associates each file/line of the source file(s) to an address on the final ROM. The build will be a lot slower, though.

6)
If you are using the Hg disassemblies, you are done. If you are using the S2 2007 disassembly, you still have to do a few things:

a) Find the following lines in s2.asm:
dma68kToVDP macro source,dest,length,type 
	lea	(VDP_control_port).l,a5 
	move.l	#(($9400|((((length)>>1)&$FF00)>>8))<<16)|($9300|(((length)>>1)&$FF)),(a5) 
	move.l	#(($9600|((((source)>>1)&$FF00)>>8))<<16)|($9500|(((source)>>1)&$FF)),(a5) 
	move.w	#$9700|(((((source)>>1)&$FF0000)>>16)&$7F),(a5) 
	move.w	#((dest)&$3FFF)|((type&1)<<15)|$4000,(a5) 
	move.w	#$80|(((dest)&$C000)>>14)|((type&2)<<3),(DMA_data_thunk).w 
	move.w	(DMA_data_thunk).w,(a5) 
	endm 
	; values for the type argument 
	enum VRAM=0,CRAM=1,VSRAM=2 
 
; tells the VDP to fill a region of VRAM with a certain byte 
dmaFillVRAM macro byte,addr,length 
	lea	(VDP_control_port).l,a5
	move.w	#$8F01,(a5) ; VRAM pointer increment: $0001
	move.l	#(($9400|((((length)-1)&$FF00)>>8))<<16)|($9300|(((length)-1)&$FF)),(a5) ; DMA length ...
	move.w	#$9780,(a5) ; VRAM fill
	move.l	#$40000080|(((addr)&$3FFF)<<16)|(((addr)&$C000)>>14),(a5) ; Start at ...
	move.w	#(byte)<<8,(VDP_data_port).l ; Fill with byte
-	move.w	(a5),d1
	btst	#1,d1
	bne.s	- ; busy loop until the VDP is finished filling...
	move.w	#$8F02,(a5) ; VRAM pointer increment: $0002
	endm

and replace them with this:
vdpComm function addr,type,rwd,(((type&rwd)&3)<<30)|((addr&$3FFF)<<16)|(((type&rwd)&$FC)<<2)|((addr&$C000)>>14)
; values for the type argument
VRAM = %100001
CRAM = %101011
VSRAM = %100101
; values for the rwd argument
READ = %001100
WRITE = %000111
DMA = %100111 
dma68kToVDP macro source,dest,length,type
	lea	(VDP_control_port).l,a5
	move.l	#(($9400|((((length)>>1)&$FF00)>>8))<<16)|($9300|(((length)>>1)&$FF)),(a5)
	move.l	#(($9600|((((source)>>1)&$FF00)>>8))<<16)|($9500|(((source)>>1)&$FF)),(a5)
	move.w	#$9700|(((((source)>>1)&$FF0000)>>16)&$7F),(a5)
	move.w	#((vdpComm(dest,type,DMA)>>16)&$FFFF),(a5)
	move.w	#(vdpComm(dest,type,DMA)&$FFFF),(DMA_data_thunk).w
	move.w	(DMA_data_thunk).w,(a5)
	endm
; tells the VDP to fill a region of VRAM with a certain byte
dmaFillVRAM macro byte,addr,length
	lea	(VDP_control_port).l,a5
	move.w	#$8F01,(a5) ; VRAM pointer increment: $0001
	move.l	#(($9400|((((length)-1)&$FF00)>>8))<<16)|($9300|(((length)-1)&$FF)),(a5) ; DMA length ...
	move.w	#$9780,(a5) ; VRAM fill
	move.l	#$40000080|(((addr)&$3FFF)<<16)|(((addr)&$C000)>>14),(a5) ; Start at ...
	move.w	#(byte)<<8,(VDP_data_port).l ; Fill with byte loop:
loop:
	move.w	(a5),d1
	btst	#1,d1
	bne.s	loop ; busy loop until the VDP is finished filling...
	move.w	#$8F02,(a5) ; VRAM pointer increment: $0002
	endm

b) Open "Address Error Defs.asm" and replace the following lines:
EniDec := Eni_Decomp KosDec := Kos_Decomp PlaneMapToVRAM := Plane_Map_To_VRAM

with this:
Chunk_Table := Metablock_Table
PlaneMapToVRAM := ShowVDPGraphics 

Once all of this is done, the screen is ready for use. To test it and see if it is working, you can add this code anywhere you are sure will execute:
	movea.w	#$0001,a0
	jmp	(a0)

Of course, the disassembler does not initialize the z80 or the VDP, instead assuming that they have been initialized already; so the test code must go after the initialization code for them both, or you will get a black screen. Here is a sample of the output:
Posted Image
It has a readable version of all data saved on a bus/address error, all registers, and a disassembly of the instruction that caused the address error. The disassembler was hand-coded, and recovers as much information as possible. Jumps, branches and loops usually do not allow full recovery, with jsr, bsr, and being exceptions. Nevertheless, only jmp will be an issue because all the others are caught by the assembler when building the ROM. The disassembler also warns when the disassembly could not retrieve all information.

Being in possession of all this data and of the map file allows you to quickly find where the error happened and give you an idea why.

I would appreciate if anyone could test this on real hardware; I know it works on Regen, but I don't know if Regen works the same way as real hardware does with respect to the behavior of the program counter.

For those that got this earlier in another thread: this version has a bug fix on the disassembler, and does not need separate versions for S2 and S&K disassemblies; you should grab this version.

Spoiler


Please ignore this attachment, it is of the older version:

Attached File(s)


This post has been edited by flamewing: 23 July 2012 - 01:08 PM

#2 User is offline flamewing 

Posted 18 February 2012 - 10:52 AM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
I updated the address error with a vastly superior version that includes a hand-coded disassembler. Look at the post above for details on how to use it and the download link.

#3 User is offline redhotsonic 

Posted 18 February 2012 - 03:56 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
Cheers, just one problem:

> > >Address Error.asm(99): error: unknown function
> > > VDPCOMM
> > > 	move.l	#vdpComm($0000,VSRAM,WRITE),(a6)
> > >Address Error.asm(321): error: unknown function
> > > VDPCOMM
> > > 	move.l	#vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE),d0


Probably because I'm using xenowhirls 2007.


I now know why my hack is freezing too, just not sure how to solve it so hopefully this will help once in.

#4 User is offline flamewing 

Posted 18 February 2012 - 04:55 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
Add these lines to 'Address Error Defs.asm' just under the line with 'make_art_tile':
vdpComm function addr,type,rwd,(((type&rwd)&3)<<30)|((addr&$3FFF)<<16)|(((type&rwd)&$FC)<<2)|((addr&$C000)>>14)
; values for the type argument
VRAM = %100001
CRAM = %101011
VSRAM = %100101

; values for the rwd argument
READ = %001100
WRITE = %000111
DMA = %100111


Edit: you will also need to find in s2.asm the definitions of dma68kToVDP and dmaFillVRAM and replace them both by this:
; tells the VDP to copy a region of 68k memory to VRAM or CRAM or VSRAM
dma68kToVDP macro source,dest,length,type
	lea	(VDP_control_port).l,a5
	move.l	#(($9400|((((length)>>1)&$FF00)>>8))<<16)|($9300|(((length)>>1)&$FF)),(a5)
	move.l	#(($9600|((((source)>>1)&$FF00)>>8))<<16)|($9500|(((source)>>1)&$FF)),(a5)
	move.w	#$9700|(((((source)>>1)&$FF0000)>>16)&$7F),(a5)
	move.w	#((vdpComm(dest,type,DMA)>>16)&$FFFF),(a5)
	move.w	#(vdpComm(dest,type,DMA)&$FFFF),(DMA_data_thunk).w
	move.w	(DMA_data_thunk).w,(a5)
	endm

; tells the VDP to fill a region of VRAM with a certain byte
dmaFillVRAM macro byte,addr,length
	lea	(VDP_control_port).l,a5
	move.w	#$8F01,(a5) ; VRAM pointer increment: $0001
	move.l	#(($9400|((((length)-1)&$FF00)>>8))<<16)|($9300|(((length)-1)&$FF)),(a5) ; DMA length ...
	move.w	#$9780,(a5) ; VRAM fill
	move.l	#$40000080|(((addr)&$3FFF)<<16)|(((addr)&$C000)>>14),(a5) ; Start at ...
	move.w	#(byte)<<8,(VDP_data_port).l ; Fill with byte
loop:	move.w	(a5),d1
	btst	#1,d1
	bne.s	loop ; busy loop until the VDP is finished filling...
	move.w	#$8F02,(a5) ; VRAM pointer increment: $0002
	endm

This post has been edited by flamewing: 18 February 2012 - 04:59 PM

#5 User is offline redhotsonic 

Posted 18 February 2012 - 05:22 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
I now have 72 errors, something to do with VDPCOMM. Here are some typical errors:

> > >s2.asm(985) DMA68KTOVDP(5): error: unknown function
> > > VDPCOMM
> > >         move.w  #((vdpComm($0000,CRAM,DMA)>>16)&$FFFF),(a5)
> > >s2.asm(985) DMA68KTOVDP(6): error: unknown function
> > > VDPCOMM
> > >         move.w  #(vdpComm($0000,CRAM,DMA)&$FFFF),(DMA_data_thunk).w
> > >s2.asm(991) DMA68KTOVDP(5): error: unknown function
> > > VDPCOMM
> > >         move.w  #((vdpComm($0000,CRAM,DMA)>>16)&$FFFF),(a5)
> > >s2.asm(991) DMA68KTOVDP(6): error: unknown function
> > > VDPCOMM
> > >         move.w  #(vdpComm($0000,CRAM,DMA)&$FFFF),(DMA_data_thunk).w
> > >s2.asm(1019) DMA68KTOVDP(5): error: unknown function
> > > VDPCOMM
> > >         move.w  #((vdpComm($F800,VRAM,DMA)>>16)&$FFFF),(a5)




I will say, I commented the last line out here:

    ; values for the type argument
;    enum VRAM=0,CRAM=1,VSRAM=2


Otherwise, I got 3 errors saying the double defined.

#6 User is offline flamewing 

Posted 18 February 2012 - 05:36 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12

View Postredhotsonic, on 18 February 2012 - 05:22 PM, said:

I now have 72 errors, something to do with VDPCOMM. Here are some typical errors:

Move the vdpComm definition (and the constants below) to right above the dma68kToVDP definition.


#7 User is offline redhotsonic 

Posted 18 February 2012 - 06:19 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
I'm not sure what you mean. If you mean not to have them to the very left hand side as labels, that's already so:

; simplifying macros

; tells the VDP to copy a region of 68k memory to VRAM or CRAM or VSRAM
dma68kToVDP macro source,dest,length,type
	lea	(VDP_control_port).l,a5
	move.l	#(($9400|((((length)>>1)&$FF00)>>8))<<16)|($9300|(((length)>>1)&$FF)),(a5)
	move.l	#(($9600|((((source)>>1)&$FF00)>>8))<<16)|($9500|(((source)>>1)&$FF)),(a5)
	move.w	#$9700|(((((source)>>1)&$FF0000)>>16)&$7F),(a5)
	move.w	#((vdpComm(dest,type,DMA)>>16)&$FFFF),(a5)
	move.w	#(vdpComm(dest,type,DMA)&$FFFF),(DMA_data_thunk).w
	move.w	(DMA_data_thunk).w,(a5)
	endm
    ; values for the type argument
;    enum VRAM=0,CRAM=1,VSRAM=2

; tells the VDP to fill a region of VRAM with a certain byte
dmaFillVRAM macro byte,addr,length
	lea	(VDP_control_port).l,a5
	move.w	#$8F01,(a5) ; VRAM pointer increment: $0001
	move.l	#(($9400|((((length)-1)&$FF00)>>8))<<16)|($9300|(((length)-1)&$FF)),(a5) ; DMA length ...
	move.w	#$9780,(a5) ; VRAM fill
	move.l	#$40000080|(((addr)&$3FFF)<<16)|(((addr)&$C000)>>14),(a5) ; Start at ...
	move.w	#(byte)<<8,(VDP_data_port).l ; Fill with byte
loop:	
  move.w	(a5),d1
	btst	#1,d1
	bne.s	loop ; busy loop until the VDP is finished filling...
	move.w	#$8F02,(a5) ; VRAM pointer increment: $0002
	endm


#8 User is offline flamewing 

Posted 18 February 2012 - 06:21 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12

View Postredhotsonic, on 18 February 2012 - 06:19 PM, said:

I'm not sure what you mean. If you mean not to have them to the very left hand side as labels, that's already so:

I meant this:

View Postflamewing, on 18 February 2012 - 04:55 PM, said:

Add these lines to 'Address Error Defs.asm' just under the line with 'make_art_tile':
vdpComm  function  addr,type,rwd,(((type&rwd)&3)<<30)|((addr&$3FFF)<<16)|(((type&rwd)&$FC)<<2)|((addr&$C000)>>14)
; values for the type argument
VRAM = %100001
CRAM = %101011
VSRAM = %100101

; values for the rwd argument
READ = %001100
WRITE = %000111
DMA = %100111



View Postflamewing, on 18 February 2012 - 05:36 PM, said:

Move the vdpComm definition (and the constants below) to right above the dma68kToVDP definition.


#9 User is offline redhotsonic 

Posted 18 February 2012 - 06:34 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
Okay, that's bit is fixed, it passed the first one, 2nd pass, failed. 83 errors. I'm really sorry, I feel like I'm annoying you =P


Here's the errors (spoiler as quite big)

Spoiler


#10 User is offline flamewing 

Posted 18 February 2012 - 06:53 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
Remove the following lines from "Address Error Defs.asm":
EniDec := Eni_Decomp
KosDec := Kos_Decomp
PlaneMapToVRAM := Plane_Map_To_VRAM

and add the following:
Chunk_Table := Metablock_Table

Edit: Also add this:
PlaneMapToVRAM := ShowVDPGraphics

This post has been edited by flamewing: 18 February 2012 - 06:59 PM

#11 User is offline redhotsonic 

Posted 18 February 2012 - 06:58 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
Awesome, almost there:

> > >Address Error.asm(324): error: symbol undefined
> > > PlaneMapToVRAM
> > > 	jsr	(PlaneMapToVRAM).l
> > >Address Error.asm(324): warning: address is not properly aligned
> > > 	jsr	(PlaneMapToVRAM).l
> > >Address Error.asm(324): error: addressing mode not allowed here
> > > 	jsr	(PlaneMapToVRAM).l


I uncommented PlaneMapToVRAM := Plane_Map_To_VRAM but that made more errors.


How I love my disassembly =P
This post has been edited by redhotsonic: 18 February 2012 - 06:59 PM

#12 User is offline flamewing 

Posted 18 February 2012 - 07:00 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
See the edit in my last post; it took me too long to make it :v:

#13 User is offline redhotsonic 

Posted 18 February 2012 - 07:06 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
HOORAY! No more errors! Cheers, mate, greatly appreciated. I know I am a pain in the arse! At least people with the 2007 disassembly can do it too now =P


By doing this again (it always triggers it), I got this:

Posted Image

I've added this picture to my thread.


I might be mistaken, but did you say it generates an error file when this happens? Or am I dreaming? =P

Also, just to let you know, music no longer continues when displaying this screen, not like I give a shit though =P


EDIT: I made it freeze in a different location in a different level, and it was the same error message "move.w (a1)+,d1" but the address read was $FFFFFFFF, so it's this line in my ASM that's causing the touble I guess?


EDIT2: Here's another

Posted Image

It is definately respawn_index. Some objects do NOT respawn when you leave and re-enter the area if you haven't destroyed them. This can happen to badniks, springs, anything. Then when you go to touch where they originally were, BOOM, error. (1st picture error you see).


In the RARE case that it doesn't freeze when you touch their location where they should be, this triggers something else. As soon as you next get hurt, it will freeze. (2nd error picture you see).


Thanks, mate, this has really helped. I will get on to looking at moving respawn_index elsewhere.


To anyone else, I recommend putting this neat feature in your hack.
This post has been edited by redhotsonic: 18 February 2012 - 07:36 PM

#14 User is offline flamewing 

Posted 18 February 2012 - 07:49 PM

  • Elite Hacker
  • Posts: 736
  • Joined: 11-October 10
  • Gender:Male
  • Location:Brasil
  • Project:Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
  • Wiki edits:12
Time now to build the ROM generating the map file (as I mentioned earlier) and use it to find out where the thing that causes the error is. In the first screen, you want to find out what is at address $536B9; unless I am mistaken, $17760 is in BuildSprites (near label 'loc_166CC'), meaning $536B9 is in a mappings file that is located at an odd address. If I am right about the first error, then the second error (reading from $FFFFFFFF in the same line) is caused by an object that either does not have his mappings set, or one that calls DisplaySprite/DisplaySprite2/DisplaySprite3 before calling DeleteObject/DeleteObject2 (the latter possibly being called through MarkObjGone/MarkObjGone2/MarkObjGone3. And yes, I got rid of lots of errors like this in my hack :-)

The third error looks like the start of an object's code; it seems like the routine of the object is being set to an odd value (note d0 is 3). Good luck squashing them all :v:

#15 User is offline redhotsonic 

Posted 18 February 2012 - 08:05 PM

  • Also known as RHS
  • Posts: 1094
  • Joined: 31-January 05
  • Gender:Male
  • Location:United Kingdom
  • Project:Sonic 2 Recreation
  • Wiki edits:24
I built it without putting the "-g MAP" code at first and triggered to get these results. Then adding -g MAP" whilst building again then triggering it in the same place gave me the same results, so I'm not sure what I am meant to do here.


As for you mentioning the markobjgone, that will explain why suddenly they decide not to appear every now and then, and when you run into them, it locks up.


Will give this ago tomorrow as it's 1am now and I can't think anymore =P


Thanks again, mate.

  • 4 Pages +
  • 1
  • 2
  • 3
  • Last ►
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users