Smallest 'Useful' MD ROM

Announce (tech) demos or games releases

Moderator: Mask of Destiny

snkenjoi
Newbie
Posts: 6
Joined: Thu Aug 06, 2009 9:36 am

Smallest 'Useful' MD ROM

Post by snkenjoi » Thu Aug 06, 2009 8:08 pm

First, a little intro.

Some of you will recognise me from Sonic Retro, where I make hacks of the various sonic games. I recently made this 'demo' with stef's devkit that got me interested in spritesmind.

Anyway, I hope you find this an interesting read, it documents my journey to attempt to create the smallest Megadrive ROM that actually does something.

So, first I need some code that does something basic - this is to check that the code actually worked, and that it's relativly small.

The best thing I could think of for this task was to make the screen go green :) The code is a carbon copy from the checksum error routine from 'most' ROMs.

So here is the first revision, with the checksum code pasted after the header I ripped from Sonic 1.

Code: Select all

Vectors:	dc.l $FFFE00, CodeStart, CodeStart, CodeStart; 0
		dc.l CodeStart, CodeStart, CodeStart, CodeStart; 4
		dc.l CodeStart, CodeStart,	CodeStart, CodeStart; 8
		dc.l CodeStart, CodeStart, CodeStart, CodeStart; 12
		dc.l CodeStart, CodeStart, CodeStart, CodeStart; 16
		dc.l CodeStart, CodeStart, CodeStart, CodeStart; 20
		dc.l CodeStart, CodeStart,	CodeStart, CodeStart; 24
		dc.l CodeStart, CodeStart, CodeStart, CodeStart; 28
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 32
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 36
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 40
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 44
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 48
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 52
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 56
		dc.l CodeStart,	CodeStart, CodeStart, CodeStart; 60
Header:		dc.b 'SEGA MEGA DRIVE ' ; Console name
asc_110:	dc.b '(C)SEGA 1991.APR' ; Copyright/Date
DomesticName:	dc.b 'SONIC THE               HEDGEHOG                ' ; Domestic Name
asc_150:	dc.b 'SONIC THE               HEDGEHOG                ' ; International Name
		dc.b 'GM 00001009-00'   ; Version
Checksum:	dc.w $264A		; DATA XREF: ROM:00000332o
					; Checksum
asc_190:	dc.b 'J               ' ; I/O Support
RomStartLoc:	dc.l 0			; ROM Start
RomEndLoc:	dc.l $7FFFF		; DATA XREF: ROM:00000322o
					; ROM End
RamStartLoc:	dc.l $FF0000		; RAM Start
RamEndLoc:	dc.l $FFFFFF		; RAM End
asc_1B0:	dc.b '                                                          ' ; Notes
		dc.b '      '
		dc.b 'JUE             ' ; Country
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

CodeStart:
	move.l	#$C0000000,($C00004).l
	move.w	#$F0,($C00000).l
	bra.s CodeStart
Which comes out to 532 bytes. Which I feel is somewhat bloated. ;)

Now, there is a lot of spare space in the header. How about we try storing the code in there? Then we just have to branch into it and we'll save loads of space.

So, we change CodeStart to this;

Code: Select all

CodeStart:
	bra.s asc_1B0
To insert the code into the header, the machine code is simply assembled and pasted in the corresponding place.

Code: Select all

	move.l	#$C0000000,($C00004).l
	move.w	#$F0,($C00000).l
	jmp $1B0
becomes

Code: Select all

23FCC000000000C0000433FC00F000C000004EF9000001B0
paste this onto the header at $1B0 and we get;

Code: Select all

00000000 00FF FE00 0000 0200 0000 0200 0000 0200 ................
00000010 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000020 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000030 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000040 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000050 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000060 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000070 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000080 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000090 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000A0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000B0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000C0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000D0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000E0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000F0 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000100 5345 4741 204D 4547 4120 4452 4956 4520 SEGA MEGA DRIVE 
00000110 2843 2953 4547 4120 3139 3931 2E41 5052 (C)SEGA 1991.APR
00000120 534F 4E49 4320 5448 4520 2020 2020 2020 SONIC THE       
00000130 2020 2020 2020 2020 4845 4447 4548 4F47         HEDGEHOG
00000140 2020 2020 2020 2020 2020 2020 2020 2020                 
00000150 534F 4E49 4320 5448 4520 2020 2020 2020 SONIC THE       
00000160 2020 2020 2020 2020 4845 4447 4548 4F47         HEDGEHOG
00000170 2020 2020 2020 2020 2020 2020 2020 2020                 
00000180 474D 2030 3030 3031 3030 392D 3030 264A GM 00001009-00&J
00000190 4A20 2020 2020 2020 2020 2020 2020 2020 J               
000001A0 0000 0000 0007 FFFF 00FF 0000 00FF FFFF ................
000001B0 23FC C000 0000 00C0 0004 33FC 00F0 00C0 #.........3.....
000001C0 0000 4EF9 0000 01B0 2020 2020 2020 2020 ..N.....        
000001D0 2020 2020 2020 2020 2020 2020 2020 2020                 
000001E0 2020 2020 2020 2020 2020 2020 2020 2020                 
000001F0 4A55 4520 2020 2020 2020 2020 2020 2020 JUE             
00000200 60AE                                    `.              
514 bytes! Not bad, but if we want to go further than this, we have to learn about the header format.

If you take these bytes from the first line;

00000000 00FF FE00 0000 0200 0000 0200 0000 0200 ................

These point to the location in the ROM where the code starts, we can change this to define a new start location for our code.

So if we change it to say, 0001B0, it'll point to the code in the header and we can remove the trailing branch from the end of the code.

Code: Select all

00000000 00FF FE00 0000 01B0 0000 0200 0000 0200 ................
00000010 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000020 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000030 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000040 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000050 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000060 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000070 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000080 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000090 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000A0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000B0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000C0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000D0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000E0 0000 0200 0000 0200 0000 0200 0000 0200 ................
000000F0 0000 0200 0000 0200 0000 0200 0000 0200 ................
00000100 5345 4741 204D 4547 4120 4452 4956 4520 SEGA MEGA DRIVE 
00000110 2843 2953 4547 4120 3139 3931 2E41 5052 (C)SEGA 1991.APR
00000120 534F 4E49 4320 5448 4520 2020 2020 2020 SONIC THE       
00000130 2020 2020 2020 2020 4845 4447 4548 4F47         HEDGEHOG
00000140 2020 2020 2020 2020 2020 2020 2020 2020                 
00000150 534F 4E49 4320 5448 4520 2020 2020 2020 SONIC THE       
00000160 2020 2020 2020 2020 4845 4447 4548 4F47         HEDGEHOG
00000170 2020 2020 2020 2020 2020 2020 2020 2020                 
00000180 474D 2030 3030 3031 3030 392D 3030 264A GM 00001009-00&J
00000190 4A20 2020 2020 2020 2020 2020 2020 2020 J               
000001A0 0000 0000 0007 FFFF 00FF 0000 00FF FFFF ................
000001B0 23FC C000 0000 00C0 0004 33FC 00F0 00C0 #.........3.....
000001C0 0000 4EF9 0000 01B0 2020 2020 2020 2020 ..N.....        
000001D0 2020 2020 2020 2020 2020 2020 2020 2020                 
000001E0 2020 2020 2020 2020 2020 2020 2020 2020                 
000001F0 4A55 4520 2020 2020 2020 2020 2020 2020 JUE             
512 bytes! We have a ROM that actually does something that is the size of a full MD header. It's worth noting that the only emulator that will run the ROMs from this point is Regen. Surely we can't go smaller than this. Or can we...?

Turns out, a lot of the header isn't required. In fact, most of it - the only *requirement* is the first 8 bytes. So if we set the start of the code to $8... we can just paste our code straight afterwards removing almost the entire header.

Code: Select all

00000000 00FF FE00 0000 0008 23FC C000 0000 00C0 ........#.......
00000010 0004 33FC 00F0 00C0 0000 4EF9 0000 0008 ..3.......N.....
32 bytes! Brilliant! That's much smaller, and it still runs in regen.

Of course, we can remove the last three words to bring it down to 24 bytes, too. I'm told this will break eventually, but it works in regen, so I'm keeping it.

We can't get any smaller than this. It's just not possible.

That's what I thought, until I came up with this dirty trick;

Code: Select all

00000000 4E71 23FC C000 0000 00C0 0004 33FC 00F0 Nq#.........3...
00000010 00C0                                    ..              
18 bytes! Can you see what I did?

Part of the code is used to set the start of the code. A nop (4E71) is added to align it to the correct place and then the code sets the start to $0. This then runs through the code again, ignores the nop, and executes the rest as normal - so the bytes used to set the address of the code are reused as part of the code.

I don't know how well I explained that or if you will understand it. Please ask if you don't get it.

===

From this point I'd pretty much called it a day, there wasn't much more i could do to optimise this any further. I sent the ROMs off to TmEE to find out which ones will run on hardware. Unfortunatly none :(. Well, at least they were running on Regen!

Anyway, after this he sent me the smallest ROM he could think of that runs on hardware. 38 bytes! Apparently, the MD required some VDP initilisation that I overlooked. Here is his code;

Code: Select all

; Smallest possible MD program to run on most hardware

 DC.L   $00FFFE00       ; Default A7, Padding
 DC.L   CodeStart       ; Default PC
CodeStart:
 LEA    $C00004, A0     ; Makes things a little bit more tighter ;)

 MOVE.L #$80148700, (A0) ; Initialize VDP into enough nice state
 MOVE.W #$8134, (A0)
 MOVE.L #$C0000000, (A0)
 MOVE.W #$0FF0, -4(A0)
 BRA.B  CodeStart
Note; this will work on non-TMSS hardware only, TMSS based ROMs have a lower bound and trying to make them small is fairly trivial and uninteresting.

Anyhoo, as you can see the code is pretty compact leaving little room for optimisation. That doesn't mean I didn't try anyway ;)

Here is my final piece of code. With use of the trick I demonstrated before, and a little shifting around of the code, I managed to get it down to 32 bytes. Just trace the execution of this thing, it's beautiful.

Code: Select all

Start:
 bra.s CodeStart
 dc.w   $20BC           ; this and instruction below are executed as;
 dc.l   $C0000000       ; move.l #$C0000000, (a0)
CodeStart:
 move.w #$F0,-4(a0)  ; does nothing the first run through ;)
 lea    $C00004,a0
 move.l #$80148700,(a0)
 move.w #$8134,(a0)
 bra.s Start+2

Code: Select all

00000000 6006 20BC C000 0000 317C 00F0 FFFC 41F9 `. .....1|....A.
00000010 00C0 0004 20BC 8014 8700 30BC 8134 60E2 .... .....0..4`.
download

On a side note, qiuu suggested that the smallest valid ROM (that doesn't do anything) would be 2 bytes long (assuming padding is 00s). bra.s -2 / '60FE'. This actually works in Regen :D

And that's about all I have to say for my first post. Hopefully next time I post a demo, it'll do a more than just this ;)

Shiru
Very interested
Posts: 786
Joined: Sat Apr 07, 2007 3:11 am
Location: Russia, Moscow
Contact:

Post by Shiru » Thu Aug 06, 2009 10:57 pm

This is surely interesting information for 256/512b intro or minigame (1K/2K/4K) creators.

I think, relying for padding zeroes is somewhat wrong, because in the real world if you have, say, 256 byte ROM chip, it will not have zeroes above 256 byte. Instead, it will be repeated throughout whole address space.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Thu Aug 06, 2009 11:02 pm

Most of the exception vectors will never get called, so you could easily use most of that space for code. The rom header should probably be left alone, but you could also stick code or data in the strings of the header.

HardWareMan
Very interested
Posts: 745
Joined: Sat Dec 15, 2007 7:49 am
Location: Kazakhstan, Pavlodar

Post by HardWareMan » Fri Aug 07, 2009 7:05 am

Chinese programmers don't fill required header (except vectors table) and they games run only on chinese MD clones (without TMSS). So, to run your code on MD with TMSS you will need to fill only used vectors and string at $100..$103 (wich contains "SEGA" word, that presence checked by TMSS). All other places can be filled your own data/code.

TascoDLX
Very interested
Posts: 262
Joined: Tue Feb 06, 2007 8:18 pm

Re: Smallest 'Useful' MD ROM

Post by TascoDLX » Fri Aug 07, 2009 7:07 am

snkenjoi wrote:Here is my final piece of code. With use of the trick I demonstrated before, and a little shifting around of the code, I managed to get it down to 32 bytes. Just trace the execution of this thing, it's beautiful.
Nice, but it could be shorter. You get a free register load because of the stack pointer, and you're moving 2 words that you can fit into 1 longword.

Here is 28 bytes:

Code: Select all

Stack:
dc.l   $00C00004         ; a7 = 00C00004
Data:
dc.l   $C0000008         ; pc = Start
Start:
move.l #$87008004,(a7)   ; vdp reg set = 8700, vdp reg set = 8004
move.l Data,(a7)         ; vdp addr set = C0000008 (bit 3 ignored by vdp)
move.l #$0E8E8104,-2(a7) ; vdp data write = 0E8E (pink!), vdp reg set = 8104
Done:
bra.s  Done

Code: Select all

000000 : 00C0 0004 C000 0008 2EBC 8700 8004 2EBA
000010 : FFF4 2F7C 0E8E 8104 FFFE 60FE
Download here

I don't think it can get any shorter.
snkenjoi wrote:It's worth noting that the only emulator that will run the ROMs from this point is Regen.
Fusion works fine (unless you've set it up to use the TMSS BIOS).

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Fri Aug 07, 2009 11:30 am

and TascoDLX pwns everyone :P
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Aug 07, 2009 3:40 pm

That won't work on all Genesis models, so it doesn't count. :P

As stated in another post by HardWareMan, you at least need the "SEGA" in the header or TMSS systems won't accept it.

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Fri Aug 07, 2009 3:43 pm

so you have a 230 byte ROM with lot of nothingness in it :P
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Aug 07, 2009 5:09 pm

260 :P
:lol:

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Fri Aug 07, 2009 5:55 pm

craaap.... I somehow got 226 in my mind..... my brain needs sleep which it has not got for a while :P
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

snkenjoi
Newbie
Posts: 6
Joined: Thu Aug 06, 2009 9:36 am

Re: Smallest 'Useful' MD ROM

Post by snkenjoi » Sat Aug 08, 2009 5:14 pm

Chilly Willy; You didn't read this >:|
snkenjoi wrote:Note; this will work on non-TMSS hardware only, TMSS based ROMs have a lower bound and trying to make them small is fairly trivial and uninteresting.
I know about the TMSS, guys.
TascoDLX wrote:
snkenjoi wrote:It's worth noting that the only emulator that will run the ROMs from this point is Regen.
Fusion works fine (unless you've set it up to use the TMSS BIOS).
I meant for all the non-hardware ROMs, I shoulda clarified.
TascoDLX wrote:

Code: Select all

000000 : 00C0 0004 C000 0008 2EBC 8700 8004 2EBA
000010 : FFF4 2F7C 0E8E 8104 FFFE 60FE
This is brilliant. I really admire your use of the stack pointer.

You might argue the validity of what I'm going to say next, but I believe it counts.

I believe 26 bytes is possible by simply truncating your example to 26. This will cause the game to crash eventually. However, this will not change the graphics on the screen - resulting in the same behaviour as the infinite loop anyway. This leads me to think you can just drop it. Ugly, but it works. (I think?)

Code: Select all

00C00004C00000082EBC870080042EBAFFF42F7C0E8E8104FFFE

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Smallest 'Useful' MD ROM

Post by Chilly Willy » Sat Aug 08, 2009 6:12 pm

snkenjoi wrote:Chilly Willy; You didn't read this >:|
snkenjoi wrote:Note; this will work on non-TMSS hardware only, TMSS based ROMs have a lower bound and trying to make them small is fairly trivial and uninteresting.
Sure I did. That doesn't change my position that unless it works on all (official) models, it doesn't count. It's not so much that the minimum size is 260 bytes as much as what you do with it. Who gives a rat's ass if you can do a "loop: bra loop" demo - I want a tiny demo that really does something (and works on any model). 8)

Without TMSS, the smallest rom possible is always going to be 10 bytes: the reset SSP, the reset PC, and one bra.b opcode. There's nothing special about that. That won't earn anything more than "Noob...". :roll:

You want praise? Make pong in 260 bytes (or something similar).

snkenjoi
Newbie
Posts: 6
Joined: Thu Aug 06, 2009 9:36 am

Post by snkenjoi » Sat Aug 08, 2009 8:03 pm

Maybe it doesn't count in your eyes. That's fine.

But you're still missing the point. Thankfully you don't govern what I can and can't try to do :)

(Besides, it does do something... it detects if you have TMSS or not ;)

I'm not looking for praise, I'm saying "Hi guys, I joined the forum. Here's something cool I did recently that you may find interesting."

You don't have to be such an arse about it :(.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Aug 08, 2009 8:21 pm

Sorry, but "loop: bra loop" demos are LAME, not interesting. You'd have a be a complete noob to think otherwise. Just telling it like it is. :twisted:

And to tell the truth, when someone comes along gushing about how fantastic such things are, yes, I DO have to be an arse about it. :wink:

Feel free to share your "exciting" potty training stories, but don't get mad at me when I laugh and point. :lol:

Shiru
Very interested
Posts: 786
Joined: Sat Apr 07, 2007 3:11 am
Location: Russia, Moscow
Contact:

Post by Shiru » Sat Aug 08, 2009 8:26 pm

If you have real 256 byte ROM, word 'SEGA' probably could be placed at $000, but if it is possible to make the code start somehow after that? I don't know 68K opcodes, what 'SEGA' would be as code?

Post Reply