From 3ed0bed61c757ef841f8eddf13f9f284a13bd7ae Mon Sep 17 00:00:00 2001 From: condret Date: Sun, 6 Oct 2024 07:38:55 +0200 Subject: [PATCH] Start implementing mbc1 --- include/gb.h | 3 ++ io/mbc1.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 io/mbc1.c diff --git a/include/gb.h b/include/gb.h index cd4eb8c..ac2450f 100644 --- a/include/gb.h +++ b/include/gb.h @@ -24,6 +24,9 @@ GBTimers *gb_timers_open(RIO *io); void gb_timers_close(RIO *io, GBTimers *timers); void gb_timers_update(GBTimers *timers, ut32 cycles); +int gb_mbc1_open(RIO *io, char *path); + extern RIOPlugin r_io_plugin_gb_timers; +extern RIOPlugin r_io_plugin_gb_mbc1; #endif diff --git a/io/mbc1.c b/io/mbc1.c new file mode 100644 index 0000000..4c805e6 --- /dev/null +++ b/io/mbc1.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include + +typedef struct gb_mbc1_data { + RIO *io; + ut32 *rombank_to_io_map; + ut32 *rambank_to_io_map; + ut64 seek; + ut32 size; + int file_fd; + int mem_fd; + ut8 n_rombanks; + ut8 n_rambanks; + ut8 rombank_mask; + ut8 rombank; + union { + ut8 high_rombank; + ut8 rambank; + }; + bool ram_enable; + bool small_ram; +} MBC1; + +ut8 mbc1_mask[] = { 0x1, 0x3, 0x7, 0xf, 0x1f, 0x1f, 0x1f }; + +static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { + if (!r_str_startswith (pathname, "gb_mbc1://")) { + return NULL; + } + if (!r_file_exists (&pathname[10]) || !r_file_is_regular (&pathname[10])) { + return NULL; + } + RIODesc *desc = r_io_desc_open (io, &pathname[10], R_PERM_R, 0); + if (!desc) { + return NULL; + } + ut8 mbc_info[3] = {0xfb, 0xff, 0xff}; + r_io_desc_read_at (desc, 0x147, mbc_info, 3); + r_io_desc_close (desc); + if (R_UNLIKELY (!mbc_info[0] || (mbc_info[0] > 3) || + (mbc_info[1] > 6) || (mbc_info[2] > 2))) { + //not a mbc1 game + return NULL; + } + MBC1 *mbc = R_NEW0 (MBC1); + if (!mbc) { + return NULL; + } + mbc->n_rombanks = 0x1 << (mbc_info[1] + 1); + mbc->rombank_to_io_map = R_NEWS0 (ut32, mbc->n_rombanks); + if (!mbc->rombank_to_io_map) { + free (mbc); + return NULL; + } + mbc->rombank_mask = mbc1_mask[mbc_info[1]]; + if (mbc_info[0] != 1) { + switch (mbc_info[2]) { + case 0x1: + mbc->small_ram = true; + case 0x3: + mbc->n_rambanks = 4; + break; + case 0x2: + mbc->n_rambanks = 1; + break; + } + mbc->rambank_to_io_map = R_NEWS0 (ut32, mbc->n_rambanks); + if (!mbc->rambank_to_io_map) { + free (mbc->rombank_to_io_map); + free (mbc); + return NULL; + } + } + mbc->io = r_io_new (); + if (!mbc->io) { + free (mbc->rombank_to_io_map); + free (mbc->rambank_to_io_map); + free (mbc); + return NULL; + } + mbc->file_fd = r_io_fd_open (mbc->io, &pathname[10], R_PERM_R, 0); + { + char *malloc_uri = r_str_newf ("malloc://0x%"PFMT64x, + mbc->small_ram? 0x800: (0x2000 * mbc->n_rambanks)); + mbc->mem_fd = r_io_fd_open (mbc->io, malloc_uri, R_PERM_RW, 0); + free (malloc_uri); + } + if ((mbc->file_fd < 0) || (mbc->mem_fd < 0)) { + goto fail; + } + RIOMap *map = r_io_map_add (mbc->io, mbc->file_fd, R_PERM_R, 0ULL, 0ULL, 0x4000); + if (!map) { + goto fail; + } + mbc->rombank_to_io_map[0] = map->id; + ut32 i; + for (i = 1; i < mbc->n_rombanks; i++) { + map = r_io_map_add_bottom (mbc->io, mbc->file_fd, R_PERM_R, + 0x4000 * i, 0x4000, 0x4000); + if (!map) { + goto fail; + } + mbc->rombank_to_io_map[i] = map->id; + } + if (mbc->small_ram) { + for (i = 0; i < 4; i++) { + map = r_io_map_add (mbc->io, mbc->mem_fd, R_PERM_RW, + 0ULL, 0xa000 + 0x800 * i, 0x800); + if (!map) { + goto fail; + } + mbc->rambank_to_io_map[i] = map->id; + } + } else { + for (i = 0; i < 4; i++) { + map = r_io_map_add_bottom (mbc->io, mbc->mem_fd, R_PERM_RW, + 0x2000 * i, 0xa000, 0x2000); + if (!map) { + goto fail; + } + mbc->rambank_to_io_map[i] = map->id; + } + } + mbc->rombank = 1; + mbc->io->cache.mode = 0; + desc = r_io_desc_new (io, &r_io_plugin_gb_mbc1, pathname, + R_PERM_RWX, mode, mbc); + return desc; +fail: + r_io_free (mbc->io); + free (mbc->rombank_to_io_map); + free (mbc->rambank_to_io_map); + free (mbc); + return NULL; +}