PDA

View Full Version : Megadrive and ASM68k - having trouble with absolute basics



Headcrab
12-30-2011, 09:32 AM
Hi,

I'm trying to get a very small sample up and running - not even Hello World, not even initialising the VDP or Z80, just move one register to another - to make sure my toolchain is up to scratch and that my debugger of choice (MESS) is working correctly, but after a few days of trying I haven't had much luck.

Here's my code, it's a mash of different samples and tutorials from all over the net, trimmed down to something which I can start off with:

RomStart:

; ************************************************** ****************
; Sega Megadrive ROM header
; ************************************************** ****************
dc.l 0x00FFE000 ; Initial stack pointer value
dc.l EntryPoint ; Start of program
dc.l Exception ; Bus error
dc.l Exception ; Address error
dc.l Exception ; Illegal instruction
dc.l Exception ; Division by zero
dc.l Exception ; CHK exception
dc.l Exception ; TRAPV exception
dc.l Exception ; Privilege violation
dc.l Exception ; TRACE exception
dc.l Exception ; Line-A emulator
dc.l Exception ; Line-F emulator
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Spurious exception
dc.l Exception ; IRQ level 1
dc.l Exception ; IRQ level 2
dc.l Exception ; IRQ level 3
dc.l HBlankInterrupt ; IRQ level 4 (horizontal retrace interrupt)
dc.l Exception ; IRQ level 5
dc.l VBlankInterrupt ; IRQ level 6 (vertical retrace interrupt)
dc.l Exception ; IRQ level 7
dc.l Exception ; TRAP #00 exception
dc.l Exception ; TRAP #01 exception
dc.l Exception ; TRAP #02 exception
dc.l Exception ; TRAP #03 exception
dc.l Exception ; TRAP #04 exception
dc.l Exception ; TRAP #05 exception
dc.l Exception ; TRAP #06 exception
dc.l Exception ; TRAP #07 exception
dc.l Exception ; TRAP #08 exception
dc.l Exception ; TRAP #09 exception
dc.l Exception ; TRAP #10 exception
dc.l Exception ; TRAP #11 exception
dc.l Exception ; TRAP #12 exception
dc.l Exception ; TRAP #13 exception
dc.l Exception ; TRAP #14 exception
dc.l Exception ; TRAP #15 exception
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)
dc.l Exception ; Unused (reserved)

dc.b "SEGA GENESIS "
dc.b "(C)SEGA 1992.SEP"
dc.b "YOUR GAME HERE "
dc.b "YOUR GAME HERE "
dc.b "GM XXXXXXXX-XX"
dc.w 0
dc.b "J "
dc.l RomStart
dc.l RomEnd-1
dc.l $FF0000
dc.l $FFFFFF
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b "JUE "

; ************************************************** ****************
; Entry Point
; ************************************************** ****************
EntryPoint:
move.l d0, d1 ; Do something
bra EntryPoint ; Do it again

; ************************************************** ****************
; Exception handler
; ************************************************** ****************
Exception:
bra Exception ; Just Loop

; ************************************************** ****************
; Sync interrupts
; ************************************************** ****************
HBlankInterrupt:
rts ; Do nothing

VBlankInterrupt:
rts ; Do nothing

RomEnd:
END

I'm assembling and preparing the BIN using:

C:\>asm68k.exe test2.asm,test2.bin

SN 68k version 2.53

Assembly completed.
0 error(s) from 88 lines in 0.0 seconds

C:\>rompad.exe test2.bin 255 0
Lightning's ROM Padder

C:\>fixheadr.exe test2.bin

Reported Size: 20202020 Reported Checksum: 2047
Size applied: 3FF Checksum Applied: 1C90

and all seems well. ASM68K is my assembler of choice since SNASM68K doesn't run on Windows 7 64 bit. The other two tools are from the Sonic disassembly dump, which included everything needed to assemble, pad and fix the header.

When I open the BIN using MESS and begin debugging, I see some invalid opcodes in the disassembly, and the program will not run:

http://i41.tinypic.com/10h59pd.png

The disassembly doesn't seem to match any of the code I've written, although that may be because I'm just starting out and don't really know what I'm looking for yet.

I'm not sure if it's my code, the build process or the debugger which is at fault, but loading up a Sonic ROM in MESS runs and shows correct debug info.

Any help appreciated!

l_oliveira
12-30-2011, 09:53 AM
Put some NOPs and see if they show up as 4E71 on MAME debugger. If they appear as 714E you're having endian-ness issues. I think MESS will want the ROM byte swapped as that's how MAME take it's ROMs.

Byte Swapped as if it were read from an SEGA MASK ROM I mean. :nod:

Edit, also make sure you set the ENTRY POINT after 0x0001FF. As EVERYTHING before that are vectors for the 68000 CPU, even if they're unused. There's so much room for code, a few bytes won't hurt and will save you from future headaches.

Headcrab
12-30-2011, 10:07 AM
Nail on the head! The NOPs show up as 714E (and way WAY further down the disassembly than I expected).

How would I solve this? Is it as simple as an assembler option to swap the endianness?

Also, how would I tell if my entry point is after 0x0001FF? Do I simply sum up the size of the header (since it's the first line of code after that)?

l_oliveira
12-30-2011, 10:52 AM
Some hex editors (I use winhex for that) can byteswap files.

Your case is 16 bit byteswap. :thumbsup:

For setting the base address for an program, the assembler program has an pseudo instruction ".org 0x<Your desired address here in hexadecimal>".

I suggest you read a bit about macros and pseudo instructions on assembly programs as these work with most assembler programs and they usually are the same regardless what the target CPU is.

Calpis
12-30-2011, 01:14 PM
Byte Swapped as if it were read from an SEGA MASK ROM I mean. :nod:
All 16-bit ROMs can be little-endian or big-endian depending on which the the programmer software chooses, not the physical ROM layout. Little-endian is the true/logical endian and what most device programmers default to so this is just more MAME crew craziness.

Headcrab
12-30-2011, 03:33 PM
Ok, I've given it a shot word-swapping the whole file (with HHD Software's Hex Editor Neo), and the results still aren't as expected - it runs the following instructions in a loop:

http://i41.tinypic.com/or19jr.png

I've tried loading it up using Gens (with the KMod plugin) and RetroDrive but I get the same results both with and without the endian swapping, so I'm not entirely certain that it's MESS to blame. Gens correctly displays the 'YOUR GAME HERE' title, so at least it's read the ROM correctly.

Adding .org to offset the start of the code didn't seem to change anything either, but I'll leave it in since your recommendation makes perfect sense.

I don't suppose anybody has a working sample which assembles using ASM68K for me to test? It doesn't need to do anything fancy, just increment a register in a loop or something. Once I'm over that hurdle the rest should roll easier.

l_oliveira
12-30-2011, 11:21 PM
Can you upload your binary file somewhere for me to have a little look ?

Headcrab
12-31-2011, 10:10 AM
Sure: http://www.filesend.net/download.php?f=e21272be5dcc2031e21f4888602ce429

Kjell
12-31-2011, 10:41 AM
The first 15 bytes of your ROM contain junk.

http://i.imgur.com/UtoGZ.png

Once you delete those, your ROM seems to work fine.

http://i.imgur.com/IZK8R.png

http://i.imgur.com/IVz3m.png

You probably want to take a look at the manual of your assembler.

Jorge Nuno
12-31-2011, 11:01 AM
A reset vector of 0x000001FF is totally not fine, it must be an even address

Headcrab
12-31-2011, 12:11 PM
The first 15 bytes of your ROM contain junk.


Perfect! That works! Thank you so much. May I ask which debugger you're using? That screenshot looks pretty fully-fledged.



A reset vector of 0x000001FF is totally not fine, it must be an even address


Doesn't that mean the line of code after the .org starts at byte 512? That sounds reasonable to me unless I'm missing something.

Kjell
12-31-2011, 12:28 PM
May I ask which debugger you're using?

Regen (http://aamirm.hacking-cult.org/regen/Regen0972D.zip)


Doesn't that mean the line of code after the .org starts at byte 512?

If you want your code to start at byte 512, you need to use "org 0x200" instead of "org 0x1FF".

l_oliveira
12-31-2011, 01:16 PM
Headcrab, when I said 0x0001FF I meant that was the last byte of the 68000 vector area. So yes, two things you need to observe:

1- Because 68000 uses 16bit instruction encoding, it's alignment is 16 bit based, which means it will only fetch instructions from even addresses.

If you try to jump on an odd address it will trigger an "Address Error" exception and everything will freeze (there's no vector setup for error handling, right ? lol)...

2- 68000 does not have an A0 line so it can only see the memory as one 16bit device. When you need to use byte instructions (it has support for that and it's treated as an special case) the chip has special pins to signal that kind of memory access... :thumbsup:

Good to see that you're progressing. It's the first step, learn how to use the tools. :nod:


Edit:

Forgot to say this:

Do mind the subtle details. Now you saw why I said "after 0x0001FF"...

Headcrab
12-31-2011, 01:41 PM
1- Because 68000 uses 16bit instruction encoding, it's alignment is 16 bit based, which means it will only fetch instructions from even addresses.


Thanks, that makes sense. Coming from C to Assembly is quite awkward, where I only have to deal with alignment and the likes when dealing with very low level stuff.



If you try to jump on an odd address it will trigger an "Address Error" exception and everything will freeze (there's no vector setup for error handling, right ? lol)...


I intend to properly handle each error type as soon as I figure out what information I should be fetching to deal with the situation (or how to display the errors on screen, if the CPU isn't left in a confused state after the error). On Xbox, Wii and PS3 we have the luxury of displaying errors on screen inside an exception handler, is this a common practice on platforms of this era or should I limit it to a STOP op and rely on the debugger?



Do mind the subtle details. Now you saw why I said "after 0x0001FF"...

Indeed, this was just my head going foggy, of course I need 0x200 to begin on byte 512.


Thanks for the help all! I'll see what those extra bytes are and figure out how to stop my assembler putting them in. MESS seems quite happy with a file of that endianness, by the way.

Now to initialise the thing and get a pixel on screen!

l_oliveira
12-31-2011, 02:17 PM
About error handling, it could be something super simple as just making it reset/restart or something like this :
https://lh4.googleusercontent.com/-It9pKI1sbV8/S5-w1X6rUWI/AAAAAAAACKs/bsUJ9pXWLv0/s800/TV2010031513061000.jpg
(Pocket Fighter, Capcom 1997 CPS2/68000)

or this
https://lh5.googleusercontent.com/-CCDrTKA7p54/TcvUoxWib4I/AAAAAAAADg8/vybpV4ch3vE/s800/stop_version3.jpg
(Street Fighter Zero 3, 1998 Capcom CPS2/68000)

Headcrab
02-04-2012, 06:32 AM
Well, after many weeks of typing away, reading articles and tearing my hair out, I finally have Hello World up and running! Thanks to everyone here who helped!

http://www.mediafire.com/?o27lnohcco53i2o

Here it is for critique, or in the hope that somebody else starting out finds it useful. It's by no means the fastest code in the world, I've sacrificed a lot of optimisations for code readability, and I've dissected some of the confusing bits from other samples and broken them down. Rather than load a table of registers to the 68k from the beginning, I load destination addresses as and when I need them, to group relative code together.

I have some questions:

1. Originally, to help me better understand how addressing the VDP works, I scrapped use of the AutoIncrement register and manually incremented addresses myself after each copy. For copying the palette, this worked a treat - I copy two bytes, I increment the address by two bytes - but for copying the tiles it all went wrong. However many bytes I incremented my address by after copying a longword, my tiles were garbled, and I had to rely on setting AutoIncrement to 2 to solve this, but I can't figure it out. What exactly does AutoIncrement increment, and by how much? How would I do the same operation manually?

2. VDP addressing still confuses me. I've read and understand how to break down an address using the 'RRAA AAAA AAAA AAAA ---- ---- RRRR --AA' pattern, and I found a tool here (http://megadrive.org/~elbarto/md/vdp/) to help me with the job, but the results didn't seem to work. To copy a tile to the VDP, I've been writing 0x40000000 to the VDP command port, as decribed in Marc's Realm (http://darkdust.net/writings/megadrive), but if I use the calculated address using that tool, I end up with 0x40000011 for a VSRAM write, which makes sense looking at the pattern but it doesn't work. Why?

3. How could I animate a tile? I'd like to computationally edit a tile (perhaps increment some of the colour IDs), would I edit the data live (i.e., move the changed longword lines to the correct address in VRAM) or would I keep a tile in main RAM to modify, and at regular intervals copy it to an unused area on the VDP and set the new tile ID (a double-buffered approach)?

4. I still can't figure out what those first 15 bytes of my ROM are, I've been manually deleting them in a HEX editor. Does anyone else here use ASM68k? Any success stories? I can't find any relevant documentation. Even the Sonic2 disassemblies are set up to use ASM68k, yet I haven't found any mention of this problem anywhere else.

Thanks in advance!

Jorge Nuno
02-04-2012, 04:15 PM
Well, after many weeks of typing away, reading articles and tearing my hair out, I finally have Hello World up and running! Thanks to everyone here who helped!

http://www.mediafire.com/?o27lnohcco53i2o

Here it is for critique, or in the hope that somebody else starting out finds it useful. It's by no means the fastest code in the world, I've sacrificed a lot of optimisations for code readability, and I've dissected some of the confusing bits from other samples and broken them down. Rather than load a table of registers to the 68k from the beginning, I load destination addresses as and when I need them, to group relative code together.

I have some questions:

1. Originally, to help me better understand how addressing the VDP works, I scrapped use of the AutoIncrement register and manually incremented addresses myself after each copy. For copying the palette, this worked a treat - I copy two bytes, I increment the address by two bytes - but for copying the tiles it all went wrong. However many bytes I incremented my address by after copying a longword, my tiles were garbled, and I had to rely on setting AutoIncrement to 2 to solve this, but I can't figure it out. What exactly does AutoIncrement increment, and by how much? How would I do the same operation manually?

The 68000 utilizes a 16bit bus, meaning that a longword write will cause 2 sequential 16bit accesses, in this case the first to 0xC00000 and the second one to 0xC00002. With the auto increment set to 2, the VDP will add 2 to the internal VRAM address 2 times.

If you setup the auto increment to 0, you cannot write a longword to the VDP, I think. Both 16bit halves would be written to same address.

For word writes it's equivalent: the VDP incrementing by 2 or you doing it manually...


2. VDP addressing still confuses me. I've read and understand how to break down an address using the 'RRAA AAAA AAAA AAAA ---- ---- RRRR --AA' pattern, and I found a tool here (http://megadrive.org/%7Eelbarto/md/vdp/) to help me with the job, but the results didn't seem to work. To copy a tile to the VDP, I've been writing 0x40000000 to the VDP command port, as decribed in Marc's Realm (http://darkdust.net/writings/megadrive), but if I use the calculated address using that tool, I end up with 0x40000011 for a VSRAM write, which makes sense looking at the pattern but it doesn't work. Why?

0x40000011 in binary is 0100 0000 0000 0000 0000 0000 0001 0001..
You may want a 0x40000003 for VRAM 0xC000...

3. How could I animate a tile? I'd like to computationally edit a tile (perhaps increment some of the colour IDs), would I edit the data live (i.e., move the changed longword lines to the correct address in VRAM) or would I keep a tile in main RAM to modify, and at regular intervals copy it to an unused area on the VDP and set the new tile ID (a double-buffered approach)?

Your choice, you can build your tiles on RAM without having to rely on the VDP access setup/slowdowns or you can build a buffer in RAM and do a transfer to the VDP on the VBI (using DMA or not)

4. I still can't figure out what those first 15 bytes of my ROM are, I've been manually deleting them in a HEX editor. Does anyone else here use ASM68k? Any success stories? I can't find any relevant documentation. Even the Sonic2 disassemblies are set up to use ASM68k, yet I haven't found any mention of this problem anywhere else.

IIRC S2 has an extra tool that converts s2.p in s2.bin, you may want to look into that..

Thanks in advance!

Replied in the quote :)

Headcrab
02-05-2012, 09:32 AM
The 68000 utilizes a 16bit bus ...
If you setup the auto increment to 0, you cannot write a longword to the VDP, I think. Both 16bit halves would be written to same address.


Ah that explains a few things that have been gong wrong, then. Makes perfect sense! Now that I understand how writing to the ports work, I'll just be using autoincrement anyway. Doing it manually was purely an educational exercise.



0x40000011 in binary is 0100 0000 0000 0000 0000 0000 0001 0001..
You may want a 0x40000003 for VRAM 0xC000...


My VDP registers are set up as 0xC000 for Plane A, 0xE000 for plane B, and 0xD400 for the sprite attr. table. So to write this data I should use addresses 0x40000003, 0x60000003 and 0x54000003 respectively, correct?

Which addresses should I use to write palette data and pattern data? I've been using 0xC0000000 and 0x40000000, but only through example - I can't find a list of the VDP's various addresses (which aren't set by the user via registers).



Your choice, you can build your tiles on RAM without having to rely on the VDP access setup/slowdowns or you can build a buffer in RAM and do a transfer to the VDP on the VBI (using DMA or not)


I'll experiment with these after I have a working sprite. I quite like the animated background tiles in the Sonic 2 multiplayer results screen, and wanted to achieve something similar as a starting point.



IIRC S2 has an extra tool that converts s2.p in s2.bin, you may want to look into that.


I'll have a look.

Thanks for the answers, much appreciated!

Kjell
02-05-2012, 11:02 AM
I still can't figure out what those first 15 bytes of my ROM are, I've been manually deleting them in a HEX editor.
Hmm, pretty sure I send you a PM regarding this a month ago .. anyway, did you use the "/p" option of ASM68K?

Headcrab
02-05-2012, 12:11 PM
Hmm, pretty sure I send you a PM regarding this a month ago .. anyway, did you use the "/p" option of ASM68K?

I had no idea I had a PM! Just checked, and yes thank you, that worked.

Is there a way to turn on email notifications for PMs?

Jorge Nuno
02-05-2012, 12:56 PM
the VDP has 64kB of VRAM, so everything not used by the sprite table, the Hscroll data, PlaneA and B tables is free for the tile generator. In your case from 0 to BFFF and some free spots between the tables.

You can check the VRAM utilisation on regen's VDP debugger (also gens)

segaloco
02-08-2012, 12:15 AM
I noticed all the problems up above with there being junk data the beginning of the file. Simple simple fix. Stick a /p in the commandline for asm68k. Output's a Pure binary rather than whatever format asm68k outputs for the accessory programs that are part of the PsyQ set for MegaDrive.

Headcrab
02-08-2012, 04:21 AM
Output's a Pure binary rather than whatever format asm68k outputs for the accessory programs that are part of the PsyQ set for MegaDrive.

Ahh I see, some sort of metadata for the debugger, I presume?