├── README.md ├── sega_genesis_checksum_utility.py └── Resources └── Backup └── The Complete Documentation About Genesis Rom Format (v1.1).txt /README.md: -------------------------------------------------------------------------------- 1 | # Sega Genesis Checksum Utility 2 | A simple command line utility to verify (or correct) Sega Genesis ROM checksums. 3 | 4 | # Example Usage 5 | 6 | Simply execute the script with a single argument: the relative path to a Sega Genesis or Sega Mega Drive binary ROM file. 7 | 8 | ``` 9 | python sega_genesis_checksum_utility.py 10 | ``` 11 | 12 | Or on Linux, you can simply execute the file as an executable: 13 | 14 | ``` 15 | ./sega_genesis_checksum_utility.py 16 | ``` 17 | 18 | The script will then execute and verify the checksums match. If they match successfully, you will see a success message like so: 19 | 20 | ![Successful script execution output example.](https://i.imgur.com/XjasEpn.jpg) 21 | 22 | If the checksums do not match, you will be prompted with a y/n (yes or no) option to decide if you want the script to update the header checksum to match the computed checksum -- this should "fix" any issue for ROMs that have had their data manipulated: 23 | 24 | ![Script execution example where the checksums do not match.](https://i.imgur.com/i4DaYzD.jpg) 25 | 26 | *Note: Some games, such as [Sonic & Knuckles](https://en.wikipedia.org/wiki/Sonic_%26_Knuckles), lack checksum checks, possibly because of the time required to check the entire ROM. [[Source](https://segaretro.org/Checksum)]* 27 | 28 | # Background 29 | 30 | Sega Genesis / Sega Mega Drive games have a source of "tamper protection", which compares [checksum](https://en.wikipedia.org/wiki/Checksum) to ensure the ROM on the cartridge matches the intended checksum value. If someone attempted to manipulate the code on the cart, the checksum calculation would no longer match and the system would not load the game. 31 | 32 | > The most important data stored in the metadata, at least when determining if the ROM is good, is the "checksum." A checksum is used by companies like Nintendo and Sega to fight game piracy. The checksum is calculated through each company’s unique algorithm. At first, the ROMs were tested in emulators to see if they would run. If they passed the company’s checksum algorithm, they were considered good ROMs of the game. If a single byte in the ROM was different, the checksum wouldn’t calculate properly and thus, not run. 33 | *([Source](https://web.stanford.edu/group/htgg/cgi-bin/drupal/?q=node/1179))* 34 | 35 | The intent of this script is to be used alongside the [Retrode 2](http://www.retrode.org/), which can be purchased [here](https://www.dragonbox.de/en/71-retrode-2-cart-reader-4260416650091.html?search_query=retrode&results=7), for extracting Sega Genesis saves. 36 | 37 | According to this [2013 article](https://web.stanford.edu/group/htgg/cgi-bin/drupal/?q=node/1179) posted on Stanford 's website, the Retrode can be unreliable and occasionally read a ROM with a bad checksum. It's unclear if this is the fault of the device, or an issue with the ROM data itself for certain cartridges. Regardless, I decided to put together a simple tool, based off of this article, to detect and correct any invalid ROM checksums. 38 | 39 | *(Note: Existing tools already exist, such as this nifty interactive tool called [E.S.E by Kuwabara](https://www.romhacking.net/utilities/342/). However, as far as I can tell, it is not open-source.)* 40 | 41 | # ROM Layout 42 | 43 | All of this information is borrowed from [THE COMPLETE DOCUMENTATION ABOUT GENESIS ROM FORMAT](http://www.emulatronia.com/doctec/consolas/megadrive/genesis_rom.txt). (Note: A backed up copy of this text file can be found in the [Resources/Backup/](https://github.com/mrhappyasthma/Sega-Genesis-Checksum-Utility/blob/master/Resources/Backup/) folder.) 44 | 45 | ``` 46 | 47 | THE BASIC INFORMATION: 48 | ^^^^^^^^^^^^^^^^^^^^^ 49 | 50 | H100: 'SEGA MEGA DRIVE' 1 51 | H110: '(C)SEGA 1988.JUL' 2 52 | H120: GAME NAME (DOMESTIC) 3 53 | H150: GAME NAME (OVERSEAS) 4 54 | H180: 'XX' 5 55 | H182: 'XXXXXXX-XX' 6 56 | H18E: XXXX 7 57 | H190: 'XXXXXXXXXXXXXXXX' 8 58 | H1A0: 00000000, XXXXXXXX 9 59 | H1A8: RAM 10 60 | H1BC: MODEM DATA 11 61 | H1C8: MEMO 12 62 | H1F0: Country in which the product 13 63 | can be released. 64 | 65 | ... 66 | 67 | 7: Check sum, a two-bytes value (see "Calculating the Checksum") 68 | ``` 69 | 70 | All of this information is borrowed from [THE COMPLETE DOCUMENTATION ABOUT GENESIS ROM FORMAT](http://www.emulatronia.com/doctec/consolas/megadrive/genesis_rom.txt). (Note: A backed up copy of this text file can be found in the [Resources/Backup/](https://github.com/mrhappyasthma/Sega-Genesis-Checksum-Utility/blob/master/Resources/Backup/) folder.) 71 | 72 | 73 | # Calculating the Checksum (Algorithm) 74 | 75 | ``` 76 | CALCULATING THE CHECKSUM: 77 | ^^^^^^^^^^^^^^^^^^^^^^^^ 78 | 79 | Genesis checksum is simple enough... All you need to do is: 80 | 1) Checksum starts as zero 81 | 2) Skip the first 512 bytes of the ROM 82 | 3) Read a byte from the rom and multiply its ascii value by 256, then sum 83 | it to the checksum 84 | 4) Read the next byte from the rom and just sum it to the checksum 85 | 5) If you're not in the end of file, goto step 3 86 | 6) Get the first 16 bits from the resulting checksum and discard the higher 87 | bits 88 | 7) That's your checksum! 89 | ``` 90 | -------------------------------------------------------------------------------- /sega_genesis_checksum_utility.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Reads the checksum from a Sega Genesis binary ROM file 4 | # and compares it to the computed checksum. If there is a 5 | # mismatch, the script will ask the user if they want to 6 | # update the checksum to the "correct" computed value. 7 | # 8 | # Resources: 9 | # - http://www.emulatronia.com/doctec/consolas/megadrive/genesis_rom.txt 10 | # - https://web.stanford.edu/group/htgg/cgi-bin/drupal/?q=node/1179 11 | # - https://segaretro.org/Checksum 12 | import argparse 13 | import os 14 | import struct 15 | 16 | # The fixed offset into a Genesis file where the checksum metadata is stored. 17 | CHECKSUM_HEADER_OFFSET = 0x18E 18 | 19 | 20 | def main(): 21 | parser = argparse.ArgumentParser(description='Compares (and optionally ' 22 | 'corrects) the checksum for a ' 23 | 'Sega Genesis ROM.') 24 | parser.add_argument('path', nargs=1, help='Relative file path to the Sega ' 25 | 'Genesis ROM binary.') 26 | args = parser.parse_args() 27 | 28 | print('Reading checksum from file...') 29 | with open(args.path[0], 'r+b') as genesis_file: 30 | valid_genesis_file = verify_console_name_from_header(genesis_file) 31 | if not valid_genesis_file: 32 | print('\nERROR: File is not a valid Genesis or Mega Drive ROM file.') 33 | return 34 | 35 | header_checksum = read_checksum_from_header(genesis_file) 36 | print('Header checksum =',) 37 | print_word(header_checksum) 38 | 39 | print('Computing checksum...') 40 | computed_checksum = compute_checksum(genesis_file) 41 | print('Computed checksum = ',) 42 | print_word(computed_checksum) 43 | 44 | if header_checksum == computed_checksum: 45 | print('\nChecksums match. Horray!') 46 | return 47 | 48 | print('\nWARNING: Checksums do not match!') 49 | while(1): 50 | data = input('\nWould you like to update the header checksum to match the computed checksum? (y/n)') 51 | if data == 'n': 52 | return 53 | if data != 'y': 54 | continue 55 | 56 | print('\nWriting computed checksum to header...') 57 | write_checksum_to_header(genesis_file, computed_checksum) 58 | print('Writing complete. The header should now be updated.') 59 | print('Verifying header checksum...') 60 | header_checksum = read_checksum_from_header(genesis_file) 61 | if header_checksum == computed_checksum: 62 | print('\nChecksums match. Horray!') 63 | return 64 | print('\nERROR: Failed to write to file. Are you sure you have ' 65 | 'permission?') 66 | print('Aborting script...') 67 | return 68 | 69 | 70 | def print_word(word): 71 | """Prints a hexidecimal representation of a WORD. 72 | 73 | Args: 74 | word: A integer containing a WORD value. 75 | """ 76 | print('0x{0:04X}'.format(word)) 77 | 78 | 79 | def read_byte_as_int(open_file): 80 | """Read a BYTE from an opened file, as an int. 81 | 82 | Args: 83 | open_file: An opened file object from `open()`. 84 | 85 | Returns: 86 | An integer containing the BYTE value. 87 | """ 88 | return ord(open_file.read(1)) 89 | 90 | 91 | def read_word_as_int(open_file): 92 | """Read a WORD from an opened file, as an int. 93 | 94 | Args: 95 | open_file: An opened file object from `open()`. 96 | 97 | Returns: 98 | An integer containing the WORD value. 99 | """ 100 | high_bits = read_byte_as_int(open_file) << 8 101 | low_bits = read_byte_as_int(open_file) 102 | return high_bits | low_bits 103 | 104 | 105 | def read_checksum_from_header(open_file): 106 | """Read the checksum value stored in the header metadata of the file. 107 | 108 | Args: 109 | open_file: An opened file object referencing the binary ROM for a genesis 110 | game. 111 | 112 | Returns: 113 | An integer containing the checksum value. 114 | """ 115 | open_file.seek(CHECKSUM_HEADER_OFFSET) 116 | return read_word_as_int(open_file) 117 | 118 | def read_checksum_from_header(open_file): 119 | """Read the checksum value stored in the header metadata of the file. 120 | 121 | Args: 122 | open_file: An opened file object referencing the binary ROM for a genesis 123 | game. 124 | 125 | Returns: 126 | An integer containing the checksum value. 127 | """ 128 | open_file.seek(CHECKSUM_HEADER_OFFSET) 129 | return read_word_as_int(open_file) 130 | 131 | 132 | def verify_console_name_from_header(open_file): 133 | """Verify an `open_file` is a valid Genesis rom, by reading the console name 134 | from the file's header. 135 | 136 | Args: 137 | open_file: An opened file object referencing the binary ROM for a genesis 138 | game. 139 | 140 | Returns: 141 | True if the header of `open_file` contains the correct console name in the 142 | right location. 143 | """ 144 | memorybuffer = open_file.read() 145 | # Get the 15bits console_name and decode it with unicode. 146 | console_name = memorybuffer[0x100:0x110].decode('utf-8') 147 | if console_name.strip() == "SEGA MEGA DRIVE": 148 | return True 149 | if console_name.strip() == "SEGA GENESIS": 150 | return True 151 | return False 152 | 153 | 154 | def compute_checksum(open_file): 155 | """Computes the checksum manually from a given Sega Genesis file. 156 | 157 | Args: 158 | open_file: An opened file object referencing the binary ROM for a genesis 159 | game. 160 | 161 | Returns: 162 | An interger containing the checksum value. 163 | """ 164 | CHECKSUM_CALCULATION_START_OFFSET = 0x200 165 | open_file.seek(CHECKSUM_CALCULATION_START_OFFSET) 166 | 167 | checksum = 0 168 | file_size = os.path.getsize(open_file.name) 169 | NUM_BYTES_PER_WORD = 2 170 | for i in range(open_file.tell(), file_size, NUM_BYTES_PER_WORD): 171 | word = read_word_as_int(open_file) 172 | checksum += word 173 | 174 | # Extract the checksum as the lowest 16 bits of the result. 175 | WORD_MASK = 65535 176 | return checksum & WORD_MASK 177 | 178 | 179 | def write_checksum_to_header(open_file, checksum): 180 | """Writes the computed `checksum` into the header metadata of `open_file`. 181 | 182 | Args: 183 | open_file: An opened file object referencing the binary ROM for a genesis 184 | game. 185 | checksum: An integer representing the computer checksum, as a WORD, to write 186 | to the `open_file` header metadata. 187 | """ 188 | open_file.seek(CHECKSUM_HEADER_OFFSET) 189 | open_file.write(struct.pack('>H', checksum)) 190 | 191 | 192 | main() 193 | -------------------------------------------------------------------------------- /Resources/Backup/The Complete Documentation About Genesis Rom Format (v1.1).txt: -------------------------------------------------------------------------------- 1 | // NOTE: Backed up copy from http://www.emulatronia.com/doctec/consolas/megadrive/genesis_rom.txt. 2 | 3 | 4 | THE COMPLETE DOCUMENTATION ABOUT 5 | GENESIS ROM FORMAT 6 | 7 | Version 1.1 8 | 9 | 10 | Release history 11 | ^^^^^^^^^^^^^^^ 12 | Version 1.0 (December, 1997) 13 | - Initial Release 14 | 15 | Version 1.1 (January, 1998) 16 | - Splitted rom format explained! 17 | - New company codes 18 | - New errors in copyright interpreting found 19 | - Month interpreting (in copyright) 20 | 21 | 22 | In this document you will find everything you need to know about 23 | the information embedded within a Genesis ROM. You will also find 24 | how to read all this information from the different ROM formats 25 | (BIN, SMD and MD). 26 | The information in this document was hacked by Volker Oth (dOnut) 27 | and by me with help from technical documents found on internet. 28 | The primary document from the internet that we used was gentech.txt. 29 | If you want to change this document to add any important info about 30 | the Genesis ROMs, do it freely but I would like to receive a copy of 31 | the updated document. Then, I'll add your name in it and post it on my 32 | homepage. Don't be a lamer and keep all names mentioned here! 33 | Note that all numbers with a "H" in the left are in hexadecimal, and 34 | the first byte of a file is the ZERO position. All information is 35 | provided based on the BIN file-format because of the nature of this 36 | format(see sections about each rom format). 37 | *This document should be downloaded from my homepage. Any other site 38 | may contain outdated material!* 39 | If you use this information for anything, please give the proper 40 | credits to the all these names listed below! I would thank you if you 41 | include a link to our homepages and emails, too! 42 | 43 | Felipe XnaK: 44 | http://www.classicgaming.com/launchtool 45 | felipe@ComPorts.com 46 | Volker Oth (dOnut): 47 | http://members.aol.com/~volkeroth 48 | volkeroth@aol.com 49 | 50 | 51 | THE BASIC INFORMATION: 52 | ^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | H100: 'SEGA MEGA DRIVE' 1 55 | H110: '(C)SEGA 1988.JUL' 2 56 | H120: GAME NAME (DOMESTIC) 3 57 | H150: GAME NAME (OVERSEAS) 4 58 | H180: 'XX' 5 59 | H182: 'XXXXXXX-XX' 6 60 | H18E: XXXX 7 61 | H190: 'XXXXXXXXXXXXXXXX' 8 62 | H1A0: 00000000, XXXXXXXX 9 63 | H1A8: RAM 10 64 | H1BC: MODEM DATA 11 65 | H1C8: MEMO 12 66 | H1F0: Country in which the product 13 67 | can be released. 68 | 69 | 1: This is just the console name. It can be 'SEGA MEGA DRIVE' or 70 | 'SEGA GENESIS' depending on the console's country of origin. 71 | 72 | 2: Copyright notice. There SHOULD be 4 characters for the company 73 | code, a space and then the date in yyyy.mmm format; however, there are 74 | variations. 75 | For a listing of company codes, see "TABLE OF COMPANY CODES". 76 | For a listing of month abbreviations, se "TABLE OF MONTH ABBREVIATIONS". 77 | When the company uses a number as a company code, the copyright has 78 | (in most cases!) this format: '(C)T-XX 1988.JUL', where XX is the 79 | company code. If the company code has three digits, it should use the 80 | space between the code and the date. 81 | Some wrong copyrights i've found: 82 | * The year is written as '199X' or '19XX', or doen't include the 83 | millenium and the century. 84 | * The company name is '00' or 'XX' 85 | * Some companies that use a number for company code overwrite the 86 | hiphen, not the space. 87 | * Some companies doesn't include the '(C)' in the beginning and 88 | others include just their name; some just include the the year 89 | * Some copyrights have the year and month separated by ',','/', '-', 90 | space or null character (H00). I'd found one that hasn't any separator 91 | at all! 92 | -- Good luck! -- 93 | 94 | 3: This is the so-called "Domestic game name". Is the name the game has 95 | in its country of origin. This field is 48 bytes long... 96 | 97 | 4: ... and this is the so-called "Overseas game name". This is the name 98 | the game has worldwide. 48 bytes long too. 99 | 100 | 5: Type of product. This is 2 bytes long. Known values: 101 | GM = Game 102 | Al = Education 103 | 104 | 6: Product code and Version number: 105 | * The first 7 characters are the product code 106 | * The 2 characters after the hiphen is the version number. This will 107 | vary depending on the the type of ROM or software version 108 | 109 | 7: Check sum, a two-bytes value (see "Calculating the Checksum") 110 | 111 | 8: I/0 support: (this is 16 bytes long) 112 | J = Joypad 4 = Team Play 113 | 6 = 6-button Joypad 0 = Joystick for MS 114 | K = Keyboard R = Serial RS232C 115 | P = Printer T = Tablet 116 | B = Control Ball V = Paddle Controller 117 | F = Floppy Disk Drive C = CD-ROM 118 | L = Activator M = Mega Mouse 119 | 120 | 9: ROM capacity. Here you will find the start and end address of the rom, 121 | respectively. The start address in most cases is 0 and the end address is 122 | the size of rom in BYTES. Note that these values don't include the headers 123 | that some rom images have (discussed later). Each address is 4-bytes long. 124 | 125 | 10: There is a lot of information here that I can't help you with. What 126 | I can say is that you can get the start and end positions of the backup 127 | RAM at offset H1B4. Like in ROM addresses, you first acquire the start, 128 | then the end address. Remember, these addresses are four bytes each. 129 | 130 | 11: If the rom has no support for MODEM, fill this with spaces. If it has 131 | support for MODEM, then fill in this format: 'MOxxxxyy.z', where: 132 | xxxx Firm name the same as in 2 133 | yy MODEM NO. 134 | z Version 135 | 136 | 12: I don't know what the heck it is! But by it's name and considering 137 | all roms that I investigated, it seems that you can write whatever you want 138 | in this field... 139 | 140 | 13: Countries where the game can be released. What is most interesting 141 | here is that changing this info in some games has different behaviour. 142 | Streets of Rage, for example, automatically changes it's name for Bare 143 | Knuckle if you set the game for Japan. The "official" codes are: 144 | E = Europe 145 | J = Japan 146 | U = USA 147 | I've found some others as well(I do not guarantee this is correct!) 148 | A = Asia 149 | B = Brazil 150 | 4 = Brazil 151 | F = France 152 | 8 = Hong Kong 153 | This field can only contain three countries. This isn't really a 154 | problem because all "unofficial" codes run as Europe! Don't forget to 155 | set spaces to fill the bytes you don't use in this field. 156 | 157 | 158 | TABLE OF COMPANY CODES: 159 | ^^^^^^^^^^^^^^^^^^^^^^ 160 | 161 | This table was compiled by myself by just getting the company code 162 | in the ROM and writing the license that appears on the tittle screen. 163 | In other words, it probably contains errors and is missing a lot of 164 | companies. 165 | When two comp1anies use the same code and are different companies 166 | (at least to my knownledge) the names are separeted by an "or". If the 167 | companies are the same (like Acclain and Flying Edge), they're separated 168 | by a backslash (/). 169 | 170 | CODE COMPANY 171 | 172 | ACLD Ballistic 173 | ASCI Asciiware 174 | RSI Razorsoft 175 | SEGA SEGA 176 | TREC Treco 177 | VRGN Virgin Games 178 | WSTN Westone 179 | 10 Takara 180 | 11 Taito or Accolade 181 | 12 Capcom 182 | 13 Data East 183 | 14 Namco or Tengen 184 | 15 Sunsoft 185 | 16 Bandai 186 | 17 Dempa 187 | 18 Technosoft 188 | 19 Technosoft 189 | 20 Asmik 190 | 22 Micronet 191 | 23 Vic Tokai 192 | 24 American Sammy 193 | 29 Kyugo 194 | 32 Wolfteam 195 | 33 Kaneko 196 | 35 Toaplan 197 | 36 Tecmo 198 | 40 Toaplan 199 | 42 UFL Company Limited 200 | 43 Human 201 | 45 Game Arts 202 | 47 Sage's Creation 203 | 48 Tengen 204 | 49 Renovation or Telenet 205 | 50 Eletronic Arts 206 | 56 Razorsoft 207 | 58 Mentrix 208 | 60 Victor Musical Industries 209 | 69 Arena 210 | 70 Virgin 211 | 73 Soft Vision 212 | 74 Palsoft 213 | 76 Koei 214 | 79 U.S. Gold 215 | 81 Acclaim/Flying Edge 216 | 83 Gametek 217 | 86 Absolute 218 | 93 Sony 219 | 95 Konami 220 | 97 Tradewest 221 | 100 T*HQ Software 222 | 101 Tecmagik 223 | 112 Designer Software 224 | 113 Psygnosis 225 | 119 Accolade 226 | 120 Code Masters 227 | 125 Interplay 228 | 130 Activision 229 | 132 Shiny & Playmates 230 | 144 Atlus 231 | 151 Infogrames 232 | 161 Fox Interactive 233 | 239 Disney Interactive 234 | 235 | - SPECIAL CASES: 236 | 237 | In "Smurfs II" the copyright is just '(C) INFOGRAMES' 238 | In "Baby's day out" rom, the copyright is: '(C) T-SNK 95-FEB', 239 | but the company name is "HI-TECH entertainment" 240 | 241 | 242 | TABLE OF MONTH ABBREVIATIONS: 243 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 244 | 245 | ABBREVIATIONS MONTH 246 | 247 | JAN January 248 | FEB February 249 | MAR March 250 | APR or APL April 251 | MAY May 252 | JUN June 253 | JUL July 254 | AUG or 08 August 255 | SEP or SEPT September 256 | OCT October 257 | NOV November 258 | DEC December 259 | 260 | 261 | CALCULATING THE CHECKSUM: 262 | ^^^^^^^^^^^^^^^^^^^^^^^^ 263 | 264 | Genesis checksum is simple enough... All you need to do is: 265 | 1) Checksum starts as zero 266 | 2) Skip the first 512 bytes of the ROM 267 | 3) Read a byte from the rom and multiply its ascii value by 256, then sum 268 | it to the checksum 269 | 4) Read the next byte from the rom and just sum it to the checksum 270 | 5) If you're not in the end of file, goto step 3 271 | 6) Get the first 16 bits from the resulting checksum and discard the higher 272 | bits 273 | 7) That's your checksum! 274 | 275 | 276 | Super Magic Drive Binary file-format (.BIN): 277 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 278 | 279 | This rom file-format is a simple rom dump. Nothing more to add! 280 | 281 | 282 | Super Magic Drive Interleaved file-format (.SMD): 283 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 284 | 285 | This is a much more complex file-format. It have a 512 bytes header 286 | and is interleaved in 16KB blocks. These blocks have their even bytes 287 | at the beginning and the odd bytes at the end of them. 288 | 289 | WHAT YOU FIND IN THE 512 BYTES HEADER: 290 | 291 | 0: Number of blocks 1 292 | 1: H03 * 293 | 2: SPLIT? 2 294 | 8: HAA * 295 | 9: HBB * 296 | ALL OTHER BYTES: H00 297 | 298 | 1: This first byte should have the number of 16KB blocks the rom has. 299 | The header isn't part of the formula, so this number is: 300 | [size of rom-512]/16386 301 | If the size is more than 255, the value should be H00. 302 | 303 | 2: This byte indicates if the ROM is a part of a splitted rom series. If 304 | the rom is the last part of the series (or isn't a splitted rom at all), 305 | this byte should be H00. In other cases should be H40. See "CREATING 306 | SPLITTED ROMS" for details on this format. 307 | 308 | *: Fixed values 309 | 310 | 311 | THE DE-INTERLEAVING CODE (how to convert a SMD to a BIN): 312 | 313 | 1) Skip the 512 bytes header 314 | 2) Get 16KB from the ROM (16384 bytes) 315 | 3) Decode the block 316 | 4) Write the decoded block to the BIN file 317 | 318 | DECODING A SMD BLOCK (stating byte is 0): 319 | 320 | 1) Get Middlepoint (8192) 321 | 2) Get a byte from the block 322 | 3) If the byte position is equal or smaller than middlepoint, put it 323 | in the first unused EVEN position of the decoded buffer 324 | 4) If the byte position is greater than middlepoint, put it in the 325 | first unused ODD position of the decoded buffer 326 | 327 | To convert a BIN to a SMD, just create a header (as explained before) and 328 | then do the reverse process! 329 | 330 | 331 | Multi Game Doctor file-format (.MD): 332 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 333 | 334 | The MD file format also doesn't have a header. The interleaving it uses 335 | is equal to the SMD, but without the division in blocks! (Even bytes in 336 | the end of file, odd bytes in the beginning). 337 | 338 | THE DECODING A MD (how to convert a MD to a BIN): 339 | 340 | 1) Get middlepoint ([size of rom]/2) 341 | 2) Get a byte from the ROM 342 | 3) If the byte position is equal or smaller than the middlepoint put the 343 | byte in [byte position]*2 of the destination buffer 344 | 4) If the byte position is greater than the middlepoint, put the byte in 345 | ([byte position]*2) - [size of rom] -1 346 | 347 | 348 | CREATING SPLITTED ROMS: 349 | ^^^^^^^^^^^^^^^^^^^^^^^ 350 | 351 | Splitted ROMs are a SMD divided into pieces. Knowing this, you may 352 | guess that you first need to convert your ROM to a SMD! :) 353 | To have a splitted ROM created all you need is divide your SMD in 354 | several pieces, usually all with the same size (with the exception of 355 | the last one). After doing that, you need to add a SMD header to all 356 | these pieces. About these SMD headers: 357 | 1) The number of blocks embedded in them should be relative to the 358 | piece, not to the joined ROM. 359 | 2) As stated before, with the exception of the last piece, all roms 360 | should have their SPLIT byte set. 361 | 362 | 363 | HOW YOU CAN HELP ME WITH THIS DOCUMENT: 364 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 365 | 366 | - Telling me the intricacies of a MGD ROM image. I never found one, but 367 | I do believe it's equal to MD format. 368 | - I'm trying to find out how the sprites are saved in Genesis ROMs. If 369 | you have this info, I would like to have it! 370 | - I never had a rom with modem support. If you have one, please test if 371 | the information about it is correct in this documentation (I got it from 372 | gentech). If you find it's correct, please explain me!!! 373 | 374 | If you have any of this information, send it with your addresses (e-mail, 375 | homepage, etc) so I can add this to the document! 376 | --------------------------------------------------------------------------------