The Sega Master System/Game Gear/Coleco Music Format ---------------------------------------------------- By Kevin Horton 10/21/03 - Revision 1.00 11/05/09 - Revision 2.00, finalized filename extention and a few other things 11/07/09 - Revision 2.10, fleshed out some things 12/30/09 - Revusion 2.50, Release version ------ This is a proposal for a ripped music format supporting the Sega Master System, Game Gear, and Colecovision, and possibly others. If you're familiar with the .GBS Gameboy music format, this will look fairly similar to that. I have named it .SGC for "SMS, GG, CV". The ordering of the systems is somewhat arbitrary, and I googled for various iterations of the same letters. .SGC came up the winner. As for the format itself, it borrows heavily from the .GBS Gameboy music format, and the NSF format. Turns out, there's ALOT of systems that include a Z80 CPU and an SN76489 for sound. I can think of five right off the bat: Sega Master System, Game Gear, Colecovision, MSX, and the SG1000/3000 systems by Sega. So far, I have outlined support for three of these systems. I need additional help to implement the SGxxxx stuff, and possibly any other systems I missed. MSX is specifically left out, since there's a decent MSX format already. That MSX format theoretically could handle SMS/GG/Coleco/SG1000 but it's ill-suited for that task IMO, being designed mainly for MSX' banking and memory layouts. The header is the same for all three currently supported systems, but the address decoding and a few other things change depending on which system is being emulated. Without further ado, here is the header layout: --------- Here's what you need to emulate for each system: BIOS ROM | Z80 | mapper | YM2413 --------------------------------- SMS | X X X GG | X X CV | X X (Incidentally, the Sega mapper chip's part number is 315-5426). ----- 00h-03h STRING - "SGC",1Ah 04h BYTE - version. Currently 01h 05h BYTE - PAL/NTSC flag. 00h = NTSC, 01h = PAL 06h BYTE - # of scanlines between interrupts, 00h = not used. NOTE: DO NOT USE THIS yet. It is being reserved for this purpose. 07h BYTE - reserved 08h,09h WORD - Start address of data in ROM space 0ah,0bh WORD - Init address 0ch,0dh WORD - Play address 0eh,0fh WORD - Stack pointer 10h,11h WORD - reserved 12h-1fh WORD*7 - RST 08h through RST 38h pointers 20h-23h BYTE - Program words for the mapper chip, 20h = fffch, 21h = fffdh, etc. 24h BYTE - Start song 25h BYTE - Total songs 26h BYTE - starting number for the first sound effect 27h BYTE - ending number for the last sound effect 28h BYTE - system type 29h-3fh BYTE - reserved 40h-5fh STRING - Null terminated song name string 60h-7fh STRING - Null terminated song author string 80h-9fh STRING - Null terminated copyright string a0h-EOF BYTE - the actual music/data code. NOTE: All words are little endian, meaning the LSB is FIRST. ----- OK, a bit of explaination. 00h-03h - this is the identification. It lets a player know what type of file this is. 04h - version # (currently only version 1 is recognized) 05h - NTSC/PAL flag. 0 = NTSC, 1 = PAL. This changes the CPU clock and the frame interrupt rate. 06h - Do not use this yet. It will be used later IF it is required. Please let me know if this functionality is needed! 07h, etc - Reserved bytes: Make sure these are set to 00h. DO NOT use these for anything else! It may break future tunes!! You have been warned! 08h, 09h - Start address. This specifies in memory where the ROM data was ripped from. Note: addresses must start at 0400h or higher. 0ah, 0bh - init address. Load the accumulator with the desired song # (0 = song 1, 1 = song 2, etc) and then call this address. It MUST end with an RET. 0ch, 0dh - Play address. Call this periodically to get music. It should be called 50 times a second for PAL, 60 times a second for NTSC. It must end with an RET. 0eh, 0fh - Stack pointer. You need to spec a stack pointer to prevent over-writing stuff, depending on where RAM variables are at. Ideally it should be placed where the game had it originally. 10h, 11h - not used at the moment.. it is here to fill the "hole" at RST 00h 12h- 1fh - RST pointers. Put the address of the normal RST xx handler here. I.e. if RST 08h had "JMP 04000h" in it, use 4000h at 12h. (NOTE: The RST pointers are NOT USED on the Colecovision tunes, since they are vectored through the BIOS). 20h- 23h - Mapper Chip bytes. (SMS/GG only) Use this to pre-configure the mapper. (see farther down for more info) If you do not use the mapper, and wish to have a "flat" address space from 00400h to 0bfffh, be sure to load it with these values: 20h - 00h 21h - 00h 22h - 01h 23h - 02h 24h - Start song. This is the first song that is run on loading. 25h - Total songs. 26h - First sound effect. This is the entry # for the first sound effect. NOTE: it can and most likely WILL be larger than the total number of songs. (I will explain this in a short section below) 27h - Last sound effect. 28h - System type. 00h = SMS 01h = GG 02h = Colecovision 03h and higher - not used yet. 29h- 3fh - Reserved. Maintain at 00h 40h- 5fh 60h- 7fh 80h- 9fh - Null terminated strings for song name, author, and copyright respectively. If the string is 32 bytes, no terminator is needed. a0h - your music data goes here. ----------------- System memory maps: SMS/GG: ------- First, a word about the SMS/GG memory mapper. This is the stock memory mapper as found on the game cartridges. It was very suitable for this purpose, and almost every game used the same mapper. Thus, it is good enough for our purposes. This mapper sits in memory and is accessable through four memory addresses. These are FFFC through FFFF. They are fully decoded and are not mirrored, and do not appear anywhere else in memory. fffch - Control register (this is the 315-5426 mapper chip, almost) bits: 7 - not used 6 - not used 5 - not used 4 - not used 3 - RAM/ROM select 0 = ROM in bank 2, 1 = RAM in bank 2 2 - not used* 1 - not used 0 - not used NOTE: *- the RAM page select was removed. It is not needed. fffdh - Page 0 select, select a 16K page. fffeh - Page 1 select, select a 16K page. ffffh - Page 2 select, select a 16K page. The SMS/GG memory map: 00000h-003FFh : Unbankable, unswitchable ROM. This is always the first 1K of the ROM area. This lets you drop in a player stub for easier playback on *real* hardware and actual SMS/GG consoles. 00400h-03FFFh : ROM bank 0 04000h-07FFFh : ROM bank 1 08000h-0BFFFh : ROM bank 2 (or another 16K RAM bank) 0C000h-0DFFFh : RAM 0E000h-0FFFFh : Mirror of RAM at C000-DFFF 0FFFCh : mapper register 0 (see above) 0FFFDh : mapper register 1 0FFFEh : mapper register 2 0FFFFh : mapper register 3 The IO map between the SMS and GG are very similar. 006h : Gamegear stereo control port (GG only) 07Eh,07Fh : SN76489 sound chip IO port (both) 090h,091h : YM2413 sound chip IO port (SMS only) When in GG mode, you should disable the YM2413, and likewise when in SMS mode, you should disable the GG's stereo control port. Colecovision: ------------- 00000h-01FFFh : BIOS ROM (the Coleco's BIOS, which is usually named coleco.bin) 02000h-05FFFh : unused (you can put a player stub in here if you wish. That is what I ended up doing) 06000h-07FFFh : 1K of RAM, mirrored 8 times 08000h-0FFFFh : ROM area where music data will be found. There's no bankswitching on the Colecovision. IO map: 0e0h - 0ffh : SN76489 sound chip IO port NOTE: There's no mapper registers to load, and the RST xxxh pointers do not need to be loaded, since the BIOS vectors them through the cartridge ROM area! ----------------------- Now here is how you load, initialize, and play a song. SMS/GG loading: --------------- 1) allocate a chunk of memory to hold the music data. 4Mbytes is a good amount simply because that is the maximum file size- there are 256 banks of 16K each which ends up being 4Mbytes. Clear the first 48K of this buffer (0000h-bfffh). 2) Load the music data in starting at its load address. So, if the music loads in at 3000h, load it starting at 3000h in the buffer, until EOF. 3) If you wish to play on hardware, or to make your code simpler, you can load a player stub in at 00000-03ffh at this time. 4) Set up the bankswitching registers. Load the four bytes from the header and write them to FFFCh-FFFFh. (see below for more about this bankswitching) 5) Clear system RAM at C000-DFFF. 6) Set up your stack pointer from the SP value in the header. 7) Run the music initialization routine, with the desired song # in the accumulator. 8) Call the play address at 50Hz or 60Hz depending on the header's PAL/NTSC rate bit. Colecovision loading: --------------------- 1) Allocate a 64K chunk of memory to hold the music data + RAM + BIOS ROM. 2) Clear all 64K of this memory. Load the Colecovision BIOS ROM at 0000-1FFFh. This is required by most tunes. 3) Load the music data in as specified by the header. It must be in the range of 8000-FFFF. 4) Set up the stack pointer from the value in the header. 5) Load song # in the accimulator, and call the initialization routine. 6) Call the play address at 50/60 Hz as specified in the header. ----- About song and SFX numbering: Let's imagine we have the following list of tunes and SFX: 000h - first song 001h - second song 002h - third song 003h - first sound effect 004h - second sound effect 005h - last sound effect The first song is always 000h, regardless of the tune. The number of songs specifies how many there are, which is 3. Since the SFX are after the music, the start SFX number is 003h, and the end SFX number is 005h. Because you can specify the starting and ending SFX number, they don't have to be directly after the music... So, you can have something like this: 000h - first song 001h - second song 002h - third song 040h - first sound effect 041h - second sound effect 042h - last sound effect So as before, the number of songs is 3, but the start SFX number is now 40h and the end SFX number is now 42h. Tips on use: ------------ The first 1K is reserved (SMS/GG) so that player code can be written and plugged in here to play the tunes on real hardware. There's not a whole lot really to it. You just load the ROM data into the appropriate spot in memory, load the mapper hardware (from the header), load the RST jumps (from the header), load the stack pointer, load the value from 24h in the header into the accumulator, then call the init address. Then, periodically call the play address at the correct NTSC or PAL rate. That's about it. NOTE: song data cannot exceed 4Mbytes (SMS/GG) or 32K (CV). I highly doubt they will ever need to be this big, but that's how much space 8 bits of mapper select gives you. NOTE: Interrupts may be used later to play digi sounds.. I don't know if this is required or not. NOTE: When ripping songs, make sure the accumulator is what is used to select the song. Song #1 is 00h, song #2 is 01h, etc. Also, make sure that ONLY the accumulator can affect the selected song. The flags and other registers could be essentially random. Some times, a little "stub" piece of code has to be written and appended on the front or back that "converts" the song number into what the music code is looking for. An example would be a small lookup table that selects the songs in a certain order. Other things are possible, but for now this will good enough for starters. ----------------------- Notes on the text strings. To make things easier, please follow this convention! It is the same that is used by the HV SIDs collection, and I think it's very good. If you do not know what a field should contain, please use the string "<?>" to indicate it is not known, and "(?)" to indicate suspect information. ALso, these fields are NOT for ripper credits. Please put those at the end of the file or inside the file somewhere (this is what I usually do). If you do not know the copyright date, use question marks as indicated. i.e. Good: ---- Sonic the Hedgehog <- proper game name <?> <- field was not known Sega 19?? <- exact copyright date is not known - Example Game Guido Guido 1998 <- everything is known - Example Game Guido(?) <- author's name is not known for certain Guido 199? <- The date is some time from 1990-1999 Bad: --- Sonic 1 <- no good. This is not the complete name Ripmaster 2000 <- Bad. This is not the author of the song dorks <- nope. Should be a copyright string -----