diff --git a/support/makebin/makebin.c b/support/makebin/makebin.c
index 83d4ec6..d8028d3 100644
--- a/support/makebin/makebin.c
+++ b/support/makebin/makebin.c
@@ -1,121 +1,491 @@
-/** @name makebin - turn a .ihx file into a binary image.
- */
+/*
+  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
+
+  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 <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
-#if defined(__BORLANDC__) || defined(__MINGW32__) || defined(__CYGWIN__)
-  #include <fcntl.h>
-  #include <io.h>
+#if defined(_WIN32)
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
 #endif
 
 
 typedef unsigned char BYTE;
 
-#define FILL_BYTE 0xFF
+#define FILL_BYTE 0xff
 
-int getnibble(char **p)
+int
+getnibble (FILE *fin)
 {
-  int ret = *((*p)++) - '0';
-  if (ret > 9) {
-    ret -= 'A' - '9' - 1;
-  }
+  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(char **p)
+int
+getbyte (FILE *fin, int *sum)
 {
-  return (getnibble(p) << 4) | getnibble(p);
+  int b = (getnibble (fin) << 4) | getnibble (fin);
+  *sum += b;
+  return b;
 }
 
-void usage(void)
+void
+usage (void)
 {
-  fprintf(stderr, 
-          "makebin: convert a Intel IHX file to binary.\n"
-          "Usage: makebin [-p] [-s romsize] [-h]\n");
+  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: 32768)\n"
+           "  -Z             genarate GameBoy format binary file\n"
+           "GameBoy format options (applicable only with -Z option):\n"
+           "  -yo n          number of rom banks (default: 2)\n"
+           "  -ya n          number of ram banks (default: 0)\n"
+           "  -yt n          MBC type (default: no MBC)\n"
+           "  -yn name       cartridge name (default: none)\n"
+           "Arguments:\n"
+           "  <in_file>      optional IHX input file, '-' means stdin. (default: stdin)\n"
+           "  <out_file>     optional output file, '-' means stdout. (default: stdout)\n");
 }
 
-void fixStdout(void)
+#define CART_NAME_LEN 16
+
+struct gb_opt_s
 {
-  #if defined(__BORLANDC__) || defined(__MINGW32__) || defined(__CYGWIN__)
-    setmode(fileno(stdout), O_BINARY);
-  #endif
+  char cart_name[CART_NAME_LEN];  /* cartridge name buffer */
+  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) */
+};
+
+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.
+   */
+
+  memcpy (&rom[0x104], gb_logo, sizeof (gb_logo));
+
+  /*
+   * 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]);
+    }
+
+  /*
+   * 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;
+    }
+
+  /* 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;
 }
 
+int
+read_ihx (FILE *fin, BYTE *rom, int size, int *real_size)
+{
+  int record_type;
+
+  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 > 1)
+        {
+          fprintf (stderr, "error: unsupported record type: %02x.\n", record_type);
+          return 0;
+        }
+
+      if (addr + nbytes > size)
+        {
+          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;
+        }
 
-int main(int argc, char **argv)
+      while (isspace (sum = getc (fin)))  /* skip all kind of speces */
+        ;
+      ungetc (sum, fin);
+    }
+  while (1 != record_type); /* EOF record */
+
+  return 1;
+}
+
+int
+main (int argc, char **argv)
 {
-    int size = 32768, pack = 0, real_size = 0;
-    BYTE *rom;
-    char line[256];
-    char *p;
-
-    argc--;
-    argv++;
-
-    fixStdout();
-    
-    while (argc--) {
-        if (**argv != '-') {
-            usage();
-            return -1;
+  int size = 32768, pack = 0, real_size = 0;
+  BYTE *rom;
+  FILE *fin, *fout;
+  int ret;
+  int gb = 0;
+  struct gb_opt_s gb_opt = { "", 0, 2, 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 = atoi (*argv);
+          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;
+                }
+              gb_opt.nb_rom_banks = atoi (*argv);
+              break;
+
+            case 'a':
+              if (!++argv)
+                {
+                  usage ();
+                  return 1;
+                }
+              gb_opt.nb_ram_banks = atoi (*argv);
+              break;
+
+            case 't':
+              if (!*++argv)
+                {
+                  usage ();
+                  return 1;
+                }
+              gb_opt.mbc_type = atoi (*argv);
+              break;
+
+            case 'n':
+              if (!*++argv)
+                {
+                  usage ();
+                  return 1;
+                }
+              strncpy (gb_opt.cart_name, *argv, CART_NAME_LEN);
+              break;
+
+            default:
+              usage ();
+              return 1;
+            }
+          break;
+
+        default:
+          usage ();
+          return 1;
         }
-        switch (argv[0][1]) {
-	case 's':
-            if (argc < 1) {
-                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;
             }
-            argc--;
-            argv++;
-	    size = atoi(*argv);
-	    break;
-	case 'h':
-            usage();
-	    return 0;
-	case 'p':
-	    pack = 1;
-	    break;
-	default:
-            usage();
-            return -1;
-	}
-        argv++;
+        }
+      ++argv;
+    }
+
+  if (NULL != argv[0] && NULL != argv[1])
+    {
+      usage ();
+      return 1;
     }
 
-    rom = malloc(size);
-    if (rom == NULL) {
-	fprintf(stderr, "error: couldn't allocate room for the image.\n");
-	return -1;
+  if (gb && size != 32768)
+    {
+      fprintf (stderr, "error: only length of 32768 bytes supported for GameBoy binary.\n");
+      return 1;
     }
-    memset(rom, FILL_BYTE, size);
-    while (fgets(line, 256, stdin) != NULL) {
-	int nbytes;
-	int addr;
-
-	if (*line != ':') {
-	    fprintf(stderr, "error: invalid IHX line.\n");
-	    return -2;
-	}
-	p = line+1;
-	nbytes = getbyte(&p);
-	addr = getbyte(&p)<<8 | getbyte(&p);
-	getbyte(&p);
-
-	while (nbytes--) {
-	    if (addr < size)
-		rom[addr++] = getbyte(&p);
-	}
-
-	if (addr > real_size)
-	    real_size = addr;
+
+  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);
+
+  ret = read_ihx (fin, rom, size, &real_size);
 
-    if (pack)
-        fwrite(rom, 1, real_size, stdout);
-    else
-        fwrite(rom, 1, size, stdout);
-    
-    return 0;
+  fclose (fin);
+
+  if (ret)
+    {
+      if (gb)
+        gb_postproc (rom, size, &real_size, &gb_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;
+                }
+            }
+        }
+
+      fwrite (rom, 1, (pack ? real_size : size), fout);
+
+      fclose (fout);
+
+      return 0;
+    }
+  else
+    return 1;
 }
