Rivet
Member
- Messages
- 26
Way back in March, a discord user by the name of PinoBatch was making programs on various consoles that displayed the Ukrainian Flag by setting the top half of the screen blue and the bottom half yellow. I noticed that he hadn't made a Genesis version yet, so I figured it could be a neat challenge to see how small of a rom I could make. The first version I made with the help of Jorge and Tails8521 was a measly 128 bytes. Though, I wasn't content with the size, so I contacted a friend and got to work.
Here's the entire program in it's confusing glory:
Things may seem a bit odd at first, so let's explain each trick one by one:
TMSS:
Without this the program would be way smaller, but we want to support as many consoles as possible. Some later Genesis models (due to a court case) include a Trade Mark Security System that will not enable the VDP until it sees "SEGA" at $100 in ROM and "SEGA" has been written to $A14000. If you look at the top of the program you'll notice that where the stack pointer would usually be set in the vector table, there is now text that reads "SEGA". Since out program is smaller than $100 we can't physically place the text at that address, though we can take advantage of ROM Mirroring. This means that if our ROM is the correct size (we want powers of 2), the Genesis can see our small program repeated up until the end of where it can see a normal ROM. Putting "SEGA" at the very start of our rom will have it mirrored all the way to $100 and way past if needed.
Something that I didn't know before doing this was that you can move values directly into the CCR. Genesis models that do not have TMSS unfortunately don't like having "SEGA" written to $A14000 and will crash since that address doesn't exist on them. So to check if we need to write the text we move the hardware version directly into the CCR. From there it's just a matter of finding which branch matches up. In this case it was BCC. If it is a TMSS compatible console, we move the stack pointer (set to "SEGA") into the TMSS register.
Setting up the VDP:
After we've set up TMSS (or not, if necessary) there's still some things that we need to do before we can properly display anything on screen.
Here we set the console to the Genesis' color and video mode, clear auto increment (Everdrive flash carts leave this set), set the control port to the start of CRAM, then increment the control port address by 4 bytes to make it point to the HV counter. Usually when setting the VDP control port to the start of CRAM we want to use a whole longword ($C0000000) but here we take advantage of the fact that each VDP port is 16 bits wide. When sending a longword to the VDP control or data port, the other half will go to a mirror (In the control port's case, $C00006 which will contain zero).
Displaying the flag:
Now that we have everything ready with our very minimal setup, we can start displaying things to the screen!
First we start by sending the color blue to the VDP data port mirror. Right under where we do our TMSS setting and checking we copied the control port address we sent to a1 into a0. That was done so we can take advantage of pre-decrement here. So before blue is written to the address in a0, it's decremented down to $C00002 then written. After this we wait till the HV counter tells us that the TV beam has reached the middle scanline of the screen and we write the color yellow to the data port mirror. Here we increment the address in a0 so that the register stays set to $C00002 forever while the program is running.
There are many ways this program can be optimized, but this is the best that we could figure out at the time. I would like to thank Jorge, Tails8521, and Rændom all for helping me squish this program down as much as we could! I'm excited to see any possible ways that this program could be made smaller and still work on the console.
Squishing the program into 64 bytes
Here's the entire program in it's confusing glory:
Code:
; ---------------------------------------------------------------------------------------
; Vector Table
dc.l "SEGA", CPUStart
; ---------------------------------------------------------------------------------------
; Main Program
CPUStart:
move.w $A10000, ccr ;Test Hardware version
bcc.s @Skip ;"
move.l sp, $A14000 ;Write "SEGA" to TMSS
@Skip:
lea $C00004, a1 ;VDPControl
lea (a1), a0 ;Clone of VDPControl
move.l #$80048F00, (a1) ;Genesis Colors, Auto Inc = 0
move.l #$8104C000, (a1)+ ;Genesis Mode, Set Control to CRAM, Set A1 to HV Counter
MainLoop:
move.w #$0E00, -(a0) ;$0E00 Blue
@NotYet1:
cmp.b #112, (a1)
bne.s @NotYet1
move.w #$00EE, (a0)+ ;$00EE Yellow
@NotYet2:
cmp.b #240, (a1)
bne.s @NotYet2
bra.s MainLoop
; ---------------------------------------------------------------------------------------
TMSS:
Without this the program would be way smaller, but we want to support as many consoles as possible. Some later Genesis models (due to a court case) include a Trade Mark Security System that will not enable the VDP until it sees "SEGA" at $100 in ROM and "SEGA" has been written to $A14000. If you look at the top of the program you'll notice that where the stack pointer would usually be set in the vector table, there is now text that reads "SEGA". Since out program is smaller than $100 we can't physically place the text at that address, though we can take advantage of ROM Mirroring. This means that if our ROM is the correct size (we want powers of 2), the Genesis can see our small program repeated up until the end of where it can see a normal ROM. Putting "SEGA" at the very start of our rom will have it mirrored all the way to $100 and way past if needed.
Code:
move.w $A10000, ccr ;Test Hardware version
bcc.s @Skip ;"
move.l sp, $A14000 ;Write "SEGA" to TMSS
@Skip:
Setting up the VDP:
After we've set up TMSS (or not, if necessary) there's still some things that we need to do before we can properly display anything on screen.
Code:
move.l #$80048F00, (a1) ;Genesis Colors, Auto Inc = 0
move.l #$8104C000, (a1)+ ;Genesis Mode, Set Control to CRAM, Set A1 to HV Counter
Displaying the flag:
Now that we have everything ready with our very minimal setup, we can start displaying things to the screen!
Code:
MainLoop:
move.w #$0E00, -(a0) ;$0E00 Blue
@NotYet1:
cmp.b #112, (a1)
bne.s @NotYet1
move.w #$00EE, (a0)+ ;$00EE Yellow
@NotYet2:
cmp.b #240, (a1)
bne.s @NotYet2
bra.s MainLoop
Conclusion
There are many ways this program can be optimized, but this is the best that we could figure out at the time. I would like to thank Jorge, Tails8521, and Rændom all for helping me squish this program down as much as we could! I'm excited to see any possible ways that this program could be made smaller and still work on the console.Attachments
Last edited: