int compute_snes_checksum(void) { int i, x, n, m, l, o; if (snes_rom_mode == SNES_ROM_MODE_LOROM) { if (romsize < 0x8000) { fprintf(stderr, "COMPUTE_SNES_CHECKSUM: SNES checksum computing for a LoROM image requires a ROM of at least 32KB.\n"); return FAILED; } } else { if (romsize < 0x10000) { fprintf(stderr, "COMPUTE_SNES_CHECKSUM: SNES checksum computing for a HiROM image requires a ROM of at least 64KB.\n"); return FAILED; } } /* n = data inside 4mbit blocks, m = data outside that */ if (romsize < 512*1024) { n = romsize; m = 0; } else { n = (romsize/(512*1024))*512*1024; m = romsize - n; } /* sum all the bytes inside the 4mbit blocks */ x = 0; for (i = 0; i < n; i++) { if (snes_rom_mode == SNES_ROM_MODE_LOROM) { /* skip the checksum bytes */ if (!(i == 0x7FDC || i == 0x7FDD || i == 0x7FDE || i == 0x7FDF)) x += rom[i]; } else { /* skip the checksum bytes */ if (!(i == 0xFFDC || i == 0xFFDD || i == 0xFFDE || i == 0xFFDF)) x += rom[i]; } } /* add to that the data outside the 4mbit blocks, ringbuffer style repeating the remaining block until the the final part reaches 4mbits */ for (o = 0, l = i; i < romsize; i++, o++) x += rom[(o % m) + l]; /* 2*255 is for the checksum and its complement bytes that we skipped earlier */ x += 2*255; /* compute the inverse checksum */ l = (x & 0xFFFF) ^ 0xFFFF; /* insert the checksum bytes */ if (snes_rom_mode == SNES_ROM_MODE_LOROM) { mem_insert(0x7FDC, l & 0xFF); mem_insert(0x7FDD, (l >> 8) & 0xFF); mem_insert(0x7FDE, x & 0xFF); mem_insert(0x7FDF, (x >> 8) & 0xFF); }
int mem_insert_allow_overwrite(int address, unsigned char data, unsigned int allowed_overwrites) { if (rom_usage[address] > allowed_overwrites) return mem_insert(address, data); rom_usage[address]++; rom[address] = data; return SUCCEEDED; }
int compute_gb_complement_check(void) { int i, x; if (romsize < 0x8000) { fprintf(stderr, "COMPUTE_GB_COMPLEMENT_CHECK: GB complement check computing requires a ROM of at least 32KB.\n"); return FAILED; } i = 0; for (x = 0x134; x <= 0x14C; x++) i += rom[x]; i += 25; mem_insert(0x14D, 0 - (i & 0xFF)); return SUCCEEDED; }
/*! * \brief Insert string into string * * Insert \p s into \p *str. It the function succeeds. \p *str will be passed to * `free()` and \p *str will be updated to point to the newly allocated string. * If the function fails, \p *str will be left unchanged. * * \param[in,out] str Pointer to string to modify * \param[in] pos Position in which to insert new string * (0 \<= \p pos \<= \p *mem_size) * \param[in] s New string to insert * * \return Nothing if successful. Otherwise, the error code. */ oc::result<void> str_insert(char **str, size_t pos, const char *s) { size_t str_size; str_size = strlen(*str); if (pos > str_size) { return std::make_error_code(std::errc::invalid_argument); } else if (str_size == SIZE_MAX) { return std::make_error_code(std::errc::value_too_large); } ++str_size; return mem_insert(reinterpret_cast<void **>(str), &str_size, pos, s, strlen(s)); }
int compute_gb_checksum(void) { int i, x; if (romsize < 0x8000) { fprintf(stderr, "COMPUTE_GB_CHECKSUM: GB checksum computing requires a ROM of at least 32KB.\n"); return FAILED; } i = 0; for (x = 0; x < 0x14E; x++) i += rom[x]; for (x = 0x150; x < romsize; x++) i += rom[x]; mem_insert(0x14E, (i >> 8) & 0xFF); mem_insert(0x14F, i & 0xFF); return SUCCEEDED; }
int insert_sections(void) { struct section *s, **sa; int d, f, i, x, t, q, sn, p; char *ram_slots[256], *c; /* initialize ram slots */ for (i = 0; i < 256; i++) ram_slots[i] = NULL; /* find all touched slots */ s = sec_first; while (s != NULL) { if (s->status == SECTION_STATUS_RAM && ram_slots[s->slot] == NULL) { ram_slots[s->slot] = malloc(slots[s->slot].size); if (ram_slots[s->slot] == NULL) { fprintf(stderr, "INSERT_SECTIONS: Out of memory error.\n"); return FAILED; } memset(ram_slots[s->slot], 0, slots[s->slot].size); } s = s->next; } /* count the sections */ i = 0; s = sec_first; while (s != NULL) { /* no references - skip it */ if (s->alive == YES) i++; s = s->next; } sn = i; if (sn == 0) return SUCCEEDED; sa = malloc(sizeof(struct section *) * sn); if (sa == NULL) { fprintf(stderr, "INSERT_SECTIONS: Out of memory error.\n"); return FAILED; } /* insert the sections into an array for sorting */ i = 0; s = sec_first; while (s != NULL) { /* no references - skip it */ if (s->alive == YES) sa[i++] = s; s = s->next; } /* sort the sections by size, biggest first */ qsort(sa, sn, sizeof(struct section *), _sections_sort); /* print the sizes (DEBUG) */ /* for (d = 0; d < i; d++) fprintf(stderr, "SIZE: %d\n", sa[d]->size); */ /* ram sections */ p = 0; while (p < sn) { s = sa[p++]; /* search for free space */ if (s->status == SECTION_STATUS_RAM) { c = ram_slots[s->slot]; i = slots[s->slot].size; t = 0; for (x = 0; x < i; x++, c++) { if (*c == 0) { for (q = 0; x < i && q < s->size; x++, q++, c++) { if (*c != 0) break; } if (q == s->size) { t = 1; break; } } } if (t == 0) { fprintf(stderr, "INSERT_SECTIONS: No room for RAM section \"%s\" (%d bytes) in slot %d.\n", s->name, s->size, s->slot); return FAILED; } /* mark as used */ c = c - s->size; for (i = 0; i < s->size; i++, c++) *c = 1; s->address = c - s->size - ram_slots[s->slot]; } } /* free tmp memory */ for (i = 0; i < 256; i++) { if (ram_slots[i] != NULL) free(ram_slots[i]); } /* force sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_FORCE) { memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = s->address; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; d = pc_full; i = d + s->size; s->output_address = d; section_overwrite = OFF; if (i > romsize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) goes beyond the ROM size.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } if (s->address + s->size > banksize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) overflows from ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } for (; d < i; d++) { if (rom_usage[d] != 0 && rom[d] != s->data[d - pc_full]) break; } if (d == i) { for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } else { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes).\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } } } /* absolute sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_ABSOLUTE) { d = s->address; s->output_address = d; section_overwrite = ON; for (i = 0; i < s->size; i++) { if (mem_insert(d + i, s->data[i]) == FAILED) return FAILED; } } } /* semisubfree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_SEMISUBFREE) { pc_bank = 0; d = bankaddress[s->bank]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; i = FAILED; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < s->address && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == s->address) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes) in ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < s->address && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } /* free & semifree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_FREE || s->status == SECTION_STATUS_SEMIFREE) { pc_bank = s->address; d = bankaddress[s->bank]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; i = FAILED; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == banksizes[s->bank]) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes) in ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } /* superfree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_SUPERFREE) { /* go through all the banks */ i = FAILED; f = 0; for (q = 0; i == FAILED && q < rombanks; q++) { pc_bank = 0; d = bankaddress[q]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; /* if the slotsize and banksize differ -> try the next bank */ if (banksizes[q] != slots[s->slot].size) continue; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < banksizes[q] && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == banksizes[q]) break; /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } } if (i == SUCCEEDED) { s->bank = q-1; memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } else { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes).\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } } } /* overwrite sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_OVERWRITE) { memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = s->address; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->output_address = pc_full; section_overwrite = ON; if (pc_full + s->size > romsize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) goes beyond the ROM size.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } if (s->address + s->size > banksize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) overflows from ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } free(sa); return SUCCEEDED; }