Finish ppu, and mbc1 mapping
This commit is contained in:
160
lib/cart.c
160
lib/cart.c
@ -6,10 +6,39 @@ typedef struct {
|
||||
u32 rom_size;
|
||||
u8 *rom_data;
|
||||
rom_header *header;
|
||||
|
||||
//mbc1 data
|
||||
bool ram_enabled;
|
||||
bool ram_banking;
|
||||
|
||||
u8 *rom_bank_x;
|
||||
u8 banking_mode;
|
||||
|
||||
u8 rom_bank_value;
|
||||
u8 ram_bank_value;
|
||||
|
||||
u8 *ram_bank;
|
||||
u8 *ram_banks[16];
|
||||
|
||||
//battery
|
||||
bool battery;
|
||||
bool need_save;
|
||||
} cart_context;
|
||||
|
||||
static cart_context ctx;
|
||||
|
||||
bool cart_need_save () {
|
||||
return ctx.need_save;
|
||||
}
|
||||
|
||||
bool cart_mbc1() {
|
||||
return BETWEEN(ctx.header->type, 1, 3);
|
||||
}
|
||||
|
||||
bool cart_battery() {
|
||||
return ctx.header->type == 3;
|
||||
}
|
||||
|
||||
static const char *ROM_TYPES[] = {
|
||||
"ROM ONLY",
|
||||
"MBC1",
|
||||
@ -132,6 +161,23 @@ const char *cart_lic_name() {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
void cart_setup_bamking() {
|
||||
for (int i=0; i<16; i++) {
|
||||
ctx.ram_banks[1] = 0;
|
||||
|
||||
if((ctx.header->ram_size == 2 && i == 0) ||
|
||||
(ctx.header->ram_size == 3 && i < 4) ||
|
||||
(ctx.header->ram_size == 5 && i < 8) ||
|
||||
(ctx.header->ram_size == 4)) {
|
||||
ctx.ram_banks[i] = malloc(0x2000);
|
||||
memset(ctx.ram_banks[i], 0, 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.ram_bank = ctx.ram_banks[0];
|
||||
ctx.rom_bank_x = ctx.rom_data + 0x4000;
|
||||
}
|
||||
|
||||
bool cart_load(char *cart) {
|
||||
snprintf(ctx.filename, sizeof(ctx.filename), "%s", cart);
|
||||
FILE *fp = fopen(cart, "r");
|
||||
@ -153,6 +199,8 @@ bool cart_load(char *cart) {
|
||||
|
||||
ctx.header = (rom_header *)(ctx.rom_data + 0x100);
|
||||
ctx.header->title[15] = 0;
|
||||
ctx.battery = cart_battery();
|
||||
ctx.need_save = false;
|
||||
|
||||
printf("Cartridge Loaded:\n");
|
||||
printf("\t Title : %s\n", ctx.header->title);
|
||||
@ -162,6 +210,8 @@ bool cart_load(char *cart) {
|
||||
printf("\t LIC Code : %2.2X (%s)\n", ctx.header->lic_code, cart_lic_name());
|
||||
printf("\t ROM Vers : %2.2X\n", ctx.header->version);
|
||||
|
||||
cart_setup_bamking();
|
||||
|
||||
u16 x = 0;
|
||||
for (u16 i=0X0134; i<=0X014C; i++) {
|
||||
x = x - ctx.rom_data[i] -1;
|
||||
@ -172,17 +222,119 @@ bool cart_load(char *cart) {
|
||||
if((x & 0xFF) != ctx.header->checksum) {
|
||||
fprintf(stderr, "WARNING!!! The header checksum does not match! ROM may be corrupt or invalid!\n");
|
||||
}
|
||||
|
||||
if(ctx.battery) {
|
||||
cart_battery_load();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 cart_read(u16 address){
|
||||
//for now ROM ONLY type supported...
|
||||
if(!cart_mbc1() || address < 0x4000) {
|
||||
return ctx.rom_data[address];
|
||||
}
|
||||
|
||||
if((address & 0xE000) == 0xA000) {
|
||||
if (!ctx.ram_enabled) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
if(!ctx.ram_bank) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return ctx.ram_bank[address - 0xA000];
|
||||
}
|
||||
|
||||
return ctx.rom_bank_x[address - 0x4000];
|
||||
|
||||
return ctx.rom_data[address];
|
||||
}
|
||||
|
||||
void cart_write(u16 address, u8 value){
|
||||
printf("UNSUPPORTED cart_write(%04X)\n", address);
|
||||
//NO_IMPL
|
||||
if(!cart_mbc1()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(address < 0x2000) {
|
||||
ctx.ram_enabled = ((value & 0xF) == 0xA);
|
||||
}
|
||||
|
||||
if((address & 0xE000) == 0x2000) {
|
||||
//rom bank
|
||||
if(value == 0) {
|
||||
value = 1;
|
||||
}
|
||||
|
||||
value &= 0b11111;
|
||||
ctx.rom_bank_value = value;
|
||||
ctx.rom_bank_x = ctx.rom_data + (0x4000 * ctx.rom_bank_value);
|
||||
}
|
||||
|
||||
if((address & 0xE000) == 0x4000) {
|
||||
//ram bank number
|
||||
ctx.ram_bank_value = value & 0xb11;
|
||||
if(ctx.ram_banking) {
|
||||
if(cart_need_save) {
|
||||
cart_battery_save();
|
||||
}
|
||||
ctx.ram_bank = ctx.ram_banks[ctx.ram_bank_value];
|
||||
}
|
||||
}
|
||||
|
||||
if((address & 0xE000) == 0x6000) {
|
||||
//bamking mode select
|
||||
|
||||
ctx.banking_mode = value & 1;
|
||||
|
||||
ctx.ram_banking = ctx.banking_mode;
|
||||
|
||||
if (ctx.ram_banking) {
|
||||
if(cart_need_save) {
|
||||
cart_battery_save();
|
||||
}
|
||||
ctx.ram_bank = ctx.ram_banks[ctx.ram_bank_value];
|
||||
}
|
||||
}
|
||||
|
||||
if((address & 0xE000) == 0xA000) {
|
||||
if(!ctx.ram_enabled)
|
||||
return;
|
||||
|
||||
if(!ctx.ram_bank)
|
||||
return;
|
||||
|
||||
ctx.ram_bank[address - 0xA000] = value;
|
||||
|
||||
if(ctx.battery) {
|
||||
ctx.need_save = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cart_battery_load(){
|
||||
char fn[1048];
|
||||
sprintf(fn, "%s.battery", ctx.filename);
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
|
||||
if(!fp) {
|
||||
fprintf(stderr, "unable to open: %s\n", fn);
|
||||
}
|
||||
|
||||
fread(ctx.ram_bank, 0x2000, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
bool cart_battery_save(){
|
||||
char fn[1048];
|
||||
sprintf(fn, "%s.battery", ctx.filename);
|
||||
FILE *fp = fopen(fn, "wb");
|
||||
|
||||
if(!fp) {
|
||||
fprintf(stderr, "unable to open: %s\n", fn);
|
||||
}
|
||||
|
||||
fwrite(ctx.ram_bank, 0x2000, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
}
|
Reference in New Issue
Block a user