Initializing Sega CD in Mode 1

Discussion in 'Technical Discussion' started by theocas, Nov 14, 2011.

Thread Status:
Not open for further replies.
  1. theocas

    theocas

    Tech Member
    346
    0
    16
    I'm working on a little Sega CD backup RAM cart that features a flash memory that will allow one to manage the memory on the cart. When a switch is selected, the cart will boot to that flash memory. The flash memory contains some utilities to manage the RAM and use your Sega CD's hardware.

    The Sega CD has this convenient feature called Mode 1, which lets code run from a regular Mega Drive cartridge, but make use of the Sega CD's additional hardware.

    To really be able to access the Sega CD hardware, one needs to initialize the hardware and load the BIOS. How would I go about doing this? The documentation isn't very specific and only lists steps to take.

    The only other software that I know of that uses the Sega CD in Mode 1 is Flux, a music visualizer. I've attempted to disassemble parts of it, but without much success so I still haven't been able to find the code to do this.

    Any help would be greatly appreciated!
     
  2. sasuke

    sasuke

    Member
    66
    0
    0
    I did disassemble Flux once, and I discovered that it loaded the SUB-CPU BIOS from the boot ROM. It checks the BIOS version from the ROM, and decompresses it (using Kosinski Compression) from one of two locations, 0x415800 if it is US/Euro BIOS 1, and 0x416000 otherwise. It then loads a SUB-CPU program with a header similar to one loaded with a CD (though it is slightly obfuscated in Flux's code, not that it is required).

    I hope this helps.

    P. S. Also, when looking at the BIOS's with a hex editor, I also noticed the Laseractive BIOS's have the code in 0x40D500, which isn't checked by Flux.
     
  3. theocas

    theocas

    Tech Member
    346
    0
    16
    The location from which it decompresses the BIOS shouldn't really matter - the BIOS is (for some odd reason) split into 3 parts, which go in the order of 3, 1, 2, if I remember. Maybe this is to prevent hacking of the BIOS - I have absolutely no idea. The BIOS is always loaded to bank 0 of the Sub-CPU program RAM while the Main CPU has the Sub-CPU's bus and the Sub-CPU has reset de-asserted.
     
  4. sasuke

    sasuke

    Member
    66
    0
    0
    I actually meant that different versions of the BIOS have these parts in different locations and Flux only uses the first part of the BIOS. The second and third part of the BIOS are actually used for the boot sequence BGM and the CD Player controls. Your user program is loaded where the second part of the BIOS is loaded: at location $426000, with a "MAIN" header like a SUB-CPU program on the SEGA CD.

    Your code looks good so far, neglecting parts one and two of the BIOS. Like I said: load the first part of the BIOS into the SUB-CPU at $420000, your program at $426000, and then reset the SUB-CPU.

    Nice. :)
    You can see the code I am talking about at locations sub_15f6 and loc_14b8. In sub_15f6, notice how it sets the Kosinski source to $415800 if either of the byte patterns in $15b6 and $15d6 match the location in the a0 register. That is the BIOS ROM header signatures for the version 1 US and Europe headers respectively. Also, the second subroutine loads Flux's user program with the first 42 bytes being obfuscated as negative words, and the others (at $1a88) are verbatim.
     
  5. theocas

    theocas

    Tech Member
    346
    0
    16
    Thanks for the response.

    The CDX BIOS files don't seem to have a Sub-BIOS I can find whatsoever, which I find odd. I've already gotten my Sub-CPU program to load, but I can't seem to talk to my main CPU and have that do anything. Right now, it compares the first long in the Sub-CPU (w/o) to Main-CPU (r/o) memory with the ASCII string "INIT" and keeps looping until it gets that. My Sub-CPU program obviously writes that to that location, but they can't seem to work. This is my Sub-CPU code:

    Code (ASM):
    1.  
    2. SPHeader:
    3.     dc.b    'MAIN        '                          ; Module name
    4.     dc.w    $0100, 0                                ; Version, type
    5.     dc.l    $00000000                               ; pointer to next module
    6.     dc.l    SPEnd-SPHeader                          ; Module size
    7.     dc.l    $20                                     ; Module start address
    8.     dc.l    $00000000                               ; Work RAM size
    9.     dc.b    0                                       ; End mark
    10.     even
    11.    
    12.     include "cdbios.inc"
    13.    
    14. SPInit:
    15.         move.l  #"INIT", $FF8020                    ; Tell the main CPU we've initialized.
    16.        
    17.         moveq   #0, d0                              ; Clear d0
    18.         move.w  #LEDSET, d0                         ; Function number to d0
    19.         moveq   #0, d1                              ; Clear d1
    20.         move.w  #$0004, d1                          ; Blink both LEDs
    21.         jsr     _cdbios                 ; Jump into BIOS
    22.        
    23. MainLoop:
    24.  
    25.         bra.w   MainLoop                            ; Keep looping the main loop of death.
    26.    
    27. SPEnd:
    28.     END
    29.  
     
  6. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    It's at 0x16807.
     
  7. theocas

    theocas

    Tech Member
    346
    0
    16
    Is it also Kosinski compressed? It doesn't seem to have that Kosinski header, so maybe it uses some other form of compression? The Sub-BIOS is incredibly bitchy and doesn't want to run my Sub-CPU code, so I still need to figure that out, as well as from what CPU I can call into the BIOS.

    (The BIOS apparently is still 'stealing' my CPU since the drive does go into standby after a while. Maybe I forgot to set some register/gate array/comms RAM?)
     
  8. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    It might be a slightly different form of kos as it looks MOSTLY the same, but not identical to the older BIOSes. Just to make sure we're talking about the same rom, the location I found was in the US CDX v2.21 rom.

    Only the Sub-CPU can call the CDBIOS. What kind of header are you using for the code? There restrictions on what you can use for the strings, for example. The main Sub-CPU code header MUST start with "MAIN". A version 1 header would look like this

    Code (Text):
    1. SPHeader:
    2.         .asciz  "MAIN-SUBCPU"
    3.         .word   0x0001,0x0000
    4.         .long   0x00000000
    5.         .long   0x00000000
    6.         .long   SPHeaderOffsets-SPHeader
    7.         .long   0x00000000
    8.  
    9. SPHeaderOffsets:
    10.         .word   SPInit-SPHeaderOffsets
    11.         .word   SPMain-SPHeaderOffsets
    12.         .word   SPInt2-SPHeaderOffsets
    13.         .word   SPNull-SPHeaderOffsets
    14.         .word   0x0000
    15.  
    SPInit is called via jsr with the vblank int off; SPMain won't be called until after you return from SPInit. SPMain is also called via jsr, but with the vblank enabled. SPInt2 is called via jsr once vblank ints are enabled. SPNull is a user vector that's not called by the BIOS. All this is on the Sub-CPU.
     
  9. Sik

    Sik

    Sik is pronounced as "seek", not as "sick". Tech Member
    6,719
    0
    0
    being an asshole =P
    Eww, hardcoded addresses, really? =/

    Also what does Wonder Library do? (though I tried disassembling it once only to find there's a freaking bug when initializing the MCD hardware - it writes to $A120001 instead of $A12001)
     
  10. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    Err - I clearly wasn't thinking straight when I looked for the BIOS before... I was looking at the data from 0x16000 in the v1 BIOS when looking for the same data in the CDX BIOS. The data I needed to be looking for was at 0x15800 in the v1 BIOS... and that exact same data is at 0x16000 in the CDX BIOS... you can even see the copyright message in the data.

    [​IMG]
     
  11. theocas

    theocas

    Tech Member
    346
    0
    16
    I changed the header to what you suggested, but my code still doesn't exactly seem to work. It compiles, but it just won't run, and my main CPU is stuck in an initialization loop, where it waits for the Sub-CPU to write to Comms RAM.

    This is an except from my program:
    Code (ASM):
    1.  
    2. SPHeader:
    3.         dc.b   'MAIN-SUBCPU'
    4.         dc.w   $0001, $0000
    5.         dc.l   $00000000
    6.         dc.l   $00000000
    7.         dc.l   SPHeaderOffsets-SPHeader
    8.         dc.l   $00000000
    9.  
    10. SPHeaderOffsets:
    11.         dc.w   SPInit-SPHeaderOffsets
    12.         dc.w   SPMain-SPHeaderOffsets
    13.         dc.w   SPNull-SPHeaderOffsets
    14.         dc.w   SPNull-SPHeaderOffsets
    15.         dc.w   $0000
    16.         even
    17. ....
    18.  
    19. SPInit:
    20.         move.w  #$002, d1                           ; Load the LED status to d1
    21.         BIOS_LEDSET                                 ; Call into BIOS
    22.         ....
    23.  
    I defined SPNull as a simple rts at the bottom of my file, as well as SPInt2. I'm hoping the fact that I just do an rts in the level 2 interrupt routine doesn't screw stuff up, since probably the sub-BIOS runs code there to back up registers, etc and calls it with a jsr. I still can't get my code to run at all (the LEDs do not change as they should) and I'm slowly running out of ideas as to why this is happening. My last guess (and probably most likely) is that the BIOS never even calls my code for some really strange reason.

    Any ideas?

    Edit:
    Huh, odd. The dumps I have here are probably bad dumps then. Or I was just looking at the wrong file, yet again.
     
  12. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    Code (Text):
    1. dc.b   'MAIN-SUBCPU',0
    The string must be exactly 12 bytes long and should be zero padded. If it's not 12 long, the rest of the struct is off. Notice my code used .asciz - that's a zero-terminated string operative. The ending 0 is implicit. I probably should have called attention to that. Sorry. :(
     
  13. theocas

    theocas

    Tech Member
    346
    0
    16
    No problem - I should have probably invested some more thought into that than just replacing things randomly. Quite oddly, I still am unable to get this to work. Any ideas what could be causing this oddity of mine? I still can't get both the red and green LED to light up (which is what I call in my SPInit) routine.

    Could it be, quite simply, that I'm not loading my Sub-CPU code to the right place? I'm loading it to $426000 in the Main CPU's memory map, which is $6000 in the Sub-CPU program RAM. I set everything to bank 1, and it's actually just writing it right after the Sega CD BIOS. Odd.
     
  14. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    Bank 1, or bank 0? Banks go from 0 to 3, not 1 to 4.
     
  15. theocas

    theocas

    Tech Member
    346
    0
    16
    Erm, I meant bank 0. I tried loading the uncompressed program to the MCD - no difference. Maybe we should move this conversation to Skype/IRC/etc or something?
     
  16. Chilly Willy

    Chilly Willy

    Tech Member
    746
    0
    0
    Doom 32X
    Looking at the disassembly here: http://www.megadrive.org/~elbarto/md/scdstuff/SEGACD.ASM

    It seems that one of the things the CD BIOS does is wait on the INT2 after it inits but before it does the loaded code. Does your test generate INT2 to the CD in the vblank handler of the main CPU?
     
  17. theocas

    theocas

    Tech Member
    346
    0
    16
    Right now I'm calling this right after I give the Sub-CPU back the bus and release it from reset, and after clear the comms RAM:
    Code (ASM):
    1.  
    2.         bset    #8, $A12000                         ; Generate an interrupt
    3.  
    Would this be enough time to allow the Sub-BIOS to initialize? Is there some time estimate on that? I assume I could just run nop's for like 32k cycles, but meh.
     
  18. theocas

    theocas

    Tech Member
    346
    0
    16
    Thanks for everyone's help - Eventually I was able to figure out my issues with the help of Chilly Willy over Google talk.
     
Thread Status:
Not open for further replies.