2 makebin - turn a .ihx file into a binary image or GameBoy format binaryimage
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'
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.
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:
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.
42 typedef unsigned char BYTE
;
44 #define FILL_BYTE 0xff
52 if (feof (fin
) || ferror (fin
))
54 fprintf (stderr
, "error: unexpected end of file.\n");
69 if (ret
< 0 || ret
> 0xf)
71 fprintf (stderr
, "error: character %02x.\n", ret
);
78 getbyte (FILE *fin
, int *sum
)
80 int b
= (getnibble (fin
) << 4) | getnibble (fin
);
89 "makebin: convert a Intel IHX file to binary or GameBoy format binary.\n"
90 "Usage: makebin [options] [<in_file> [<out_file>]]\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 " -o bytes skip amount of bytes in binary file\n"
98 "SMS format options (applicable only with -S option):\n"
99 " -xo n rom size (0xa-0x2) (default: 0xc)\n"
100 " -xj n set region code (3-7) (default: 4)\n"
101 //" -xc n product code (0-159999)\n"
102 " -xv n version number (0-15) (default: 0)\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"
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"
124 " <in_file> optional IHX input file, '-' means stdin. (default: stdin)\n"
125 " <out_file> optional output file, '-' means stdout. (default: stdout)\n");
128 #define CART_NAME_LEN 16
132 char cart_name
[CART_NAME_LEN
]; /* cartridge name buffer */
133 char licensee_str
[3]; /* 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 */
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 */
155 gb_postproc (BYTE
* rom
, int size
, int *real_size
, struct gb_opt_s
*o
)
158 static const BYTE gb_logo
[] =
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
168 /* $0104-$0133: Nintendo logo
169 * If missing, an actual Game Boy won't run the ROM.
174 memcpy (&rom
[0x104], gb_logo
, sizeof (gb_logo
));
177 rom
[0x144] = o
->licensee_str
[0];
178 rom
[0x145] = o
->licensee_str
[1];
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.
186 /* capitalize cartridge name */
187 for (i
= 0; i
< CART_NAME_LEN
; ++i
)
189 rom
[0x134 + i
] = toupper (o
->cart_name
[i
]);
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
224 rom
[0x147] = o
->mbc_type
;
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
239 switch (o
->nb_rom_banks
)
278 fprintf (stderr
, "warning: unsupported number of ROM banks (%d)\n", o
->nb_rom_banks
);
286 * 1 - 16kBit = 2kB = 1 bank
287 * 2 - 64kBit = 8kB = 1 bank
288 * 3 - 256kBit = 32kB = 4 banks
289 * 4 - 1MBit =128kB =16 banks
291 switch (o
->nb_ram_banks
)
310 fprintf (stderr
, "warning: unsupported number of RAM banks (%d)\n", o
->nb_ram_banks
);
315 rom
[0x14A] = o
->non_jp
;
317 rom
[0x14B] = o
->licensee_id
;
319 for (i
= 0; i
< 16; i
+=2)
321 if(o
->address_overwrite
[i
] != 0xFF)
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)
330 fprintf (stderr
, ", please use -yc instead");
333 fprintf (stderr
, ", please use -yC instead");
336 o
->address_overwrite
[i
] = 0xFF;
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");
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");
357 /* Update complement checksum */
359 for (i
= 0x134; i
< 0x14d; ++i
)
361 rom
[0x014d] = (unsigned char) (0xe7 - (chk
& 0xff));
363 /* Update checksum */
367 for (i
= 0; i
< size
; ++i
)
369 rom
[0x14e] = (unsigned char) ((chk
>> 8) & 0xff);
370 rom
[0x14f] = (unsigned char) (chk
& 0xff);
372 if (*real_size
< 0x150)
377 sms_postproc (BYTE
* rom
, int size
, int *real_size
, struct sms_opt_s
*o
)
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;
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;
391 memcpy (&rom
[header_base
], tmr_sega
, sizeof (tmr_sega
) - 1);
392 // configure amounts of bytes to check
424 // calculate checksum
428 // 0x7FF0 - 0x7FFF is skipped
432 // we skipped index 0
435 rom
[header_base
+ 0xa] = chk
& 0xff;
436 rom
[header_base
+ 0xb] = (chk
>>8) & 0xff;
438 rom
[header_base
+ 0xe] &= 0xF0;
439 rom
[header_base
+ 0xe] |= o
->version
;
441 rom
[header_base
+ 0xf] = (o
->region_code
<< 4) | o
->rom_size
;
445 rom_autosize_grow(BYTE
**rom
, int test_size
, int *size
, struct gb_opt_s
*o
)
447 int last_size
= *size
;
449 while ((test_size
> *size
) && (o
->nb_rom_banks
<= 512))
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;
457 if (o
->nb_rom_banks
> 512)
459 fprintf (stderr
, "error: auto-size banks exceeded max of 512 banks.\n");
465 *rom
= realloc (*rom
, *size
);
469 fprintf (stderr
, "error: couldn't re-allocate size for larger rom image.\n");
472 memset (*rom
+ last_size
, FILL_BYTE
, *size
- last_size
);
479 noi2sym (char *filename
)
485 // no$gmb's implementation is limited to 32 character labels
486 // we can safely throw away the rest
487 #define SYM_FILE_NAME_LEN_MAX 32
488 char label
[SYM_FILE_NAME_LEN_MAX
+ 1];
489 // 0x + 6 digit hex number
490 // -> 65536 rom banks is the maximum homebrew cartrideges support (TPP1)
492 int name_len
= strlen(filename
);
494 // copy filename's value to nname and sname
495 nname
= malloc((name_len
+1) * sizeof(char));
496 strcpy (nname
, filename
);
497 sname
= malloc((name_len
+1) * sizeof(char));
498 strcpy (sname
, filename
);
499 // change the extensions
500 nname
[name_len
-1]='i';
501 nname
[name_len
-2]='o';
502 nname
[name_len
-3]='n';
503 sname
[name_len
-1]='m';
504 sname
[name_len
-2]='y';
505 sname
[name_len
-3]='s';
507 if (NULL
== (noi
= fopen (nname
, "r")))
509 fprintf (stderr
, "error: can't open %s: ", nname
);
513 if (NULL
== (sym
= fopen (sname
, "w")))
515 fprintf (stderr
, "error: can't create %s: ", sname
);
520 fprintf (sym
, "; no$gmb compatible .sym file\n; Generated automagically by makebin\n");
521 // iterate through .noi file
522 while (read
!= EOF
&& (read
= fgetc(noi
)) != EOF
)
524 // just skip line breaks
525 if (read
== '\r' || read
== '\n')
527 // read first 4 chars
528 for (i
= 0; i
< 4; ++i
)
531 if ((read
= fgetc(noi
)) == EOF
|| read
== '\r' || read
== '\n')
537 // we left loop early
540 // only accept if line starts with this
541 if (strncmp(value
, "DEF ", 4) == 0)
544 for (i
= 0; i
< (SYM_FILE_NAME_LEN_MAX
- 1); ++i
)
547 if ((read
= fgetc(noi
)) == EOF
|| read
== '\r' || read
== '\n' || read
== ' ')
553 // skip rest of the label
554 while (read
!= EOF
&& read
!= '\r' && read
!= '\n' && read
!= ' ')
556 // it has to be end of file or line if it's not space
559 // strings have to end with \0
562 for (i
= 0; i
< 8; ++i
)
565 if ((read
= fgetc(noi
)) == EOF
|| read
== '\r' || read
== '\n')
571 // number is too long; ignore
572 if (read
!= EOF
&& read
!= '\r' && read
!= '\n')
575 // we successfully read label and value
577 // but filter out some invalid symbols
578 if (strcmp(label
, ".__.ABS.") != 0)
579 fprintf (sym
, "%02X:%04X %s\n", (unsigned int)(strtoul(value
, NULL
, 0)>>16), (unsigned int)strtoul(value
, NULL
, 0)&0xFFFF, label
);
582 // skip until file/line end
583 while ((read
= fgetc(noi
))!= EOF
&& read
!= '\r' && read
!= '\n');
590 fprintf (stderr
, "Converted %s to %s.\n", nname
, sname
);
595 read_ihx (FILE *fin
, BYTE
**rom
, int *size
, int *real_size
, struct gb_opt_s
*o
)
604 int checksum
, sum
= 0;
606 if (getc (fin
) != ':')
608 fprintf (stderr
, "error: invalid IHX line.\n");
611 nbytes
= getbyte (fin
, &sum
);
612 addr
= getbyte (fin
, &sum
) << 8 | getbyte (fin
, &sum
);
613 record_type
= getbyte (fin
, &sum
);
616 extaddr
= getbyte (fin
, &sum
) << 8 | getbyte (fin
, &sum
);
617 extaddr
<<= 16; // those are the upper 16 bits
618 checksum
= getbyte (fin
, &sum
);
619 // move to the next record
620 if (0 != (sum
& 0xff))
622 fprintf (stderr
, "error: bad checksum: %02x.\n", checksum
);
625 while (isspace (sum
= getc (fin
))) /* skip all kind of spaces */
628 if (getc (fin
) != ':')
630 fprintf (stderr
, "error: invalid IHX line.\n");
633 // parse real data part
635 nbytes
= getbyte (fin
, &sum
);
637 addr
= getbyte (fin
, &sum
) << 8 | getbyte (fin
, &sum
);
638 record_type
= getbyte (fin
, &sum
);
640 // add linear address extension
642 // TODO: warn for unreachable banks according to chosen MBC
645 fprintf (stderr
, "error: unsupported record type: %02x.\n", record_type
);
649 if (addr
+ nbytes
> *size
)
651 // If auto-size is enabled, grow rom bank size by power of 2 when needed
652 if (o
->rom_banks_autosize
)
654 if (rom_autosize_grow(rom
, addr
+ nbytes
, size
, o
) == 0)
659 fprintf (stderr
, "error: size of the buffer is too small.\n");
667 (*rom
)[addr
++] = getbyte (fin
, &sum
);
670 if (addr
> *real_size
)
673 checksum
= getbyte (fin
, &sum
);
674 if (0 != (sum
& 0xff))
676 fprintf (stderr
, "error: bad checksum: %02x.\n", checksum
);
680 while (isspace (sum
= getc (fin
))) /* skip all kind of spaces */
684 while (1 != record_type
); /* EOF record */
690 main (int argc
, char **argv
)
692 int size
= 32768, offset
= 0, pack
= 0, real_size
= 0, i
= 0;
696 char *filename
= NULL
;
701 struct gb_opt_s gb_opt
= {.cart_name
="",
711 .rom_banks_autosize
=0,
713 .address_overwrite
={0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0} };
715 // 32KiB, SMS Export, version 0 <- should work with most emulaters (<32K was never used, GG accepts SMS)
716 struct sms_opt_s sms_opt
= {.rom_size
=0xc,
721 setmode (fileno (stdout
), O_BINARY
);
724 while (*++argv
&& '-' == argv
[0][0])
737 size
= strtoul (*argv
, NULL
, 0);
746 offset
= strtoul (*argv
, NULL
, 0);
758 /* generate GameBoy binary file */
764 * -yo Number of rom banks (default: 2)
765 * -ya Number of ram banks (default: 0)
766 * -yt MBC type (default: no MBC)
767 * -yn Name of program (default: name of output file)
768 * -yk,-yl,-yc,-yC,-yN,-ys,-yS,-yj,-yp see usage()
778 // Use auto-size for rom banks if -yto size param is 'A'
779 if ((*argv
)[0] == 'A' || (*argv
)[0] == 'a')
780 gb_opt
.rom_banks_autosize
= 1;
783 gb_opt
.nb_rom_banks
= strtoul (*argv
, NULL
, 0);
784 size
= gb_opt
.nb_rom_banks
* 0x4000;
794 gb_opt
.nb_ram_banks
= strtoul (*argv
, NULL
, 0);
803 gb_opt
.mbc_type
= strtoul (*argv
, NULL
, 0);
812 strncpy (gb_opt
.cart_name
, *argv
, CART_NAME_LEN
-1);
813 gb_opt
.cart_name
[CART_NAME_LEN
-1] = '\0';
822 strncpy (gb_opt
.licensee_str
, *argv
, 2);
831 gb_opt
.licensee_id
= strtoul (*argv
, NULL
, 0);
843 gb_opt
.do_logo_copy
= false; // when switch is present, turn off logo copy
851 gb_opt
.sym_conversion
= 1;
858 // like -yp0x143=0x80
863 // also support -yp 0x143=0x80
871 // effectively split string into argv and token
873 token
= strtok(NULL
, "=");
874 for (i
= 0; i
< 16; i
+=2)
876 if (gb_opt
.address_overwrite
[i
] == 0xFF)
878 gb_opt
.address_overwrite
[i
] = strtoul (*argv
, NULL
, 0);
879 gb_opt
.address_overwrite
[i
+1] = strtoul (token
, NULL
, 0);
892 /* generate SMS binary file */
906 sms_opt
.rom_size
= strtoul (*argv
, NULL
, 0);
907 if ( sms_opt
.rom_size
> 2 && (sms_opt
.rom_size
< 0xa || sms_opt
.rom_size
> 0xf ) )
909 fprintf (stderr
, "error: invalid rom size (0x%X)", sms_opt
.rom_size
);
913 if ( sms_opt
.rom_size
== 0xd || sms_opt
.rom_size
== 0x2 )
915 fprintf (stderr
, "warning: this rom size (0x%X) is bugged in some BIOSes\n", sms_opt
.rom_size
);
925 sms_opt
.region_code
= strtoul (*argv
, NULL
, 0);
926 if ( sms_opt
.region_code
< 3 && sms_opt
.region_code
> 7 )
928 fprintf (stderr
, "error: invalid region code (0x%X)", sms_opt
.region_code
);
940 sms_opt
.version
= strtoul (*argv
, NULL
, 0);
941 if ( sms_opt
.version
> 0xf )
943 fprintf (stderr
, "error: invalid version (0x%X)", sms_opt
.version
);
965 if ('-' != argv
[0][0] || '\0' != argv
[0][1])
967 if (NULL
== (fin
= fopen (*argv
, "r")))
969 fprintf (stderr
, "error: can't open %s: ", *argv
);
978 if (NULL
!= argv
[0] && NULL
!= argv
[1])
988 fprintf (stderr
, "error: couldn't allocate room for the image.\n");
991 memset (rom
, FILL_BYTE
, size
);
993 if (gb_opt
.sym_conversion
== 1)
999 fprintf (stderr
, "error: .noi to .sym conversion needs an input file.\n");
1003 ret
= read_ihx (fin
, &rom
, &size
, &real_size
, &gb_opt
);
1010 gb_postproc (rom
, size
, &real_size
, &gb_opt
);
1012 sms_postproc (rom
, size
, &real_size
, &sms_opt
);
1016 if ('-' != argv
[0][0] || '\0' != argv
[0][1])
1018 if (NULL
== (fout
= fopen (*argv
, "wb")))
1020 fprintf (stderr
, "error: can't create %s: ", *argv
);
1029 memmove (rom
, rom
+ offset
, size
- offset
);
1030 memset (rom
+ size
- offset
, FILL_BYTE
, offset
);
1033 fwrite (rom
, 1, (pack
? real_size
: size
) - offset
, fout
);