makebin.c (28342B)
1/* 2 makebin - turn a .ihx file into a binary image or GameBoy format binaryimage 3 4 Copyright (c) 2000 Michael Hope 5 Copyright (c) 2010 Borut Razem 6 Copyright (c) 2012 Noel Lemouel 7 Copyright (c) 2020-2021 Sebastian 'basxto' Riedel 8 Copyright (c) 2020 'bbbbbr' 9 10 This software is provided 'as-is', without any express or implied 11 warranty. In no event will the authors be held liable for any damages 12 arising from the use of this software. 13 14 Permission is granted to anyone to use this software for any purpose, 15 including commercial applications, and to alter it and redistribute it 16 freely, subject to the following restrictions: 17 18 1. The origin of this software must not be misrepresented; you must not 19 claim that you wrote the original software. If you use this software 20 in a product, an acknowledgment in the product documentation would be 21 appreciated but is not required. 22 2. Altered source versions must be plainly marked as such, and must not be 23 misrepresented as being the original software. 24 3. This notice may not be removed or altered from any source distribution. 25*/ 26 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <stdbool.h> 31#include <string.h> 32#include <ctype.h> 33 34#if defined(_WIN32) 35#include <fcntl.h> 36#include <io.h> 37#else 38#include <unistd.h> 39#endif 40 41 42typedef unsigned char BYTE; 43 44#define FILL_BYTE 0xff 45 46int 47getnibble (FILE *fin) 48{ 49 int ret; 50 int c = getc (fin); 51 52 if (feof (fin) || ferror (fin)) 53 { 54 fprintf (stderr, "error: unexpected end of file.\n"); 55 exit (6); 56 } 57 58 ret = c - '0'; 59 if (ret > 9) 60 { 61 ret -= 'A' - '9' - 1; 62 } 63 64 if (ret > 0xf) 65 { 66 ret -= 'a' - 'A'; 67 } 68 69 if (ret < 0 || ret > 0xf) 70 { 71 fprintf (stderr, "error: character %02x.\n", ret); 72 exit (7); 73 } 74 return ret; 75} 76 77int 78getbyte (FILE *fin, int *sum) 79{ 80 int b = (getnibble (fin) << 4) | getnibble (fin); 81 *sum += b; 82 return b; 83} 84 85void 86usage (void) 87{ 88 fprintf (stderr, 89 "makebin: convert a Intel IHX file to binary or GameBoy format binary.\n" 90 "Usage: makebin [options] [<in_file> [<out_file>]]\n" 91 "Options:\n" 92 " -p pack mode: the binary file size will be truncated to the last occupied byte\n" 93 " -s romsize size of the binary file (default: rom banks * 16384)\n" 94 " -Z generate GameBoy format binary file\n" 95 " -S generate Sega Master System format binary file\n" 96 " -t size skip size bytes from the beginning of the rom" 97 98 "SMS format options (applicable only with -S option):\n" 99 " -xo n rom size (0xa-0x2)\n" 100 " -xj n set region code (3-7)\n" 101 //" -xc n product code (0-159999)\n" 102 " -xv n version number (0-15)\n" 103 //" -xV n SDSC version number\n" 104 //" -xd n SDSC date\n" 105 //" -xA n SDSC author pointer\n" 106 //" -xn n SDSC program name pointer\n" 107 //" -xD n SDSC description pointer\n" 108 109 "GameBoy format options (applicable only with -Z option):\n" 110 " -yo n number of rom banks (default: 2) (autosize: A)\n" 111 " -ya n number of ram banks (default: 0)\n" 112 " -yt n MBC type (default: no MBC)\n" 113 " -yl n old licensee code (default: 0x33)\n" 114 " -yk cc new licensee string (default: 00)\n" 115 " -yn name cartridge name (default: none)\n" 116 " -yc GameBoy Color compatible\n" 117 " -yC GameBoy Color only\n" 118 " -ys Super GameBoy\n" 119 " -yS Convert .noi file named like input file to .sym\n" 120 " -yj set non-Japanese region flag\n" 121 " -yN do not copy big N validation logo into ROM header\n" 122 " -yp addr=value Set address in ROM to given value (address 0x100-0x1FE)\n" 123 "Arguments:\n" 124 " <in_file> optional IHX input file, '-' means stdin. (default: stdin)\n" 125 " <out_file> optional output file, '-' means stdout. (default: stdout)\n"); 126} 127 128#define CART_NAME_LEN 16 129 130struct gb_opt_s 131{ 132 char cart_name[CART_NAME_LEN]; /* cartridge name buffer */ 133 char licensee_str[2]; /* new licensee string */ 134 BYTE mbc_type; /* MBC type (default: no MBC) */ 135 short nb_rom_banks; /* Number of rom banks (default: 2) */ 136 BYTE nb_ram_banks; /* Number of ram banks (default: 0) */ 137 BYTE licensee_id; /* old licensee code */ 138 BYTE is_gbc; /* 1 if GBC compatible, 2 if GBC only, false for all other*/ 139 BYTE is_sgb; /* True if SGB, false for all other*/ 140 BYTE sym_conversion; /* True if .noi file should be converted to .sym (default false)*/ 141 BYTE non_jp; /* True if non-Japanese region, false for all other*/ 142 BYTE rom_banks_autosize; /* True if rom banks should be auto-sized (default false)*/ 143 bool do_logo_copy; /* True if the nintendo logo should be copied into the ROM (default true) */ 144 BYTE address_overwrite[16]; /* For limited compatibility with very old versions */ 145}; 146 147struct sms_opt_s 148{ 149 BYTE rom_size; /* Doesn't have to be the real size, needed for checksum */ 150 BYTE region_code; /* Region code Japan/Export/International and SMS/GG */ 151 BYTE version; /* Game version */ 152}; 153 154void 155gb_postproc (BYTE * rom, int size, int *real_size, struct gb_opt_s *o) 156{ 157 int i, chk; 158 static const BYTE gb_logo[] = 159 { 160 0xce, 0xed, 0x66, 0x66, 0xcc, 0x0d, 0x00, 0x0b, 161 0x03, 0x73, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x0d, 162 0x00, 0x08, 0x11, 0x1f, 0x88, 0x89, 0x00, 0x0e, 163 0xdc, 0xcc, 0x6e, 0xe6, 0xdd, 0xdd, 0xd9, 0x99, 164 0xbb, 0xbb, 0x67, 0x63, 0x6e, 0x0e, 0xec, 0xcc, 165 0xdd, 0xdc, 0x99, 0x9f, 0xbb, 0xb9, 0x33, 0x3e 166 }; 167 168 /* $0104-$0133: Nintendo logo 169 * If missing, an actual Game Boy won't run the ROM. 170 */ 171 172 if (o->do_logo_copy) 173 { 174 memcpy (&rom[0x104], gb_logo, sizeof (gb_logo)); 175 } 176 177 rom[0x144] = o->licensee_str[0]; 178 rom[0x145] = o->licensee_str[1]; 179 180 /* 181 * 0134-0142: Title of the game in UPPER CASE ASCII. If it 182 * is less than 16 characters then the 183 * remaining bytes are filled with 00's. 184 */ 185 186 /* capitalize cartridge name */ 187 for (i = 0; i < CART_NAME_LEN; ++i) 188 { 189 rom[0x134 + i] = toupper (o->cart_name[i]); 190 } 191 192 if (o->is_gbc == 1) 193 { 194 rom[0x143] = 0x80; 195 } 196 197 if (o->is_gbc == 2) 198 { 199 rom[0x143] = 0xC0; 200 } 201 202 if (o->is_sgb) 203 { 204 rom[0x146] = 0x03; 205 } 206 207 /* 208 * 0147: Cartridge type: 209 * 0-ROM ONLY 12-ROM+MBC3+RAM 210 * 1-ROM+MBC1 13-ROM+MBC3+RAM+BATT 211 * 2-ROM+MBC1+RAM 19-ROM+MBC5 212 * 3-ROM+MBC1+RAM+BATT 1A-ROM+MBC5+RAM 213 * 5-ROM+MBC2 1B-ROM+MBC5+RAM+BATT 214 * 6-ROM+MBC2+BATTERY 1C-ROM+MBC5+RUMBLE 215 * 8-ROM+RAM 1D-ROM+MBC5+RUMBLE+SRAM 216 * 9-ROM+RAM+BATTERY 1E-ROM+MBC5+RUMBLE+SRAM+BATT 217 * B-ROM+MMM01 1F-Pocket Camera 218 * C-ROM+MMM01+SRAM FD-Bandai TAMA5 219 * D-ROM+MMM01+SRAM+BATT FE - Hudson HuC-3 220 * F-ROM+MBC3+TIMER+BATT FF - Hudson HuC-1 221 * 10-ROM+MBC3+TIMER+RAM+BATT 222 * 11-ROM+MBC3 223 */ 224 rom[0x147] = o->mbc_type; 225 226 /* 227 * 0148 ROM size: 228 * 0 - 256Kbit = 32KByte = 2 banks 229 * 1 - 512Kbit = 64KByte = 4 banks 230 * 2 - 1Mbit = 128KByte = 8 banks 231 * 3 - 2Mbit = 256KByte = 16 banks 232 * 4 - 4Mbit = 512KByte = 32 banks 233 * 5 - 8Mbit = 1MByte = 64 banks 234 * 6 - 16Mbit = 2MByte = 128 banks 235 * $52 - 9Mbit = 1.1MByte = 72 banks 236 * $53 - 10Mbit = 1.2MByte = 80 banks 237 * $54 - 12Mbit = 1.5MByte = 96 banks 238 */ 239 switch (o->nb_rom_banks) 240 { 241 case 2: 242 rom[0x148] = 0; 243 break; 244 245 case 4: 246 rom[0x148] = 1; 247 break; 248 249 case 8: 250 rom[0x148] = 2; 251 break; 252 253 case 16: 254 rom[0x148] = 3; 255 break; 256 257 case 32: 258 rom[0x148] = 4; 259 break; 260 261 case 64: 262 rom[0x148] = 5; 263 break; 264 265 case 128: 266 rom[0x148] = 6; 267 break; 268 269 case 256: 270 rom[0x148] = 7; 271 break; 272 273 case 512: 274 rom[0x148] = 8; 275 break; 276 277 default: 278 fprintf (stderr, "warning: unsupported number of ROM banks (%d)\n", o->nb_rom_banks); 279 rom[0x148] = 0; 280 break; 281 } 282 283 /* 284 * 0149 RAM size: 285 * 0 - None 286 * 1 - 16kBit = 2kB = 1 bank 287 * 2 - 64kBit = 8kB = 1 bank 288 * 3 - 256kBit = 32kB = 4 banks 289 * 4 - 1MBit =128kB =16 banks 290 */ 291 switch (o->nb_ram_banks) 292 { 293 case 0: 294 rom[0x149] = 0; 295 break; 296 297 case 1: 298 rom[0x149] = 2; 299 break; 300 301 case 4: 302 rom[0x149] = 3; 303 break; 304 305 case 16: 306 rom[0x149] = 4; 307 break; 308 309 default: 310 fprintf (stderr, "warning: unsupported number of RAM banks (%d)\n", o->nb_ram_banks); 311 rom[0x149] = 0; 312 break; 313 } 314 315 rom[0x14A] = o->non_jp; 316 317 rom[0x14B] = o->licensee_id; 318 319 for (i = 0; i < 16; i+=2) 320 { 321 if(o->address_overwrite[i] != 0xFF) 322 { 323 rom[0x0100 & o->address_overwrite[i]] = o->address_overwrite[i+1]; 324 // warnings for builds ported from ancient GBDK 325 fprintf (stderr, "caution: -yp0x01%02x=0x%02x is outdated", o->address_overwrite[i], o->address_overwrite[i+1]); 326 if(o->address_overwrite[i] == 0x43) 327 switch(o->address_overwrite[i+1]&0xC0) 328 { 329 case 0x80: 330 fprintf (stderr, ", please use -yc instead"); 331 break; 332 case 0xC0: 333 fprintf (stderr, ", please use -yC instead"); 334 break; 335 default: 336 o->address_overwrite[i] = 0xFF; 337 } 338 if(o->address_overwrite[i] == 0x44 || o->address_overwrite[i] == 0x45) 339 fprintf (stderr, ", please use -yk cc instead"); 340 if(o->address_overwrite[i] == 0x46) 341 if(o->address_overwrite[i+1] == 0x03) 342 fprintf (stderr, ", please use -ys instead"); 343 else 344 o->address_overwrite[i] = 0xFF; 345 if(o->address_overwrite[i] == 0x47) 346 fprintf (stderr, ", please use -yt 0x%02x instead", o->address_overwrite[i+1]); 347 if(o->address_overwrite[i] == 0x4A) 348 fprintf (stderr, ", please use -yl 0x%02x instead", o->address_overwrite[i+1]); 349 if(o->address_overwrite[i] == 0x4B && o->address_overwrite[i+1] == 1) 350 fprintf (stderr, ", please use -yj instead"); 351 if(o->address_overwrite[i] == 0xFF) 352 fprintf (stderr, ", this setting is the default"); 353 fprintf (stderr, ".\n"); 354 } 355 } 356 357 /* Update complement checksum */ 358 chk = 0; 359 for (i = 0x134; i < 0x14d; ++i) 360 chk += rom[i]; 361 rom[0x014d] = (unsigned char) (0xe7 - (chk & 0xff)); 362 363 /* Update checksum */ 364 chk = 0; 365 rom[0x14e] = 0; 366 rom[0x14f] = 0; 367 for (i = 0; i < size; ++i) 368 chk += rom[i]; 369 rom[0x14e] = (unsigned char) ((chk >> 8) & 0xff); 370 rom[0x14f] = (unsigned char) (chk & 0xff); 371 372 if (*real_size < 0x150) 373 *real_size = 0x150; 374} 375 376void 377sms_postproc (BYTE * rom, int size, int *real_size, struct sms_opt_s *o) 378{ 379 // based on https://www.smspower.org/Development/ROMHeader 380 // 0x1ff0 and 0x3ff0 are also possible, but never used 381 static const char tmr_sega[] = "TMR SEGA "; 382 short header_base = 0x7ff0; 383 int chk = 0; 384 unsigned long i; 385 // choose earlier positions for smaller roms 386 if (header_base > size) 387 header_base = 0x3ff0; 388 if (header_base > size) 389 header_base = 0x1ff0; 390 391 memcpy (&rom[header_base], tmr_sega, sizeof (tmr_sega) - 1); 392 // configure amounts of bytes to check 393 switch(o->rom_size) 394 { 395 case 0xa: 396 default: 397 i = 0x1FEF; 398 break; 399 case 0xb: 400 i = 0x3FEF; 401 break; 402 case 0xc: 403 i = 0x7FEF; 404 break; 405 case 0xd: 406 i = 0xBFEF; 407 break; 408 case 0xe: 409 i = 0xFFFF; 410 break; 411 case 0xf: 412 i = 0x1FFFF; 413 break; 414 case 0x0: 415 i = 0x3FFFF; 416 break; 417 case 0x1: 418 i = 0x7FFFF; 419 break; 420 case 0x2: 421 i = 0xFFFFF; 422 break; 423 } 424 // calculate checksum 425 for(;i > 0; --i) 426 { 427 chk += rom[i]; 428 // 0x7FF0 - 0x7FFF is skipped 429 if(i == 0x8000) 430 i = 0x7FF0; 431 } 432 // we skipped index 0 433 chk += rom[0]; 434 // little endian 435 rom[header_base + 0xa] = chk & 0xff; 436 rom[header_base + 0xb] = (chk>>8) & 0xff; 437 // game version 438 rom[header_base + 0xe] &= 0xF0; 439 rom[header_base + 0xe] |= o->version; 440 // rom size 441 rom[header_base + 0xf] = (o->region_code << 4) | o->rom_size; 442} 443 444int 445rom_autosize_grow(BYTE **rom, int test_size, int *size, struct gb_opt_s *o) 446{ 447 int last_size = *size; 448 449 while ((test_size > *size) && (o->nb_rom_banks <= 512)) 450 { 451 o->nb_rom_banks *= 2; 452 // banks work differently for mbc6, they have half the size 453 // but this in general ignored by -yo 454 *size = o->nb_rom_banks * 0x4000; 455 } 456 457 if (o->nb_rom_banks > 512) 458 { 459 fprintf (stderr, "error: auto-size banks exceeded max of 512 banks.\n"); 460 return 0; 461 } 462 else 463 { 464 BYTE * t_rom = *rom; 465 *rom = realloc (*rom, *size); 466 if (*rom == NULL) 467 { 468 free(t_rom); 469 fprintf (stderr, "error: couldn't re-allocate size for larger rom image.\n"); 470 return 0; 471 } 472 memset (*rom + last_size, FILL_BYTE, *size - last_size); 473 } 474 475 return 1; 476} 477 478int 479noi2sym (char *filename) 480{ 481 FILE *noi, *sym; 482 char *nname, *sname; 483 //ssize_t read; 484 char read = ' '; 485 // no$gmb's implementation is limited to 32 character labels 486 // we can safely throw away the rest 487 char label[33]; 488 // 0x + 6 digit hex number 489 // -> 65536 rom banks is the maximum homebrew cartrideges support (TPP1) 490 char value[9]; 491 int name_len = strlen(filename); 492 int i = 0; 493 // copy filename's value to nname and sname 494 nname = malloc((name_len+1) * sizeof(char)); 495 strcpy (nname, filename); 496 sname = malloc((name_len+1) * sizeof(char)); 497 strcpy (sname, filename); 498 // change the extensions 499 nname[name_len-1]='i'; 500 nname[name_len-2]='o'; 501 nname[name_len-3]='n'; 502 sname[name_len-1]='m'; 503 sname[name_len-2]='y'; 504 sname[name_len-3]='s'; 505 506 if (NULL == (noi = fopen (nname, "r"))) 507 { 508 fprintf (stderr, "error: can't open %s: ", nname); 509 perror(NULL); 510 return 1; 511 } 512 if (NULL == (sym = fopen (sname, "w"))) 513 { 514 fprintf (stderr, "error: can't create %s: ", sname); 515 perror(NULL); 516 return 1; 517 } 518 // write header 519 fprintf (sym, "; no$gmb compatible .sym file\n; Generated automagically by makebin\n"); 520 // iterate through .noi file 521 while (read != EOF && (read = fgetc(noi)) != EOF) 522 { 523 // just skip line breaks 524 if (read == '\r' || read == '\n') 525 continue; 526 // read first 4 chars 527 for (i = 0; i < 4; ++i) 528 { 529 value[i] = read; 530 if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n') 531 { 532 // leave for-loop 533 break; 534 } 535 } 536 // we left loop early 537 if (i != 4) 538 continue; 539 // only accept if line starts with this 540 if (strncmp(value, "DEF ", 4) == 0) 541 { 542 // read label 543 for (i = 0; i < 32; ++i) 544 { 545 label[i] = read; 546 if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n' || read == ' ') 547 { 548 // leave for-loop 549 break; 550 } 551 } 552 // skip rest of the label 553 while (read != EOF && read != '\r' && read != '\n' && read != ' ') 554 read = fgetc(noi); 555 // it has to be end of file or line if it's not space 556 if (read != ' ') 557 continue; 558 // strings have to end with \0 559 label[i+1] = '\0'; 560 // read value 561 for (i = 0; i < 8; ++i) 562 { 563 value[i] = read; 564 if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n') 565 { 566 // leave for-loop 567 break; 568 } 569 } 570 // number is too long; ignore 571 if (read != EOF && read != '\r' && read != '\n') 572 continue; 573 value[i+1] = '\0'; 574 // we successfully read label and value 575 576 // but filter out some invalid symbols 577 if (strcmp(label, ".__.ABS.") != 0 && strncmp(label, "l__", 3) != 0) 578 fprintf (sym, "%02X:%04X %s\n", (unsigned int)(strtoul(value, NULL, 0)>>16), (unsigned int)strtoul(value, NULL, 0)&0xFFFF, label); 579 } 580 else 581 // skip until file/line end 582 while ((read = fgetc(noi))!= EOF && read != '\r' && read != '\n'); 583 } 584 585 // free close files 586 fclose (noi); 587 fclose (sym); 588 589 fprintf (stderr, "Converted %s to %s.\n", nname, sname); 590 return 0; 591} 592 593int 594read_ihx (FILE *fin, BYTE **rom, int *size, int *real_size, struct gb_opt_s *o) 595{ 596 int record_type; 597 598 int extaddr = 0; 599 do 600 { 601 int nbytes; 602 int addr; 603 int checksum, sum = 0; 604 605 if (getc (fin) != ':') 606 { 607 fprintf (stderr, "error: invalid IHX line.\n"); 608 return 0; 609 } 610 nbytes = getbyte (fin, &sum); 611 addr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); 612 record_type = getbyte (fin, &sum); 613 if(record_type == 4) 614 { 615 extaddr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); 616 extaddr <<= 16; // those are the upper 16 bits 617 checksum = getbyte (fin, &sum); 618 // move to the next record 619 if (0 != (sum & 0xff)) 620 { 621 fprintf (stderr, "error: bad checksum: %02x.\n", checksum); 622 return 0; 623 } 624 while (isspace (sum = getc (fin))) /* skip all kind of spaces */ 625 ; 626 ungetc (sum, fin); 627 if (getc (fin) != ':') 628 { 629 fprintf (stderr, "error: invalid IHX line.\n"); 630 return 0; 631 } 632 // parse real data part 633 checksum = sum = 0; 634 nbytes = getbyte (fin, &sum); 635 // lower 16 bits 636 addr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); 637 record_type = getbyte (fin, &sum); 638 } 639 // add linear address extension 640 addr |= extaddr; 641 // TODO: warn for unreachable banks according to chosen MBC 642 if (record_type > 1) 643 { 644 fprintf (stderr, "error: unsupported record type: %02x.\n", record_type); 645 return 0; 646 } 647 648 if (addr + nbytes > *size) 649 { 650 // If auto-size is enabled, grow rom bank size by power of 2 when needed 651 if (o->rom_banks_autosize) 652 { 653 if (rom_autosize_grow(rom, addr + nbytes, size, o) == 0) 654 return 0; 655 } 656 else 657 { 658 fprintf (stderr, "error: size of the buffer is too small.\n"); 659 return 0; 660 } 661 } 662 663 while (nbytes--) 664 { 665 if (addr < *size) 666 (*rom)[addr++] = getbyte (fin, &sum); 667 } 668 669 if (addr > *real_size) 670 *real_size = addr; 671 672 checksum = getbyte (fin, &sum); 673 if (0 != (sum & 0xff)) 674 { 675 fprintf (stderr, "error: bad checksum: %02x.\n", checksum); 676 return 0; 677 } 678 679 while (isspace (sum = getc (fin))) /* skip all kind of spaces */ 680 ; 681 ungetc (sum, fin); 682 } 683 while (1 != record_type); /* EOF record */ 684 685 return 1; 686} 687 688int 689main (int argc, char **argv) 690{ 691 int size = 32768, skipsize = 0, pack = 0, real_size = 0, i = 0; 692 char *token; 693 BYTE *rom; 694 FILE *fin, *fout; 695 char *filename = NULL; 696 int ret; 697 int gb = 0; 698 int sms = 0; 699 700 struct gb_opt_s gb_opt = {.cart_name="", 701 .licensee_str={'0', '0'}, 702 .mbc_type=0, 703 .nb_rom_banks=2, 704 .nb_ram_banks=0, 705 .licensee_id=0x33, 706 .is_gbc=0, 707 .is_sgb=0, 708 .sym_conversion=0, 709 .non_jp=0, 710 .rom_banks_autosize=0, 711 .do_logo_copy=true, 712 .address_overwrite={0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0} }; 713 714 struct sms_opt_s sms_opt = {.rom_size=0xa, 715 .region_code=7, 716 .version=0 }; 717 718#if defined(_WIN32) 719 setmode (fileno (stdout), O_BINARY); 720#endif 721 722 while (*++argv && '-' == argv[0][0] && '\0' != argv[0][1]) 723 { 724 switch (argv[0][1]) 725 { 726 case 's': 727 if (!*++argv) 728 { 729 usage (); 730 return 1; 731 } 732 size = strtoul (*argv, NULL, 0); 733 break; 734 735 case 't': 736 if (!*++argv) 737 { 738 usage (); 739 return 1; 740 } 741 skipsize = strtoul (*argv, NULL, 0); 742 break; 743 744 case 'h': 745 usage (); 746 return 0; 747 748 case 'p': 749 pack = 1; 750 break; 751 752 case 'Z': 753 /* generate GameBoy binary file */ 754 gb = 1; 755 break; 756 757 case 'y': 758 /* GameBoy options: 759 * -yo Number of rom banks (default: 2) 760 * -ya Number of ram banks (default: 0) 761 * -yt MBC type (default: no MBC) 762 * -yn Name of program (default: name of output file) 763 */ 764 switch (argv[0][2]) 765 { 766 case 'o': 767 if (!*++argv) 768 { 769 usage (); 770 return 1; 771 } 772 // Use auto-size for rom banks if -yto size param is 'A' 773 if ((*argv)[0] == 'A' || (*argv)[0] == 'a') 774 gb_opt.rom_banks_autosize = 1; 775 else 776 { 777 gb_opt.nb_rom_banks = strtoul (*argv, NULL, 0); 778 size = gb_opt.nb_rom_banks * 0x4000; 779 } 780 break; 781 782 case 'a': 783 if (!++argv) 784 { 785 usage (); 786 return 1; 787 } 788 gb_opt.nb_ram_banks = strtoul (*argv, NULL, 0); 789 break; 790 791 case 't': 792 if (!*++argv) 793 { 794 usage (); 795 return 1; 796 } 797 gb_opt.mbc_type = strtoul (*argv, NULL, 0); 798 break; 799 800 case 'n': 801 if (!*++argv) 802 { 803 usage (); 804 return 1; 805 } 806 strncpy (gb_opt.cart_name, *argv, CART_NAME_LEN-1); 807 gb_opt.cart_name[CART_NAME_LEN-1] = '\0'; 808 break; 809 810 case 'k': 811 if (!*++argv) 812 { 813 usage (); 814 return 1; 815 } 816 strncpy (gb_opt.licensee_str, *argv, 2); 817 break; 818 819 case 'l': 820 if (!*++argv) 821 { 822 usage (); 823 return 1; 824 } 825 gb_opt.licensee_id = strtoul (*argv, NULL, 0); 826 break; 827 828 case 'c': 829 gb_opt.is_gbc = 1; 830 break; 831 832 case 'C': 833 gb_opt.is_gbc = 2; 834 break; 835 836 case 'N': 837 gb_opt.do_logo_copy = false; // when switch is present, turn off logo copy 838 break; 839 840 case 's': 841 gb_opt.is_sgb = 1; 842 break; 843 844 case 'S': 845 gb_opt.sym_conversion = 1; 846 break; 847 848 case 'j': 849 gb_opt.non_jp = 1; 850 break; 851 852 // like -yp0x143=0x80 853 case 'p': 854 // remove "-yp" 855 *argv += 3; 856 // effectively split string into argv and token 857 strtok(*argv, "="); 858 token = strtok(NULL, "="); 859 for (i = 0; i < 16; i+=2) 860 { 861 if(gb_opt.address_overwrite[i] == 0xFF) 862 { 863 gb_opt.address_overwrite[i] = strtoul (*argv, NULL, 0); 864 gb_opt.address_overwrite[i+1] = strtoul (token, NULL, 0); 865 break; 866 } 867 } 868 break; 869 870 default: 871 usage (); 872 return 1; 873 } 874 break; 875 876 case 'S': 877 /* generate SMS binary file */ 878 sms = 1; 879 break; 880 881 case 'x': 882 883 switch (argv[0][2]) 884 { 885 case 'o': 886 if (!*++argv) 887 { 888 usage (); 889 return 1; 890 } 891 sms_opt.rom_size = strtoul (*argv, NULL, 0); 892 if ( sms_opt.rom_size > 2 && (sms_opt.rom_size < 0xa || sms_opt.rom_size > 0xf ) ) 893 { 894 fprintf (stderr, "error: invalid rom size (0x%X)", sms_opt.rom_size); 895 perror(NULL); 896 return 1; 897 } 898 if ( sms_opt.rom_size == 0xd || sms_opt.rom_size == 0x2 ) 899 { 900 fprintf (stderr, "warning: this rom size (0x%X) is bugged in some BIOSes\n", sms_opt.rom_size); 901 } 902 break; 903 904 case 'j': 905 if (!*++argv) 906 { 907 usage (); 908 return 1; 909 } 910 sms_opt.region_code = strtoul (*argv, NULL, 0); 911 if ( sms_opt.region_code < 3 && sms_opt.region_code > 7 ) 912 { 913 fprintf (stderr, "error: invalid region code (0x%X)", sms_opt.region_code); 914 perror(NULL); 915 return 1; 916 } 917 break; 918 919 case 'v': 920 if (!*++argv) 921 { 922 usage (); 923 return 1; 924 } 925 sms_opt.version = strtoul (*argv, NULL, 0); 926 if ( sms_opt.version > 0xf ) 927 { 928 fprintf (stderr, "error: invalid version (0x%X)", sms_opt.version); 929 perror(NULL); 930 return 1; 931 } 932 break; 933 934 default: 935 usage (); 936 return 1; 937 } 938 break; 939 940 default: 941 usage (); 942 return 1; 943 } 944 } 945 946 fin = stdin; 947 fout = stdout; 948 if (*argv) 949 { 950 if ('-' != argv[0][0] || '\0' != argv[0][1]) 951 { 952 if (NULL == (fin = fopen (*argv, "r"))) 953 { 954 fprintf (stderr, "error: can't open %s: ", *argv); 955 perror(NULL); 956 return 1; 957 } 958 filename = *argv; 959 } 960 ++argv; 961 } 962 963 if (NULL != argv[0] && NULL != argv[1]) 964 { 965 usage (); 966 return 1; 967 } 968 969 rom = malloc (size); 970 if (rom == NULL) 971 { 972 fclose (fin); 973 fprintf (stderr, "error: couldn't allocate room for the image.\n"); 974 return 1; 975 } 976 memset (rom, FILL_BYTE, size); 977 978 if (gb_opt.sym_conversion == 1) 979 { 980 if (filename) 981 noi2sym(filename); 982 else 983 { 984 fprintf (stderr, "error: .noi to .sym conversion needs an input file.\n"); 985 } 986 } 987 988 ret = read_ihx (fin, &rom, &size, &real_size, &gb_opt); 989 990 fclose (fin); 991 992 if (ret) 993 { 994 if (gb) 995 gb_postproc (rom, size, &real_size, &gb_opt); 996 else if (sms) 997 sms_postproc (rom, size, &real_size, &sms_opt); 998 999 if (*argv) 1000 { 1001 if ('-' != argv[0][0] || '\0' != argv[0][1]) 1002 { 1003 if (NULL == (fout = fopen (*argv, "wb"))) 1004 { 1005 fprintf (stderr, "error: can't create %s: ", *argv); 1006 perror(NULL); 1007 return 1; 1008 } 1009 } 1010 } 1011 1012 int writesize = (pack ? real_size : size) - skipsize; 1013 if (writesize > 0) fwrite (rom + skipsize, 1, writesize, fout); 1014 1015 fclose (fout); 1016 1017 return 0; 1018 } 1019 else 1020 return 1; 1021} 1022