Add VCS links
[debian-dgen.git] / romload.c
blob1b05c669a67000f7182df94f7586de7e88b789b7
1 /*
2 DGen/SDL v1.27+
4 Module for loading in the different ROM image types (.bin/.smd)
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <errno.h>
11 #include "romload.h"
12 #include "system.h"
14 static const char *rom_path = "roms";
16 void set_rom_path(const char *path)
18 rom_path = path;
22 WHAT YOU FIND IN THE 512 BYTES HEADER:
24 0: Number of blocks 1
25 1: H03 *
26 2: SPLIT? 2
27 8: HAA *
28 9: HBB *
29 ALL OTHER BYTES: H00
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.
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.
43 Allocate a buffer and stuff the named ROM inside. If rom_size is non-NULL,
44 store the ROM size there.
47 uint8_t *load_rom(size_t *rom_size, const char *name)
49 FILE *file;
50 size_t size;
51 uint8_t *rom;
52 int error;
53 void *context = NULL;
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;
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;
77 if (size < 512) {
78 /* ROM file too small */
79 unload(rom);
80 goto retry;
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.
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);
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);
99 De-interleave ROM, overwrite SMD header with the result.
101 while (chunks) {
102 size_t i;
103 uint8_t tmp[0x2000];
105 memcpy(tmp, src, 0x2000);
106 src += 0x2000;
107 for (i = 0; (i != 0x2000); ++i) {
108 *(dst++) = *(src++);
109 *(dst++) = tmp[i];
111 --chunks;
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;
121 load_finish(&context);
122 fclose(file);
123 if (rom_size != NULL)
124 *rom_size = size;
125 return rom;
128 void unload_rom(uint8_t *rom)
130 unload(rom);