Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   DGen/SDL v1.27+
  3.  
  4.   Module for loading in the different ROM image types (.bin/.smd)
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #include "romload.h"
  12. #include "system.h"
  13.  
  14. static const char *rom_path = "roms";
  15.  
  16. void set_rom_path(const char *path)
  17. {
  18.         rom_path = path;
  19. }
  20.  
  21. /*
  22.   WHAT YOU FIND IN THE 512 BYTES HEADER:
  23.  
  24. 0: Number of blocks                           1
  25. 1: H03                                        *
  26. 2: SPLIT?                                     2
  27. 8: HAA                                        *
  28. 9: HBB                                        *
  29. ALL OTHER BYTES: H00
  30.  
  31. 1: This first byte should have the number of 16KB blocks the rom has.
  32. The header isn't part of the formula, so this number is:
  33.             [size of rom-512]/16384
  34.    If the size is more than 255, the value should be H00.
  35.  
  36. 2: This byte indicates if the ROM is a part of a splitted rom series. If
  37. the rom is the last part of the series (or isn't a splitted rom at all),
  38. this byte should be H00. In other cases should be H40. See "CREATING
  39. SPLITTED ROMS" for details on this format.
  40. */
  41.  
  42. /*
  43.   Allocate a buffer and stuff the named ROM inside. If rom_size is non-NULL,
  44.   store the ROM size there.
  45. */
  46.  
  47. uint8_t *load_rom(size_t *rom_size, const char *name)
  48. {
  49.         FILE *file;
  50.         size_t size;
  51.         uint8_t *rom;
  52.         int error;
  53.         void *context = NULL;
  54.  
  55.         if (name == NULL)
  56.                 return NULL;
  57.         file = dgen_fopen(rom_path, name, (DGEN_READ | DGEN_CURRENT));
  58.         if (file == NULL) {
  59.                 fprintf(stderr, "%s: can't open ROM file.\n", name);
  60.                 return NULL;
  61.         }
  62. retry:
  63.         /* A valid ROM will surely not be bigger than 64MB. */
  64.         rom = load(&context, &size, file, (64 * 1024 * 1024));
  65.         error = errno;
  66.         if (rom == NULL) {
  67.                 if (error)
  68.                         fprintf(stderr, "%s: unable to load ROM: %s.\n", name,
  69.                                 strerror(error));
  70.                 else
  71.                         fprintf(stderr, "%s: no valid ROM found.\n",
  72.                                 name);
  73.                 load_finish(&context);
  74.                 fclose(file);
  75.                 return NULL;
  76.         }
  77.         if (size < 512) {
  78.                 /* ROM file too small */
  79.                 unload(rom);
  80.                 goto retry;
  81.         }
  82.         /*
  83.           If "SEGA" isn't found at 0x100 and the total size minus 512 is a
  84.           multiple of 0x4000, it probably is a SMD.
  85.         */
  86.         if (memcmp(&rom[0x100], "SEGA", 4)) {
  87.                 uint8_t *dst = rom;
  88.                 uint8_t *src = &rom[0x200];
  89.                 size_t chunks = ((size - 0x200) / 0x4000);
  90.  
  91.                 if (((size - 0x200) & (0x4000 - 1)) != 0)
  92.                         goto bad_rom;
  93.                 size -= 0x200;
  94.                 /* Corrupt ROM? Complain and continue anyway. */
  95.                 if (((rom[0] != 0x00) && (rom[0] != chunks)) ||
  96.                     (rom[8] != 0xaa) || (rom[9] != 0xbb))
  97.                         fprintf(stderr, "%s: corrupt SMD header.\n", name);
  98.                 /*
  99.                   De-interleave ROM, overwrite SMD header with the result.
  100.                 */
  101.                 while (chunks) {
  102.                         size_t i;
  103.                         uint8_t tmp[0x2000];
  104.  
  105.                         memcpy(tmp, src, 0x2000);
  106.                         src += 0x2000;
  107.                         for (i = 0; (i != 0x2000); ++i) {
  108.                                 *(dst++) = *(src++);
  109.                                 *(dst++) = tmp[i];
  110.                         }
  111.                         --chunks;
  112.                 }
  113.                 /* Does it look like a valid ROM now? */
  114.                 if (memcmp(&rom[0x100], "SEGA", 4)) {
  115.                 bad_rom:
  116.                         /* Invalid ROM */
  117.                         unload(rom);
  118.                         goto retry;
  119.                 }
  120.         }
  121.         load_finish(&context);
  122.         fclose(file);
  123.         if (rom_size != NULL)
  124.                 *rom_size = size;
  125.         return rom;
  126. }
  127.  
  128. void unload_rom(uint8_t *rom)
  129. {
  130.         unload(rom);
  131. }
  132.