(Sonic 1 Github): How to Turn on and Take Advantage of the 32x

Discussion in 'Tutorials' started by Red2010 is now, Jan 16, 2024.

Tags:
?

Do you want more sonic hacks that use the 32x?

  1. Yes

    6 vote(s)
    85.7%
  2. No

    1 vote(s)
    14.3%
  1. Red2010 is now

    Red2010 is now Active Member Member

    Joined:
    Apr 24, 2023
    Messages:
    32
    Location:
    Somewhere in Spain
    This is my first guide so you can tell me any errors in the comments :p

    Attention: This guide was built based on the AS branch of github but I don't doubt that it works on asm68k. (Except the part of turning on the pwm with the clone driver but we'll get to that)

    I have not seen anyone who has made a competent guide to turning on and taking advantage of the 32x

    If you have that strange desire to do a Sonic hack on the 32x, then this is your guide to transfer it to that system

    Question 1.Turn on the 32x:

    Well, to turn on the 32x in your disassembly we must first get a donor disassembly to turn on the 32x

    In this case it will be the disassembly of: If you already had this disassembly based on the hiverbrain code on your computer collecting dust, it's time to put it to use.

    First we will copy the "mars" folder from the donor disassembly to our disassembly

    Now we will place under:
    Code:
        include    "Macros.asm"
    This:
    Code:
            include "mars/init.asm"
    Now we will copy another code, this time for the game to start I guess

    The code is the following:
    Code:
    EntryPoint:
            tst.l    ($A10008).l    ; test port A control
            bne.s    PortA_Ok
            tst.w    ($A1000C).l    ; test port C control
    
    PortA_Ok:
            bne.s    PortC_Ok
            lea    SetupValues(pc),a5
            movem.w    (a5)+,d5-d7
            movem.l    (a5)+,a0-a4
            move.b    -$10FF(a1),d0    ; get hardware version
            andi.b    #$F,d0
            beq.s    SkipSecurity
            move.l    #'SEGA',$2F00(a1)
    
    SkipSecurity:
            move.w    (a4),d0        ; check    if VDP works
            moveq    #0,d0
            movea.l    d0,a6
            move.l    a6,usp        ; set usp to $0
            moveq    #$17,d1
    
    VDPInitLoop:
            move.b    (a5)+,d5    ; add $8000 to value
            move.w    d5,(a4)        ; move value to    VDP register
            add.w    d7,d5        ; next register
            dbf    d1,VDPInitLoop
            move.l    (a5)+,(a4)
            move.w    d0,(a3)        ; clear    the screen
            move.w    d7,(a1)        ; stop the Z80
            move.w    d7,(a2)        ; reset    the Z80
    
    WaitForZ80:
            btst    d0,(a1)        ; has the Z80 stopped?
            bne.s    WaitForZ80    ; if not, branch
            moveq    #$25,d2
    
    Z80InitLoop:
            move.b    (a5)+,(a0)+
            dbf    d2,Z80InitLoop
            move.w    d0,(a2)
            move.w    d0,(a1)        ; start    the Z80
            move.w    d7,(a2)        ; reset    the Z80
    
    ClrRAMLoop:
            move.l    d0,-(a6)
            dbf    d6,ClrRAMLoop    ; clear    the entire RAM
            move.l    (a5)+,(a4)    ; set VDP display mode and increment
            move.l    (a5)+,(a4)    ; set VDP to CRAM write
            moveq    #$1F,d3
    
    ClrCRAMLoop:
            move.l    d0,(a3)
            dbf    d3,ClrCRAMLoop    ; clear    the CRAM
            move.l    (a5)+,(a4)
            moveq    #$13,d4
    
    ClrVDPStuff:
            move.l    d0,(a3)
            dbf    d4,ClrVDPStuff
            moveq    #3,d5
    
    PSGInitLoop:
            move.b    (a5)+,$11(a3)    ; reset    the PSG
            dbf    d5,PSGInitLoop
            move.w    d0,(a2)
            movem.l    (a6),d0-a6    ; clear    all registers
            move    #$2700,sr    ; set the sr
    
    PortC_Ok:
            bra.s    GameProgram
    ; ===========================================================================
    SetupValues:    dc.w $8000        ; XREF: PortA_Ok
            dc.w $3FFF
            dc.w $100
    
            dc.l $A00000        ; start    of Z80 RAM
            dc.l $A11100        ; Z80 bus request
            dc.l $A11200        ; Z80 reset
            dc.l $C00000
            dc.l $C00004        ; address for VDP registers
    
            dc.b 4,    $14, $30, $3C    ; values for VDP registers
            dc.b 7,    $6C, 0,    0
            dc.b 0,    0, $FF,    0
            dc.b $81, $37, 0, 1
            dc.b 1,    0, 0, $FF
            dc.b $FF, 0, 0,    $80
    
            dc.l $40000080
    
            dc.b $AF, 1, $D9, $1F, $11, $27, 0, $21, $26, 0, $F9, $77 ; Z80    instructions
            dc.b $ED, $B0, $DD, $E1, $FD, $E1, $ED,    $47, $ED, $4F
            dc.b $D1, $E1, $F1, 8, $D9, $C1, $D1, $E1, $F1,    $F9, $F3
            dc.b $ED, $56, $36, $E9, $E9
    
            dc.w $8104        ; value    for VDP    display    mode
            dc.w $8F02        ; value    for VDP    increment
            dc.l $C0000000        ; value    for CRAM write mode
            dc.l $40000010
    
            dc.b $9F, $BF, $DF, $FF    ; values for PSG channel volumes
    ; ===========================================================================
    
    GameProgram:
    ;         tst.w    ($C00004).l
    ;         btst    #6,($A1000D).l
    ;         beq.s    CheckSumCheck
    ;         cmpi.l    #'init',($FFFFFFFC).w ; has checksum routine already run?
    ;         beq.w    GameInit    ; if yes, branch
    ;
    ; CheckSumCheck:
    ;         movea.l    #ErrorTrap,a0    ; start    checking bytes after the header    ($200)
    ;         movea.l    #RomEndLoc,a1    ; stop at end of ROM
    ;         move.l    (a1),d0
    ;         moveq    #0,d1
    ;
    ; loc_32C:
    ;         add.w    (a0)+,d1
    ;         cmp.l    a0,d0
    ;         bcc.s    loc_32C
    ;         movea.l    #Checksum,a1    ; read the checksum
    ;         cmp.w    (a1),d1        ; compare correct checksum to the one in ROM
    ;         bne.w    CheckSumError    ; if they don't match, branch
    ;         lea    ($FFFFFE00).w,a6
    ;         moveq    #0,d7
    ;         move.w    #$7F,d6
    ;
    ; loc_348:
    ;         move.l    d7,(a6)+
    ;         dbf    d6,loc_348
    ;         move.b    ($A10001).l,d0
    ;         andi.b    #$C0,d0
    ;         move.b    d0,($FFFFFFF8).w
    ;         move.l    #'init',($FFFFFFFC).w ; set flag so checksum won't be run again
    
             lea    ($FFFF0000),a0
             move.w    #$3F7F,d0
    @ClrRam:
             clr.l    (a0)+
             dbf    d0,@ClrRam
    
            bsr.w    VDPSetupGame
            bsr.w    SoundDriverLoad
            bsr.w    JoypadInit
            move.b    #0,($FFFFF600).w ; set Game Mode to Sega Screen
    
    MainGameLoop:
            move.b    ($FFFFF600).w,d0 ; load    Game Mode
            andi.w    #$1C,d0
            jsr    GameModeArray(pc,d0.w) ; jump to apt location in ROM
            bra.s    MainGameLoop
    That code in hiverbrain has almost the same names on github. But for those who get lost a lot, copy all that from "EntryPoint" to "MainGameLoop"

    Note: Replace any "@" with a "." if you are an AS user

    Let's go down to just before "EndOfRom". Just before that we paste this:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; MARS BANK starts here
    ; ---------------------------------------------------------------------------
     
             obj *+marsbank
             dc.b "DATA GOES HERE"
               objend
     
            cnop 0,$8000
     
    ; ===========================================================================
    
    SH2_Start:
            incbin    "mars/sh2/code.bin"
    SH2_End:
            cnop 0,4


    Note (Again, why not?): If you are an AS user, change the "incbin" to "binclude"
    PD: Delete the "obj *+marsbank" and "objend" since it didn't work for me and I had to cut those two lines, if you are an AS user of course

    What follows is to adapt the code to github

    In this case I would skip it but some find it very confusing to follow this guide without clarifying at all times what to do.


    just replace this in "init.asm":
    Code:
    PalToCRAM = HBlank
    loc_B10 = VBlank
    in mars.i (which can be opened with whatever notepad you have on hand)..replaces:
    Code:
    * = ;

    And if there is any "SoundDriverLoad" that is not from your own routine in sonic.asm replace it with "DacDriverLoad" (clone driver users can skip this)

    Now you can compile the game without problems. The first thing you will see before even seeing the Sega screen will be this image:
    [​IMG]

    Yes, I was just as traumatized as you when I saw it for the first time.

    Now the fades, flat colors and others will be replaced by the image. Unless you are a user of the clone driver or know where to modify the code, you will not be able to get rid of the image.

    But you have officially ported your hack on 32x

    From here For the rest of the guide you can withdraw since this involves Clownacy's Clone Driver, so if you are someone who is not going to switch to this sound driver or an asm68k user, you can withdraw.

    Question 2. Activating the pwm:

    Well, this will be a bit long but we require two things, the Stub SH2 and the PWM Driver. Both are included with the clownacy sound driver so you shouldn't worry too much.


    The first thing is to eliminate the following code if you have just updated the clone driver with this (you can skip it if you already have it beforehand):
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; MARS BANK starts here
    ; ---------------------------------------------------------------------------
     
             obj *+marsbank
             dc.b "DATA GOES HERE"
               objend
     
            cnop 0,$8000
     
    ; ===========================================================================
    
    SH2_Start:
            incbin    "mars/sh2/code.bin"
    SH2_End:
            cnop 0,4
    This is because the Stub SH2 already comes with this one code, so this no longer works for us.

    Well, below the line that we put to start the 32x (init.asm) we will put:
    Code:
    include "youfolderwhereyouhavethestub/Stub 32x.asm"
    Well now fix the "includes" of "Stub32x.asm" because they are necessary files for the PWM

    Now we have to import the PWM controller itself so we go to where the clone driver installation guide advises us to put the soundriver and below that line we put:
    Code:
    include "yourfolder/PWM Driver.asm"
    You fix the addresses of that file and of "PWM Samples.asm" so that there are no problems

    Well, if you have followed the guide up to this point, it is time to change the "init.asm" again.

    Replace these lines:
    Code:
            dc.l MasterStart+$120                ; Master SH2 initial PC
            dc.l SlaveStart+$120                ; Slave SH2 initial PC
            dc.l MasterStart                ; Master SH2 initial VBR address
            dc.l SlaveStart                    ; Slave SH2 intitial VBR address
    with:
    Code:
             dc.l SH2_Entry           ; Master SH2 initial PC
                 dc.l s_EntryPoint         ; Slave SH2 initial PC
                 dc.l SH2_Master           ; Master SH2 initial VBR address
                 dc.l SH2_Slave           ; Slave SH2 intitial VBR address
    The last thing we should do is go to "settings.asm" and look for the PWM variable...we change the 0 to a 1 and it is time to compil.
    [​IMG]

    Wow, I didn't expect it. Luckily MainMemory already offered me the solution in the past.

    Simply change the "Moveq" to "Move.l" and problem solved

    Compile and you should see no relevant changes. It will be time to bring in those Musics!.

    After deciding on one of the music you have with the pwm, compile it and it should be sounding correctly and identical to chaotix. Now enjoy your new music

    Wow..That was longer than I expected, for a medium short guide it was a bit long

    I suppose that in addition to a cookie you will have the 32x at your disposal. Well I guess goodbye

    Credits:

    Me: The one who discovered and wrote this

    Clownacy: Creator of the Sonic 2 clone driver 2.0

    Gardeguey: Code used from his disassembly to make it possible to move to 32x and activate the pwm

    MainMemory: Build Solution

    Known issues:

    The level selector is deactivated after following the entire guide (no solution yet)
    Update: I discovered that the level selector does not stop working, but rather that its code changes to that of the Japanese version. I discovered it late but what difference does it make :)

    02/25/24 Edit: I realized that all the images I had used in my previous posts had fallen...So I had to restore this guide with other links

    Update 03/22/24: Once again all the images from my old posts went down...I have been restoring them all morning with another image hosting site...But with this Post the images are already restored once again!
     
    Last edited: Mar 22, 2024
    Clownacy likes this.
  2. Devon

    Devon I'm a loser, baby, so why don't you kill me? Member

    Joined:
    Aug 26, 2013
    Messages:
    1,376
    Location:
    your mom
    I do appreciate your efforts to delve into this stuff, but unfortunately, I wouldn't consider this a good guide on getting the 32X activated. It fails to mention fundamental things like how memory mapping works on the 32X, the extra "vector table" that's required for when the 32X is activated, the MARS initialization block, and SH-2 program metadata... or really anything regarding the SH-2s at all. This guide really just haphazardly shoves in another disassembly's code and the Clone Driver without too much thought about the overall structure.

    Memory mapping on the 32X is very much a thing to look out for, because when the 32X gets activated, the ROM mapping goes from the first 4 MiB of m68k memory to 2 different sections in the 32X's own memory (1 that's a fixed 512 KiB bank and the other is a swappable 1 MiB bank). There's also the fact that you need to temporarily deactivate the 32X if you want to do things like perform VDP DMAs from ROM, or else the 32X will interfere with it (it takes priority over the m68k), which involves more memory map fuckery.

    I do understand if you just got overwhelmed from that one part alone; the 32X is a very fucky beast that messes with things, and as such, it requires a different way of thinking your approach to the code and data's structure, and also added knowledge about how the SH-2 side works, which is its own rabbit hole. Honestly, you might as well just use Gardeguey's disassembly as a basis from the start and port the Clone Driver into it for the use case that this guide is trying to go for.

    Again, I do applaud you for trying this out and wanting to provide a resource. I do encourage you to look further into this stuff and get to know the hardware and how to properly tackle it. Though, personally, I wouldn't recommend 32X programming to a beginner, just due to how complex and messy it can be. Would be better to first learn the Genesis hardware and some general low level programming stuff properly, and *then* tackle the 32X.
     
    Last edited: Jan 16, 2024
    Stdh, Pacca, ProjectFM and 2 others like this.
  3. Red2010 is now

    Red2010 is now Active Member Member

    Joined:
    Apr 24, 2023
    Messages:
    32
    Location:
    Somewhere in Spain
    Currently the 32x hacking is raw.. And although I am not entirely happy with using another base disassembly for this, this is what I had... I would have specified other things but simply. It's a crappy guide and now