SNASM2 Debugger vs. Cross Products MegaCD kit

Discussion in 'Sega Discussion' started by Headcrab, Jun 27, 2013.

  1. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Hi all,

    I finally have my SNASM2 and SNSERVER ISA cards fully functioning! Now I'm trying to figure out the debugging process.

    I've successfully built my code with SNASM68K.EXE, outputting a COFF file with debugging info, and the debugger (SNBUG68K.EXE) recognises the debug info and shows me the source code alongside the disassembly (F**K YEAH!). Opening the Memory window shows me some recognisable strings from the binary, so I can assume it's correctly uploaded to the target and is waiting to run.

    Unfortunately, hitting Run (or trying to step over the first line of code) immediately halts the machine and I lose SCSI connectivity. If I don't load my own binary at all, I can successfully run, step through and watch whatever startup code gets loaded on bootup (the MegaCD intro screen and main menu, possibly), so I think the debugger and target are functioning fine, it's just my code isn't suitable.

    A few things from the SNASM2 and MegaCD Development manuals caught my eye:

    SNASM2_Manual_Vectors.png

    MegaCD_Manual_CPUCode1.png

    The appendix shows the mentioned CPU code:

    MegaCD_Manual_CPUCode2.png

    Apologies for the poor scans, my manual is a copy of a copy of a copy, which I then copied.

    So my question is: Where does this code go? The top of the binary is for the header and CPU vector table, and since it halts on the first line there's no way this code would actually run to be able to do anything useful.

    At the moment all of my exceptions/traps/interrupts just point to an empty subroutine which calls RTE.
     
  2. Nemesis

    Nemesis Robust Member

    Joined:
    Mar 22, 2007
    Messages:
    248
    Likes Received:
    79
    I can explain that documentation. Basically, the SNASM system can only "take over" the physical hardware when one of the specified exceptions occur. The dev unit is looking for one of these exceptions to be triggered. This means, in order to properly debug on the hardware, you actually need to have an exception being triggered at a key point in your code, so that you can then drop down into the debugger and examine the current device state, step through code, etc.

    Now, for most games, the exception vectors they list should never occur, and if they do, the game will usually enter some kind of error state, IE, hang, or display an error screen. What that first document is telling you is that not only can your program not do this, you also need to think about deliberately generating one or more of these exceptions at some point, so that the debugger can take control.

    So, what should you do in code? You've got two main options:
    1. Enable trace mode on startup ("ORI #$8000,SR")
    2. At an appropriate point (probably the VINT handler) insert a "TRAP #0" opcode.

    The second option is probably better. Enabling trace mode will slow down program execution significantly, and the trace bit may be cleared by other code later than manually sets the supervisor register contents. In either case, you need to make sure that the exception you use to attach the debugger (either Trap0 or Trace) doesn't cause the program itself to stop running, so just do an RTE instruction for these exceptions.

    The documentation in Appendix A is talking about a MegaCD setup, where you're loading from a CD. In this case, you don't define a vector table yourself, that's defined by the BIOS. To load your program, you've got a fairly complex special CD "header" structure if you will, that the BIOS uses to load an initial program into RAM buffers for the main cpu (the one in the actual Mega Drive console) and the sub cpu (the one in the MegaCD console, usually used to handle CD access). In this scenario, usually the vector table for the main CPU would be write-only, and you couldn't modify it. On the Cross Products dev unit though, the ROM data is actually uploaded into a RAM buffer (a virtual boot ROM), and there's special internal memory addresses you can write to that enable and disable software write protect to these memory addresses. You need to disable write protect, and patch the vector table for the main CPU, to point to some kind of special handler for these exceptions. This handler is probably just doing an RTE too, but they've defined that instruction somewhere in memory for convenience, so you can just include this code block and not have to define a separate label. The sub cpu has a vector table located in RAM too, which is initialized by the BIOS. You need to disable write protect and patch this table too. That's what the supplied code does, and you would need to include this code as one of the first steps in your programs. Once this is done, the same rules apply as with a non-CD based game: you need to generate one of the specified exceptions at regular intervals so that the debugger can gain control.
     
    Last edited: Jun 27, 2013
    dcsw2k7 and l_oliveira like this.
  3. ASSEMbler

    ASSEMbler Administrator Staff Member

    Joined:
    Mar 13, 2004
    Messages:
    19,394
    Likes Received:
    995
    Any chance you can upload the whole manual?
     
  4. Nemesis

    Nemesis Robust Member

    Joined:
    Mar 22, 2007
    Messages:
    248
    Likes Received:
    79
  5. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Yep, the scans were from the SNASM-CD Installation Manual, and the non-MegaCD version of the SNASM2 Development Manual, which doesn't contain anything that the MegaCD version already provides.

    Thanks Nemesis, I'll try those suggestions later. I take it once execution has been started, this "SCSI connectivity lost" behaviour will only happen for the brief period before Trace mode gets enabled, then the debugger reattaches?

    I'm only interested in the Genesis side at the moment, so I'll ignore that MegaCD code.
     
  6. pool7

    pool7 Site Supporter 2014

    Joined:
    Mar 4, 2008
    Messages:
    1,268
    Likes Received:
    134
    Detailed information such as the one provided by Nemesis is the reason I love this community :D
    Thank you!
     
  7. Nemesis

    Nemesis Robust Member

    Joined:
    Mar 22, 2007
    Messages:
    248
    Likes Received:
    79
    I honestly don't know. I own a Cross Products dev unit, but no SNASM card at this point, so I've never been able to use the debugging features. Hopefully the error you're getting is just because no exceptions are being triggered, but it's possible there's something else wrong.
     
  8. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    YESSSS!! It's working :)

    Enabling Trace wasn't enough, it seems some of the code from that MegaCD doc is necessary. I stripped it down and got away with just this:


    MSCSITrap equ 0x108008
    MSCSIExcept equ 0x10800C
    move.b d0, 0x108000 ; Allow write to SNASM RAM
    move.l #0x02<<24+MSCSIExcept, 8+(4*0)
    move.l #0x03<<24+MSCSIExcept, 8+(4*1)
    move.l #0x04<<24+MSCSIExcept, 8+(4*2)
    move.l #0x05<<24+MSCSIExcept, 8+(4*3)
    move.l #0x06<<24+MSCSIExcept, 8+(4*4)
    move.l #0x07<<24+MSCSIExcept, 8+(4*5)
    move.l #0x08<<24+MSCSIExcept, 8+(4*6)
    move.l #0x09<<24+MSCSIExcept, 8+(4*7)
    move.l #MSCSITrap, 0x80
    move.b d0, 0x10F001 ; Write protect SNASM RAM
    ori #0x8000, sr ; Enable TRACE exception


    An educated guess: those two memory locations (0x108008 and 0x10800C) contain some known code on a chip/in the BIOS of the devkit somewhere, which is designed to poke the debugger to give it entry (as per Nemesis' explanation), and the above code write-enables the "ROM inside RAM" to fudge the vector table and pull the old switcharoo on 8 exceptions and TRAP 0.

    If I set a breakpoint on any code after this block, I can step through the disassembly AND MY SOURCE (!!!) and view memory and registers and whatnot. I've uploaded a barebones sample here: http://www.fileden.com/files/2012/3/23/3282359/dbgtest.asm, hopefully someone else can use it as a starting point.

    I finally have a working SEGA Megadrive development kit! This is an absolute game changer for my project, and has been a dream of mine for many many years. Thank you so much to everyone who has helped out so far! I just need to wait for my SCART cable to arrive (I can't see anything!) and I'll get my "Hello World" demo running, then write a blog post of everything I've learned so far.

    Officially the happiest guy in the known universe.
     
    Last edited: Jun 29, 2013
  9. Nemesis

    Nemesis Robust Member

    Joined:
    Mar 22, 2007
    Messages:
    248
    Likes Received:
    79
    Glad to hear it's working! Based on what you've reported, you should also be able to set your exception vector for the trap exception to 0x108008, and the other listed vectors to 0x10800C when compiling the ROM, and get the same result without needing that code block, other than enabling the trace mode that is.
     
  10. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Cheers, I'll give that a shot later
     
  11. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Ok, some new findings:

    Setting the vector addresses directly in the table works great! I've kept the original block, though, since I can neatly wrap it around a #define when I don't want a debug build.

    However... I can't get this Trace exception working (with either method). If I sprinkle all of my code with TRAP #0 I can debug fine (until I leave a large enough gap for the debugger to lose track, then it disconnects) but I was under the impression the Trace exception gets called after every opcode. Is this the case?
    I'm setting up the status register with move.w #0x8000, sr (move instead or ori just to make sure the rest of the bits are cleared) which should give me: Trace ON, exception level 0 (all firing), supervisor mode OFF. It's not working though :(

    I've tried manually registering my own Trace exception handler and sticking TRAP #0 inside but it doesn't seem to get fired. Is there anything else I need to do for Trace to work?
     
  12. RAQ

    RAQ Member

    Joined:
    Nov 11, 2007
    Messages:
    6
    Likes Received:
    1
    Have a try at this:

    MSCSITrap equ 0x108008
    MSCSIExcept equ 0x10800C

    move.b d0, 0x108000 ; Allow write to SNASM RAM
    move.l #0x02<<24+MSCSIExcept, 8+(4*0) ; set BUS ERROR vector
    move.l #0x03<<24+MSCSIExcept, 8+(4*1) ; set ADDRESS ERROR vector
    move.l #0x04<<24+MSCSIExcept, 8+(4*2) ; set ILLEGAL INSTRUCTION vector
    move.l #0x05<<24+MSCSIExcept, 8+(4*3) ; set DIVISION BY ZERO vector
    move.l #0x06<<24+MSCSIExcept, 8+(4*4) ; set CHK vector
    move.l #0x07<<24+MSCSIExcept, 8+(4*5) ; set TRAPV vector
    move.l #0x08<<24+MSCSIExcept, 8+(4*6) ; set PRIVILEGE INSTRUCTION vector
    move.l #0x09<<24+MSCSITrap, 8+(4*7) ; set TRACE vector
    move.l #MSCSITrap, 0x80 ; set TRAP #0 vector
    move.b d0, 0x10F001 ; Write protect SNASM RAM
    ori #0x8000, sr ; Enable TRACE exception


    Now location 0x108008 (MSCSITrap) must contain a jump to the debugger or something similar, while location 0x10800c (MSCSIExcept) must contain a RTE instruction. That explains why TRAP #0 works but trace does not. My theory anyway :)
     
    Last edited: Jul 3, 2013
  13. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    I gave it a go but it didn't make much of a difference. It turns out the Trace exception IS being called, but my debugger wasn't stopping on the breakpoint (perhaps breakpoints inside interrupts is a grey area).

    I'm close to blaming my PC (again) - with the L1 and L2 cache switched off it is unbearably slow, and doing a single step in the debugger needs a few seconds to repopulate the code window and it's at that point I usually lose sync with the target. Maybe it's starving the ISA card of data while it's doing some processing?

    I really need a 486-based machine :(
     
  14. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Been a while (house move, job move, company breakdown, PC parts exploding) but I'm back on track and have news to share.

    I got my hands on an AMD K6 200mhz machine (£5 from a car boot sale!) and re-setup the SNASM2 rig.

    At first I had the same issue - drivers wouldn't load unless I disabled the L1 and L2 caches, but this BIOS has far more options than my old machine so I was able to tinker a bit and get it working with the caches enabled. Here's my findings:

    Problem 1: BIOS

    - Turn off anything mentioning 'shadowing'
    - Set Bus Speed to 7.19mhz or 7.16mhz - this is the biggie, it fixes incompatibilities with old ISA cards, found here: http://www.oldskool.org/guides/oldonnew/cripple
    - Enable ISA Line Buffer

    Problem 2: Debugger setup code in subroutine

    I tried being neat and tidy by shoving the debugger init code (see post #8 above) into a subroutine in another file. I think messing with the vector table in this way fudges something and the return address for the PC gets lost. Inserting it inline with my code worked. I might experiment with an inline 'include' to keep this block out of my nice clean init code.

    Problem 3: The TMSS

    Although polling the machine version returns >1, writing the 'SEGA' TMSS crashes the machine and I lose SCSI connectivity. All other exceptions I've seen handle correctly and just halt the CPU, but this one seems to be a special case. I'll revisit a better way to detect machine version/write TMSS when I get my UMDK (I'll need it running on a retail machine to figure it out).

    Problem 4: Status register

    In my framework init code I set the status register to 0x2700, which disables the trace bit (required for the debugger to poll states). It turns out changing this, even to what I consider the correct value, causes the system to lock up. It's ALWAYS initialised to 0x2700 when starting the machine so I'm just going to leave it be, and hope that's not just a nicety of the devkit/SNASM. Again, I'll waiting for my UMDK to figure out this one.

    Problem 5: Resetting the kit

    There were many resets, since I made many mistakes, but it was only after a while I realised that hitting the OFF switch didn't reset the machine as I'd expect - when turning back on the registers would hold their old values (the Status register was the main problem), some recognisable patterns would still be in RAM, and occasionally it would refuse to accept my binary and shut down the SCSI link. Using the debugger's "Reset Processor" option after turning the machine back on became a worthwhile habit.



    Anyway, I can now properly debug! Still nothing on screen yet, but that's my code and not the fault of the dev environment. I'll post back when I have Hello World!
     
  15. Teancum

    Teancum Intrepid Member

    Joined:
    Aug 2, 2010
    Messages:
    663
    Likes Received:
    5
    Wow thanks for this info! I've been thinking about taking another crack at this and this is just what I need to give it another shot.
     
  16. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    I'd be very interested to see if your TMSS is misbehaving, too.

    Last night I figured out that my DIP switch settings were the cause of the bad value when polling the machine version. I've properly set it to PAL/US and I now get a version of '1', and trying to access the VDP will immediately lock up the machine (as expected).

    However... writing the TMSS also locks it up :(

    Code:
    move.b 0x00A10001, d0 ; Move Megadrive hardware version to d0
    andi.b #0x0F, d0 ; The version is stored in last four bits, so mask it with 0F
    beq @Skip ; If version is equal to 0, skip TMSS signature
    move.l #'SEGA', 0x00A14000 ; Move the string "SEGA" to 0xA14000 <-- locks up!
    @Skip:

    I've verified the header is correct (the machines title is "SEGA GENESIS", with the "SEGA" at location 0x100).

    To check if it's not a problem with the TMSS ROM itself in the machine, I've tried the following:


    • Boot Sonic 1 from cartridge - displays "Produced by or under license from SEGA Enterprises..." message
    • Upload a Sonic 1 ROM using the debugger and set it running - displays the red "checksum error" screen, which is bad, but at least it verifies the TMSS passed and the VDP was able to display some red

    I've also tried copying the TMSS setup code from the Sonic 1 disassembly at SonicRetro.org and turning it into a test ROM, still locks up.


    Running out of ideas. Anyone?
     
  17. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Ok, figured that one out, and it's really obvious now that I think about it.

    Adding to the list:


    Problem 6: You can't single step over the TMSS write

    My educated guess is this: Writing the TMSS string prompts the hardware to load a new ROM to display the "Produced by or under license from SEGA Enterprises..." screen before returning to user code. The process is probably something like:

    • Backup regs
    • Jump PC and run
    • Restore regs
    • Return PC

    This more than likely cuts the trace bit on the status register, so the debugger instructs the machine to "run instruction then halt" then sits and waits for the trace after the op has completed, which will never arrive, causing a deadlock.


    Problem 7: Alignment

    I was getting increasingly worried that after making very subtle changes (adding/removing a palette, putting a new variable in my memory map) I'd end up with spurious results - previously working code would crash with no indication of what's wrong, freezes and lockups all over the show, and I was terrified that it may be the old hardware (temperature of the caps, power issues, dry solder joints, etc). After some messing around I think my problem is alignment, something which has tripped me up in the past but I've managed to solve with a few NOPs, but now's probably the time to educate myself. I have no idea what I'm doing here, my only experience with alignment is from a C side (vector/matrix alignment for hardware float ops, audio data buffers, etc) but I have no idea about PC alignment, why it matters, or what I'm doing wrong to break it. To the internet!
     
  18. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    More:

    (this is now a running log so I can type up a blog post on it all later ;) )


    Problem 8: My initial VDP registers were ass

    "Master System" mode was set for some reason (not picked up by emuators?), CRAM address didn't match what I was writing to, DMA settings were all kinds of wrong. I'll go through every single bit with a fine tooth comb this evening and make sure each one is correct, but for now I've copied them from the Sonic 1 disassembly.


    Problem 9: VRAM needed clearing

    Again, I've been spoiled by emulators and their clean initial state. The CRAM, VRAM and VSRAM were full of junk on startup, I've written some routines to clear them (I'll share in my next blog post).



    So far I can load palettes and change the backdrop colour. My first thing on screen! Getting there slowly :)

    I can't believe how different an experience this has been from working on an emulator. I have a full game written, dammit ;)
     
    Last edited: Sep 16, 2014
  19. erhanpurple

    erhanpurple Active Member

    Joined:
    Sep 19, 2013
    Messages:
    39
    Likes Received:
    1
    I'm following your progress, wonder what will happen :)
     
  20. Headcrab

    Headcrab (BigEvilCorporation)

    Joined:
    Dec 21, 2011
    Messages:
    246
    Likes Received:
    67
    Words cannot describe how happy I am right now :)

    [​IMG]

    Alignment is STILL giving me headaches, this time something is messing with the data alignment, I had to cheat by including my font and palettes above my code (they're all longword sized lines of data) else they'd become garbled. My DrawText routine doesn't seem to be setting the palette right, either, in an emulator the text is coloured.

    I need to strip down my framework piece by piece to figure out what's offsetting it. Either that, or there's some rules about reading from addresses that far down the ROM, is this a thing?

    Anyway, time for some sleep. Tomorrow, Pong! Then a two year overdue blog post ;)

    Thank you SO MUCH to everyone who's helped me in this adventure so far! Finally some real progress!
     
    Last edited: Sep 17, 2014
    Syclopse likes this.
sonicdude10
Draft saved Draft deleted
Insert every image as a...
  1.  0%

Share This Page