Some Sega/Mega CD questions

Rivet

Member
Messages
26
Recently I've been getting back into programming for the Sega CD and I figured I should ask some questions I missed last time before I continue

What's going on with PRG-RAM?
I can't seem to find details on what's in PRG-RAM and where. I know the SP is in there as well as the Sub-CPU's vector table but I don't know where they all are and what else is in there. I was able to find this map in the BIOS manual but it still leaves me somewhat confused.
1644783785712.png

What about the Main-CPU?
I'm guessing that it's just loaded to the top of Main-CPU RAM. I know the Main-CPUs vector table is at $FFFFFD00 onward. Is there anything else I should worry about?

And to finish off!
I've been using a base that Luke Usher made (https://github.com/LukeUsher/ProjectCD) and in his SP he has a few routines to load files and initialize things. He uses BIOS_ROMREADN to retrieve the data and has a label at the bottom named SectorBuffer and says not to put any code past there. I'm confused what's going on with his code, and does that mean I have to avoid putting stuff 2kb past that label in PRG-RAM? Here's the code if anyone can help:
Code:
; =======================================================================================
;  ReadCD
;  Input: d0.l    start sector
;      d1.l    sectors to read
;      a0.l    destination
; =======================================================================================
ReadCD:
        push    d0-d7/a0-a6        ; Store all registers
        lea    BiosPacket(pc), a5    ; Load bios packet
        move.l    d0, (a5)        ; Write start sector to packet
        move.l    d1, 4(a5)        ; Write size to packet
        move.l    a0, 8(a5)        ; Write destination to packet
        movea.l    a5, a0            ; Put packet to a0 (for BIOS)
        BIOS_CDCSTOP            ; Stop CDC
        BIOS_ROMREADN            ; Begin data read
@waitSTAT:
        BIOS_CDCSTAT            ; Check CDC status
        bcs    @waitSTAT        ; If not ready, branch
@waitREAD:
        BIOS_CDCREAD            ; Read data
        bcc    @waitREAD        ; If not done, branch
@WaitTransfer:
        movea.l    8(a5), a0        ; Get destination address
        lea    12(a5), a1        ; Get header
        BIOS_CDCTRN            ; Transfer sector
        bcc    @waitTransfer        ; If not done, branch
        BIOS_CDCACK            ; Acknowledge transfer
        addq.l    #1, (a5)        ; Increment starting sector
        addi.l    #$0800, 8(a5)        ; Increment destination address
        subq.l    #1, 4(a5)        ; Decrement sectors left
        bne    @waitSTAT        ; If not finished, branch
        pop    d0-d7/a0-a6        ; Restore all registers
        rts                ; Return

       
; =======================================================================================
;  BiosPacket
;  Stores paramaters for BIOS calls
; =======================================================================================

BiosPacket:
    dc.l    0, 0, 0, 0, 0
Header:
    ds.l    32
   
; =======================================================================================
;  ISO9660 Driver
; =======================================================================================
Init9660:
        push    d0-d7/a0-a6        ; Store all registers

                        ; Load Volume VolumeDescriptor

        move.l    #$10, d0        ; Start Sector
        move.l  #2, d1            ; Size in sector
        lea.l    SectorBuffer, a0    ; Destination
        bsr    ReadCD            ; Read Data

                        ; Load Root Directory

        lea.l    SectorBuffer,a0        ; Get pointer to sector buffer
        lea.l    156(a0),a1        ; Get root directory record
       
        move.b    6(a1),d0        ; Get first part of Sector address
        lsl.l    #8,d0            ; bitshift
        move.b    7(a1),d0        ; Get next part of sector address
        lsl.l    #8,d0            ; bitshift
        move.b    8(a1),d0        ; get next part of sector address
        lsl.l    #8,d0            ; bitshift
        move.b    9(a1),d0        ; get final part of sector address.
                        ; d0 now contains start sector address
                       
        move.l    #$20, d1        ; Size ($20 Sectors)
        bsr    ReadCD
       
        pop    d0-d7/a0-a6        ; Restore all registers       
        rts
       
; =======================================================================================
;  Find File (ISO9660)
;  Input:  a0.l - Pointer to filename
;  Output: d0.l - Start sector
;       d1.l - Filesize
; =======================================================================================
FindFile:
        push    a1/a2/a6        ; Store used registers
        lea.l    SectorBuffer,a1        ; Get sector buffer
@ReadFilenameStart:
        movea.l    a0,a6            ; Store filename pointer
        move.b    (a6)+,d0        ; Read character from filename
@findFirstChar:
        movea.l    a1,a2            ; Store Sector buffer pointer
        cmp.b    (a1)+,d0        ; Compare with first letter of filename and increment
        bne.b    @findFirstChar        ; If not matched, branch
@checkChars:
        move.b    (a6)+,d0        ; Read next charactor of filename and increment
        beq    @getInfo        ; If all characters were matched, branch           
        cmp.b    (a1)+,d0        ; Else, check next character
        bne.b    @ReadFilenameStart    ; If not matched, find next file
        bra.b    @checkChars        ; else, check next character
   
@getInfo:
        sub.l    #33,a2            ; Move to beginning of directory entry
        move.b    6(a2),d0        ; Get first part of Sector address
        lsl.l    #8,d0            ; bitshift
        move.b    7(a2),d0        ; Get next part of sector address
        lsl.l    #8,d0            ; bitshift
        move.b    8(a2),d0        ; get next part of sector address
        lsl.l    #8,d0            ; bitshift
        move.b    9(a2),d0        ; get final part of sector address.
                        ; d0 now contains start sector address

        move.b    14(a2),d1        ; Same as above, but for FileSize
        lsl.l    #8,d1
        move.b    15(a2),d1
        lsl.l    #8,d1
        move.b    16(a2),d1
        lsl.l    #8,d1
        move.b    17(a2),d1
                       
        lsr.l    #8,d1            ; Bitshift filesize (to get sector count)
        lsr.l    #3,d1
   
        pop    a1/a2/a6        ; Restore used registers   
        rts

; =======================================================================================
; ANY CODE PAST THIS POINT WILL BE OVERWRITTEN AT RUNTIME AND IS USED AS A READ BUFFER
; Any and all additions to this Sub-Program must be added BEFORE the definition of this
; memory area
; =======================================================================================       
SectorBuffer:
        dc.l 0

Any help is appreciated!
 
Solution
In brief:

1) PRG-RAM structure is roughly what's there on the page. Vector, CDBIOS ID, and CD System Program are all from the BIOS, and handle initialization of the hardware and setup for the rest of the functionality of the BIOS, including the BIOS calls. Work, Heap Stack, and Common Work are RAM spaces that are set aside by the BIOS to do its work and manipulate data. Jump table is basically a series of jump functions that handle directing the BIOS calls to their appropriate internal functions within the BIOS, allowing for the BIOS to be modified with later iterations, and still provide compatibility with older titles.

The User Header and User Program are the initial SP payload that is loaded from the CD after the IP payload. The...
In brief:

1) PRG-RAM structure is roughly what's there on the page. Vector, CDBIOS ID, and CD System Program are all from the BIOS, and handle initialization of the hardware and setup for the rest of the functionality of the BIOS, including the BIOS calls. Work, Heap Stack, and Common Work are RAM spaces that are set aside by the BIOS to do its work and manipulate data. Jump table is basically a series of jump functions that handle directing the BIOS calls to their appropriate internal functions within the BIOS, allowing for the BIOS to be modified with later iterations, and still provide compatibility with older titles.

The User Header and User Program are the initial SP payload that is loaded from the CD after the IP payload. The size of that is user-defined, and pretty much everything from User Header onward is user-defined aside from needing to keep to a few rules for the User Header to make sure the BIOS communicates with the payload properly. What you can do with the remaining space is quite literally up to you, and the PRG-RAM window works in $20000-byte windows. Easy to overthink what's going on there.

2) Other than that area from $FFFD00 onward, there's usually not much more to worry about, that I can think of off-hand. If you're working clean-slate in particular, I can't think of anything system-wise that is stored there.

3) What Luke Usher's doing is using that area labeled "SectorBuffer" as a scratch RAM area where sectors can be loaded and buffered before being moved to the intended place. Remember, with the MegaCD, just about everywhere is RAM. He's using what he considers to be "unused space" in his code as a buffer to load sectors and find a specified file name provided as part of the FindFile call. Not really truly "right" or "wrong" here, just how Luke Usher chose to approach this, and a bit sensible given use of the ISO9660 standard for format.

Hope that clarifies.
 
Upvote 1
Solution
I hadn't seen that image till recently so I was thinking that he was just loading sectors en masse into who knows where in PRG-RAM. At least now I know I won't have to worry much. Everything seems more straightforward than I would have expected. Thank you for clarifying. Last note, I'm guessing that when the manual refers to "one frame worth of data" it means one sector?
 
Upvote 0
Generally, yes, frame would be sector. "Frame" as a terminology is generally used more on the audio side of the format, where you have timecode frames (sectors) and channel frames. The distinctions get a bit in the weeds, obviously, but digging more into CD raw data formatting helps with clarification on some of this.

Yeah, for as obtuse as the MegaCD is treated, a lot of it really is straightforward after getting through the initial walls of intimidation and different-ness. Some persistence and push for exploration and experimentation can get you a long way with it.
 
Upvote 0
Back
Top