diff options
| author | Louis Burda <quent.burda@gmail.com> | 2022-06-02 15:28:40 +0200 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2022-06-02 15:28:40 +0200 |
| commit | 5bc16063c29aa4d3d287ebd163ccdbcbf54c4f9f (patch) | |
| tree | c131f947a37b3af2d14d41e9eda098bdec2d061c /gbdk/gbdk-support/makebin/makebin.c | |
| parent | 78a5f810b22f0d8cafa05f638b0cb2e889824859 (diff) | |
| download | cscg2022-gearboy-master.tar.gz cscg2022-gearboy-master.zip | |
Diffstat (limited to 'gbdk/gbdk-support/makebin/makebin.c')
| -rw-r--r-- | gbdk/gbdk-support/makebin/makebin.c | 1022 |
1 files changed, 1022 insertions, 0 deletions
diff --git a/gbdk/gbdk-support/makebin/makebin.c b/gbdk/gbdk-support/makebin/makebin.c new file mode 100644 index 00000000..b279a539 --- /dev/null +++ b/gbdk/gbdk-support/makebin/makebin.c @@ -0,0 +1,1022 @@ +/* + makebin - turn a .ihx file into a binary image or GameBoy format binaryimage + + Copyright (c) 2000 Michael Hope + Copyright (c) 2010 Borut Razem + Copyright (c) 2012 Noel Lemouel + Copyright (c) 2020-2021 Sebastian 'basxto' Riedel + Copyright (c) 2020 'bbbbbr' + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> + +#if defined(_WIN32) +#include <fcntl.h> +#include <io.h> +#else +#include <unistd.h> +#endif + + +typedef unsigned char BYTE; + +#define FILL_BYTE 0xff + +int +getnibble (FILE *fin) +{ + int ret; + int c = getc (fin); + + if (feof (fin) || ferror (fin)) + { + fprintf (stderr, "error: unexpected end of file.\n"); + exit (6); + } + + ret = c - '0'; + if (ret > 9) + { + ret -= 'A' - '9' - 1; + } + + if (ret > 0xf) + { + ret -= 'a' - 'A'; + } + + if (ret < 0 || ret > 0xf) + { + fprintf (stderr, "error: character %02x.\n", ret); + exit (7); + } + return ret; +} + +int +getbyte (FILE *fin, int *sum) +{ + int b = (getnibble (fin) << 4) | getnibble (fin); + *sum += b; + return b; +} + +void +usage (void) +{ + fprintf (stderr, + "makebin: convert a Intel IHX file to binary or GameBoy format binary.\n" + "Usage: makebin [options] [<in_file> [<out_file>]]\n" + "Options:\n" + " -p pack mode: the binary file size will be truncated to the last occupied byte\n" + " -s romsize size of the binary file (default: rom banks * 16384)\n" + " -Z generate GameBoy format binary file\n" + " -S generate Sega Master System format binary file\n" + " -t size skip size bytes from the beginning of the rom" + + "SMS format options (applicable only with -S option):\n" + " -xo n rom size (0xa-0x2)\n" + " -xj n set region code (3-7)\n" + //" -xc n product code (0-159999)\n" + " -xv n version number (0-15)\n" + //" -xV n SDSC version number\n" + //" -xd n SDSC date\n" + //" -xA n SDSC author pointer\n" + //" -xn n SDSC program name pointer\n" + //" -xD n SDSC description pointer\n" + + "GameBoy format options (applicable only with -Z option):\n" + " -yo n number of rom banks (default: 2) (autosize: A)\n" + " -ya n number of ram banks (default: 0)\n" + " -yt n MBC type (default: no MBC)\n" + " -yl n old licensee code (default: 0x33)\n" + " -yk cc new licensee string (default: 00)\n" + " -yn name cartridge name (default: none)\n" + " -yc GameBoy Color compatible\n" + " -yC GameBoy Color only\n" + " -ys Super GameBoy\n" + " -yS Convert .noi file named like input file to .sym\n" + " -yj set non-Japanese region flag\n" + " -yN do not copy big N validation logo into ROM header\n" + " -yp addr=value Set address in ROM to given value (address 0x100-0x1FE)\n" + "Arguments:\n" + " <in_file> optional IHX input file, '-' means stdin. (default: stdin)\n" + " <out_file> optional output file, '-' means stdout. (default: stdout)\n"); +} + +#define CART_NAME_LEN 16 + +struct gb_opt_s +{ + char cart_name[CART_NAME_LEN]; /* cartridge name buffer */ + char licensee_str[2]; /* new licensee string */ + BYTE mbc_type; /* MBC type (default: no MBC) */ + short nb_rom_banks; /* Number of rom banks (default: 2) */ + BYTE nb_ram_banks; /* Number of ram banks (default: 0) */ + BYTE licensee_id; /* old licensee code */ + BYTE is_gbc; /* 1 if GBC compatible, 2 if GBC only, false for all other*/ + BYTE is_sgb; /* True if SGB, false for all other*/ + BYTE sym_conversion; /* True if .noi file should be converted to .sym (default false)*/ + BYTE non_jp; /* True if non-Japanese region, false for all other*/ + BYTE rom_banks_autosize; /* True if rom banks should be auto-sized (default false)*/ + bool do_logo_copy; /* True if the nintendo logo should be copied into the ROM (default true) */ + BYTE address_overwrite[16]; /* For limited compatibility with very old versions */ +}; + +struct sms_opt_s +{ + BYTE rom_size; /* Doesn't have to be the real size, needed for checksum */ + BYTE region_code; /* Region code Japan/Export/International and SMS/GG */ + BYTE version; /* Game version */ +}; + +void +gb_postproc (BYTE * rom, int size, int *real_size, struct gb_opt_s *o) +{ + int i, chk; + static const BYTE gb_logo[] = + { + 0xce, 0xed, 0x66, 0x66, 0xcc, 0x0d, 0x00, 0x0b, + 0x03, 0x73, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x0d, + 0x00, 0x08, 0x11, 0x1f, 0x88, 0x89, 0x00, 0x0e, + 0xdc, 0xcc, 0x6e, 0xe6, 0xdd, 0xdd, 0xd9, 0x99, + 0xbb, 0xbb, 0x67, 0x63, 0x6e, 0x0e, 0xec, 0xcc, + 0xdd, 0xdc, 0x99, 0x9f, 0xbb, 0xb9, 0x33, 0x3e + }; + + /* $0104-$0133: Nintendo logo + * If missing, an actual Game Boy won't run the ROM. + */ + + if (o->do_logo_copy) + { + memcpy (&rom[0x104], gb_logo, sizeof (gb_logo)); + } + + rom[0x144] = o->licensee_str[0]; + rom[0x145] = o->licensee_str[1]; + + /* + * 0134-0142: Title of the game in UPPER CASE ASCII. If it + * is less than 16 characters then the + * remaining bytes are filled with 00's. + */ + + /* capitalize cartridge name */ + for (i = 0; i < CART_NAME_LEN; ++i) + { + rom[0x134 + i] = toupper (o->cart_name[i]); + } + + if (o->is_gbc == 1) + { + rom[0x143] = 0x80; + } + + if (o->is_gbc == 2) + { + rom[0x143] = 0xC0; + } + + if (o->is_sgb) + { + rom[0x146] = 0x03; + } + + /* + * 0147: Cartridge type: + * 0-ROM ONLY 12-ROM+MBC3+RAM + * 1-ROM+MBC1 13-ROM+MBC3+RAM+BATT + * 2-ROM+MBC1+RAM 19-ROM+MBC5 + * 3-ROM+MBC1+RAM+BATT 1A-ROM+MBC5+RAM + * 5-ROM+MBC2 1B-ROM+MBC5+RAM+BATT + * 6-ROM+MBC2+BATTERY 1C-ROM+MBC5+RUMBLE + * 8-ROM+RAM 1D-ROM+MBC5+RUMBLE+SRAM + * 9-ROM+RAM+BATTERY 1E-ROM+MBC5+RUMBLE+SRAM+BATT + * B-ROM+MMM01 1F-Pocket Camera + * C-ROM+MMM01+SRAM FD-Bandai TAMA5 + * D-ROM+MMM01+SRAM+BATT FE - Hudson HuC-3 + * F-ROM+MBC3+TIMER+BATT FF - Hudson HuC-1 + * 10-ROM+MBC3+TIMER+RAM+BATT + * 11-ROM+MBC3 + */ + rom[0x147] = o->mbc_type; + + /* + * 0148 ROM size: + * 0 - 256Kbit = 32KByte = 2 banks + * 1 - 512Kbit = 64KByte = 4 banks + * 2 - 1Mbit = 128KByte = 8 banks + * 3 - 2Mbit = 256KByte = 16 banks + * 4 - 4Mbit = 512KByte = 32 banks + * 5 - 8Mbit = 1MByte = 64 banks + * 6 - 16Mbit = 2MByte = 128 banks + * $52 - 9Mbit = 1.1MByte = 72 banks + * $53 - 10Mbit = 1.2MByte = 80 banks + * $54 - 12Mbit = 1.5MByte = 96 banks + */ + switch (o->nb_rom_banks) + { + case 2: + rom[0x148] = 0; + break; + + case 4: + rom[0x148] = 1; + break; + + case 8: + rom[0x148] = 2; + break; + + case 16: + rom[0x148] = 3; + break; + + case 32: + rom[0x148] = 4; + break; + + case 64: + rom[0x148] = 5; + break; + + case 128: + rom[0x148] = 6; + break; + + case 256: + rom[0x148] = 7; + break; + + case 512: + rom[0x148] = 8; + break; + + default: + fprintf (stderr, "warning: unsupported number of ROM banks (%d)\n", o->nb_rom_banks); + rom[0x148] = 0; + break; + } + + /* + * 0149 RAM size: + * 0 - None + * 1 - 16kBit = 2kB = 1 bank + * 2 - 64kBit = 8kB = 1 bank + * 3 - 256kBit = 32kB = 4 banks + * 4 - 1MBit =128kB =16 banks + */ + switch (o->nb_ram_banks) + { + case 0: + rom[0x149] = 0; + break; + + case 1: + rom[0x149] = 2; + break; + + case 4: + rom[0x149] = 3; + break; + + case 16: + rom[0x149] = 4; + break; + + default: + fprintf (stderr, "warning: unsupported number of RAM banks (%d)\n", o->nb_ram_banks); + rom[0x149] = 0; + break; + } + + rom[0x14A] = o->non_jp; + + rom[0x14B] = o->licensee_id; + + for (i = 0; i < 16; i+=2) + { + if(o->address_overwrite[i] != 0xFF) + { + rom[0x0100 & o->address_overwrite[i]] = o->address_overwrite[i+1]; + // warnings for builds ported from ancient GBDK + fprintf (stderr, "caution: -yp0x01%02x=0x%02x is outdated", o->address_overwrite[i], o->address_overwrite[i+1]); + if(o->address_overwrite[i] == 0x43) + switch(o->address_overwrite[i+1]&0xC0) + { + case 0x80: + fprintf (stderr, ", please use -yc instead"); + break; + case 0xC0: + fprintf (stderr, ", please use -yC instead"); + break; + default: + o->address_overwrite[i] = 0xFF; + } + if(o->address_overwrite[i] == 0x44 || o->address_overwrite[i] == 0x45) + fprintf (stderr, ", please use -yk cc instead"); + if(o->address_overwrite[i] == 0x46) + if(o->address_overwrite[i+1] == 0x03) + fprintf (stderr, ", please use -ys instead"); + else + o->address_overwrite[i] = 0xFF; + if(o->address_overwrite[i] == 0x47) + fprintf (stderr, ", please use -yt 0x%02x instead", o->address_overwrite[i+1]); + if(o->address_overwrite[i] == 0x4A) + fprintf (stderr, ", please use -yl 0x%02x instead", o->address_overwrite[i+1]); + if(o->address_overwrite[i] == 0x4B && o->address_overwrite[i+1] == 1) + fprintf (stderr, ", please use -yj instead"); + if(o->address_overwrite[i] == 0xFF) + fprintf (stderr, ", this setting is the default"); + fprintf (stderr, ".\n"); + } + } + + /* Update complement checksum */ + chk = 0; + for (i = 0x134; i < 0x14d; ++i) + chk += rom[i]; + rom[0x014d] = (unsigned char) (0xe7 - (chk & 0xff)); + + /* Update checksum */ + chk = 0; + rom[0x14e] = 0; + rom[0x14f] = 0; + for (i = 0; i < size; ++i) + chk += rom[i]; + rom[0x14e] = (unsigned char) ((chk >> 8) & 0xff); + rom[0x14f] = (unsigned char) (chk & 0xff); + + if (*real_size < 0x150) + *real_size = 0x150; +} + +void +sms_postproc (BYTE * rom, int size, int *real_size, struct sms_opt_s *o) +{ + // based on https://www.smspower.org/Development/ROMHeader + // 0x1ff0 and 0x3ff0 are also possible, but never used + static const char tmr_sega[] = "TMR SEGA "; + short header_base = 0x7ff0; + int chk = 0; + unsigned long i; + // choose earlier positions for smaller roms + if (header_base > size) + header_base = 0x3ff0; + if (header_base > size) + header_base = 0x1ff0; + + memcpy (&rom[header_base], tmr_sega, sizeof (tmr_sega) - 1); + // configure amounts of bytes to check + switch(o->rom_size) + { + case 0xa: + default: + i = 0x1FEF; + break; + case 0xb: + i = 0x3FEF; + break; + case 0xc: + i = 0x7FEF; + break; + case 0xd: + i = 0xBFEF; + break; + case 0xe: + i = 0xFFFF; + break; + case 0xf: + i = 0x1FFFF; + break; + case 0x0: + i = 0x3FFFF; + break; + case 0x1: + i = 0x7FFFF; + break; + case 0x2: + i = 0xFFFFF; + break; + } + // calculate checksum + for(;i > 0; --i) + { + chk += rom[i]; + // 0x7FF0 - 0x7FFF is skipped + if(i == 0x8000) + i = 0x7FF0; + } + // we skipped index 0 + chk += rom[0]; + // little endian + rom[header_base + 0xa] = chk & 0xff; + rom[header_base + 0xb] = (chk>>8) & 0xff; + // game version + rom[header_base + 0xe] &= 0xF0; + rom[header_base + 0xe] |= o->version; + // rom size + rom[header_base + 0xf] = (o->region_code << 4) | o->rom_size; +} + +int +rom_autosize_grow(BYTE **rom, int test_size, int *size, struct gb_opt_s *o) +{ + int last_size = *size; + + while ((test_size > *size) && (o->nb_rom_banks <= 512)) + { + o->nb_rom_banks *= 2; + // banks work differently for mbc6, they have half the size + // but this in general ignored by -yo + *size = o->nb_rom_banks * 0x4000; + } + + if (o->nb_rom_banks > 512) + { + fprintf (stderr, "error: auto-size banks exceeded max of 512 banks.\n"); + return 0; + } + else + { + BYTE * t_rom = *rom; + *rom = realloc (*rom, *size); + if (*rom == NULL) + { + free(t_rom); + fprintf (stderr, "error: couldn't re-allocate size for larger rom image.\n"); + return 0; + } + memset (*rom + last_size, FILL_BYTE, *size - last_size); + } + + return 1; +} + +int +noi2sym (char *filename) +{ + FILE *noi, *sym; + char *nname, *sname; + //ssize_t read; + char read = ' '; + // no$gmb's implementation is limited to 32 character labels + // we can safely throw away the rest + char label[33]; + // 0x + 6 digit hex number + // -> 65536 rom banks is the maximum homebrew cartrideges support (TPP1) + char value[9]; + int name_len = strlen(filename); + int i = 0; + // copy filename's value to nname and sname + nname = malloc((name_len+1) * sizeof(char)); + strcpy (nname, filename); + sname = malloc((name_len+1) * sizeof(char)); + strcpy (sname, filename); + // change the extensions + nname[name_len-1]='i'; + nname[name_len-2]='o'; + nname[name_len-3]='n'; + sname[name_len-1]='m'; + sname[name_len-2]='y'; + sname[name_len-3]='s'; + + if (NULL == (noi = fopen (nname, "r"))) + { + fprintf (stderr, "error: can't open %s: ", nname); + perror(NULL); + return 1; + } + if (NULL == (sym = fopen (sname, "w"))) + { + fprintf (stderr, "error: can't create %s: ", sname); + perror(NULL); + return 1; + } + // write header + fprintf (sym, "; no$gmb compatible .sym file\n; Generated automagically by makebin\n"); + // iterate through .noi file + while (read != EOF && (read = fgetc(noi)) != EOF) + { + // just skip line breaks + if (read == '\r' || read == '\n') + continue; + // read first 4 chars + for (i = 0; i < 4; ++i) + { + value[i] = read; + if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n') + { + // leave for-loop + break; + } + } + // we left loop early + if (i != 4) + continue; + // only accept if line starts with this + if (strncmp(value, "DEF ", 4) == 0) + { + // read label + for (i = 0; i < 32; ++i) + { + label[i] = read; + if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n' || read == ' ') + { + // leave for-loop + break; + } + } + // skip rest of the label + while (read != EOF && read != '\r' && read != '\n' && read != ' ') + read = fgetc(noi); + // it has to be end of file or line if it's not space + if (read != ' ') + continue; + // strings have to end with \0 + label[i+1] = '\0'; + // read value + for (i = 0; i < 8; ++i) + { + value[i] = read; + if ((read = fgetc(noi)) == EOF || read == '\r' || read == '\n') + { + // leave for-loop + break; + } + } + // number is too long; ignore + if (read != EOF && read != '\r' && read != '\n') + continue; + value[i+1] = '\0'; + // we successfully read label and value + + // but filter out some invalid symbols + if (strcmp(label, ".__.ABS.") != 0 && strncmp(label, "l__", 3) != 0) + fprintf (sym, "%02X:%04X %s\n", (unsigned int)(strtoul(value, NULL, 0)>>16), (unsigned int)strtoul(value, NULL, 0)&0xFFFF, label); + } + else + // skip until file/line end + while ((read = fgetc(noi))!= EOF && read != '\r' && read != '\n'); + } + + // free close files + fclose (noi); + fclose (sym); + + fprintf (stderr, "Converted %s to %s.\n", nname, sname); + return 0; +} + +int +read_ihx (FILE *fin, BYTE **rom, int *size, int *real_size, struct gb_opt_s *o) +{ + int record_type; + + int extaddr = 0; + do + { + int nbytes; + int addr; + int checksum, sum = 0; + + if (getc (fin) != ':') + { + fprintf (stderr, "error: invalid IHX line.\n"); + return 0; + } + nbytes = getbyte (fin, &sum); + addr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); + record_type = getbyte (fin, &sum); + if(record_type == 4) + { + extaddr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); + extaddr <<= 16; // those are the upper 16 bits + checksum = getbyte (fin, &sum); + // move to the next record + if (0 != (sum & 0xff)) + { + fprintf (stderr, "error: bad checksum: %02x.\n", checksum); + return 0; + } + while (isspace (sum = getc (fin))) /* skip all kind of spaces */ + ; + ungetc (sum, fin); + if (getc (fin) != ':') + { + fprintf (stderr, "error: invalid IHX line.\n"); + return 0; + } + // parse real data part + checksum = sum = 0; + nbytes = getbyte (fin, &sum); + // lower 16 bits + addr = getbyte (fin, &sum) << 8 | getbyte (fin, &sum); + record_type = getbyte (fin, &sum); + } + // add linear address extension + addr |= extaddr; + // TODO: warn for unreachable banks according to chosen MBC + if (record_type > 1) + { + fprintf (stderr, "error: unsupported record type: %02x.\n", record_type); + return 0; + } + + if (addr + nbytes > *size) + { + // If auto-size is enabled, grow rom bank size by power of 2 when needed + if (o->rom_banks_autosize) + { + if (rom_autosize_grow(rom, addr + nbytes, size, o) == 0) + return 0; + } + else + { + fprintf (stderr, "error: size of the buffer is too small.\n"); + return 0; + } + } + + while (nbytes--) + { + if (addr < *size) + (*rom)[addr++] = getbyte (fin, &sum); + } + + if (addr > *real_size) + *real_size = addr; + + checksum = getbyte (fin, &sum); + if (0 != (sum & 0xff)) + { + fprintf (stderr, "error: bad checksum: %02x.\n", checksum); + return 0; + } + + while (isspace (sum = getc (fin))) /* skip all kind of spaces */ + ; + ungetc (sum, fin); + } + while (1 != record_type); /* EOF record */ + + return 1; +} + +int +main (int argc, char **argv) +{ + int size = 32768, skipsize = 0, pack = 0, real_size = 0, i = 0; + char *token; + BYTE *rom; + FILE *fin, *fout; + char *filename = NULL; + int ret; + int gb = 0; + int sms = 0; + + struct gb_opt_s gb_opt = {.cart_name="", + .licensee_str={'0', '0'}, + .mbc_type=0, + .nb_rom_banks=2, + .nb_ram_banks=0, + .licensee_id=0x33, + .is_gbc=0, + .is_sgb=0, + .sym_conversion=0, + .non_jp=0, + .rom_banks_autosize=0, + .do_logo_copy=true, + .address_overwrite={0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0} }; + + struct sms_opt_s sms_opt = {.rom_size=0xa, + .region_code=7, + .version=0 }; + +#if defined(_WIN32) + setmode (fileno (stdout), O_BINARY); +#endif + + while (*++argv && '-' == argv[0][0] && '\0' != argv[0][1]) + { + switch (argv[0][1]) + { + case 's': + if (!*++argv) + { + usage (); + return 1; + } + size = strtoul (*argv, NULL, 0); + break; + + case 't': + if (!*++argv) + { + usage (); + return 1; + } + skipsize = strtoul (*argv, NULL, 0); + break; + + case 'h': + usage (); + return 0; + + case 'p': + pack = 1; + break; + + case 'Z': + /* generate GameBoy binary file */ + gb = 1; + break; + + case 'y': + /* GameBoy options: + * -yo Number of rom banks (default: 2) + * -ya Number of ram banks (default: 0) + * -yt MBC type (default: no MBC) + * -yn Name of program (default: name of output file) + */ + switch (argv[0][2]) + { + case 'o': + if (!*++argv) + { + usage (); + return 1; + } + // Use auto-size for rom banks if -yto size param is 'A' + if ((*argv)[0] == 'A' || (*argv)[0] == 'a') + gb_opt.rom_banks_autosize = 1; + else + { + gb_opt.nb_rom_banks = strtoul (*argv, NULL, 0); + size = gb_opt.nb_rom_banks * 0x4000; + } + break; + + case 'a': + if (!++argv) + { + usage (); + return 1; + } + gb_opt.nb_ram_banks = strtoul (*argv, NULL, 0); + break; + + case 't': + if (!*++argv) + { + usage (); + return 1; + } + gb_opt.mbc_type = strtoul (*argv, NULL, 0); + break; + + case 'n': + if (!*++argv) + { + usage (); + return 1; + } + strncpy (gb_opt.cart_name, *argv, CART_NAME_LEN-1); + gb_opt.cart_name[CART_NAME_LEN-1] = '\0'; + break; + + case 'k': + if (!*++argv) + { + usage (); + return 1; + } + strncpy (gb_opt.licensee_str, *argv, 2); + break; + + case 'l': + if (!*++argv) + { + usage (); + return 1; + } + gb_opt.licensee_id = strtoul (*argv, NULL, 0); + break; + + case 'c': + gb_opt.is_gbc = 1; + break; + + case 'C': + gb_opt.is_gbc = 2; + break; + + case 'N': + gb_opt.do_logo_copy = false; // when switch is present, turn off logo copy + break; + + case 's': + gb_opt.is_sgb = 1; + break; + + case 'S': + gb_opt.sym_conversion = 1; + break; + + case 'j': + gb_opt.non_jp = 1; + break; + + // like -yp0x143=0x80 + case 'p': + // remove "-yp" + *argv += 3; + // effectively split string into argv and token + strtok(*argv, "="); + token = strtok(NULL, "="); + for (i = 0; i < 16; i+=2) + { + if(gb_opt.address_overwrite[i] == 0xFF) + { + gb_opt.address_overwrite[i] = strtoul (*argv, NULL, 0); + gb_opt.address_overwrite[i+1] = strtoul (token, NULL, 0); + break; + } + } + break; + + default: + usage (); + return 1; + } + break; + + case 'S': + /* generate SMS binary file */ + sms = 1; + break; + + case 'x': + + switch (argv[0][2]) + { + case 'o': + if (!*++argv) + { + usage (); + return 1; + } + sms_opt.rom_size = strtoul (*argv, NULL, 0); + if ( sms_opt.rom_size > 2 && (sms_opt.rom_size < 0xa || sms_opt.rom_size > 0xf ) ) + { + fprintf (stderr, "error: invalid rom size (0x%X)", sms_opt.rom_size); + perror(NULL); + return 1; + } + if ( sms_opt.rom_size == 0xd || sms_opt.rom_size == 0x2 ) + { + fprintf (stderr, "warning: this rom size (0x%X) is bugged in some BIOSes\n", sms_opt.rom_size); + } + break; + + case 'j': + if (!*++argv) + { + usage (); + return 1; + } + sms_opt.region_code = strtoul (*argv, NULL, 0); + if ( sms_opt.region_code < 3 && sms_opt.region_code > 7 ) + { + fprintf (stderr, "error: invalid region code (0x%X)", sms_opt.region_code); + perror(NULL); + return 1; + } + break; + + case 'v': + if (!*++argv) + { + usage (); + return 1; + } + sms_opt.version = strtoul (*argv, NULL, 0); + if ( sms_opt.version > 0xf ) + { + fprintf (stderr, "error: invalid version (0x%X)", sms_opt.version); + perror(NULL); + return 1; + } + break; + + default: + usage (); + return 1; + } + break; + + default: + usage (); + return 1; + } + } + + fin = stdin; + fout = stdout; + if (*argv) + { + if ('-' != argv[0][0] || '\0' != argv[0][1]) + { + if (NULL == (fin = fopen (*argv, "r"))) + { + fprintf (stderr, "error: can't open %s: ", *argv); + perror(NULL); + return 1; + } + filename = *argv; + } + ++argv; + } + + if (NULL != argv[0] && NULL != argv[1]) + { + usage (); + return 1; + } + + rom = malloc (size); + if (rom == NULL) + { + fclose (fin); + fprintf (stderr, "error: couldn't allocate room for the image.\n"); + return 1; + } + memset (rom, FILL_BYTE, size); + + if (gb_opt.sym_conversion == 1) + { + if (filename) + noi2sym(filename); + else + { + fprintf (stderr, "error: .noi to .sym conversion needs an input file.\n"); + } + } + + ret = read_ihx (fin, &rom, &size, &real_size, &gb_opt); + + fclose (fin); + + if (ret) + { + if (gb) + gb_postproc (rom, size, &real_size, &gb_opt); + else if (sms) + sms_postproc (rom, size, &real_size, &sms_opt); + + if (*argv) + { + if ('-' != argv[0][0] || '\0' != argv[0][1]) + { + if (NULL == (fout = fopen (*argv, "wb"))) + { + fprintf (stderr, "error: can't create %s: ", *argv); + perror(NULL); + return 1; + } + } + } + + int writesize = (pack ? real_size : size) - skipsize; + if (writesize > 0) fwrite (rom + skipsize, 1, writesize, fout); + + fclose (fout); + + return 0; + } + else + return 1; +} + |
