// // si/gb.c: Game Boy pak functions // // CEN64: Cycle-Accurate Nintendo 64 Emulator. // Copyright (C) 2016, Jason Benaim. // // This file is subject to the terms and conditions defined in // 'LICENSE', which is part of this source code package. // #include #include "pak.h" #include "gb.h" void cart_reset_mbc(struct controller *controller); void cart_default_cleanup(); uint8_t gb_read(struct controller *controller, uint16_t address) { uint8_t (*myfunc)(struct controller *,uint16_t) = controller->gb_readmem[address>>8]; uint8_t data; if(myfunc != NULL) data = myfunc(controller, address); else data = 0xFF; // printf("gb_read: %04X:%02X\n", address, data); return data; } void gb_write(struct controller *controller, uint16_t address, uint8_t data) { void (*myfunc)(struct controller *,uint16_t,uint8_t) = controller->gb_writemem[address>>8]; if(myfunc != NULL) myfunc(controller, address, data); // printf("gb_write: %04X:%02X\n", address, data); } void gb_init(struct controller *controller) { for(int i=0;i<0x100;i++) { controller->gb_readmem [i] = NULL; controller->gb_writemem[i] = NULL; } struct gb_cart *cart = &controller->cart; // set up pak rom cart->cartromsize = controller->tpak_rom.size; cart->cartrom = (uint8_t *)(controller->tpak_rom.ptr); cart->cartrom_bank_zero = cart->cartrom; cart->cartrom_bank_n = cart->cartrom + 0x4000; // set up pak ram if( controller->tpak_save.ptr != NULL ) { cart->extram = (uint8_t *)(controller->tpak_save.ptr); cart->extram_size = controller->tpak_save.size; } else { cart->extram = calloc( 1, 65536 ); // TODO: deallocate this eventually? cart->extram_size = 65536; } cart->extram_bank = cart->extram; mbc_mbc3_install(controller); } void mbc_mbc3_install(struct controller *controller) { int i; // cart bank zero for( i=0x00; i<=0x3F; ++i ) { controller->gb_readmem[i] = mbc_mbc3_read_bank_0; } // cart bank n for( i=0x40; i<=0x7F; ++i ) { controller->gb_readmem[i] = mbc_mbc3_read_bank_n; } // write 0000-1FFF: ram enable for( i=0x00; i<=0x1F; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_ram_enable; } // write 2000-3FFF: rom bank select for( i=0x20; i<=0x3F; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_rom_bank_select; } // write 4000-5FFF: ram bank select for( i=0x40; i<=0x5F; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_ram_bank_select; } // write 6000-7FFF: clock data latch for( i=0x60; i<=0x7F; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_clock_data_latch; } // read A000-BFFF: read extram // calculate the last address where extram is installed int extram_end = 0xA0 + (controller->cart.extram_size>8192?8192:controller->cart.extram_size)/256; for( i=0xA0; igb_readmem[i] = mbc_mbc3_read_extram; } for( i=extram_end; i<=0xBF; ++i ) { controller->gb_readmem[i] = mbc_mbc3_read_ff; } // write A000-BFFF: write extram for( i=0xA0; igb_writemem[i] = mbc_mbc3_write_extram; } for( i=extram_end; i<=0xBF; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_dummy; } } uint8_t mbc_mbc3_read_ff( struct controller *controller, uint16_t address ) { return 0xff; } void mbc_mbc3_write_dummy( struct controller *controller, uint16_t address, uint8_t data ) { } uint8_t mbc_mbc3_read_bank_0( struct controller *controller, uint16_t address ) { return controller->cart.cartrom_bank_zero[address]; } uint8_t mbc_mbc3_read_bank_n( struct controller *controller, uint16_t address ) { return controller->cart.cartrom_bank_n[address&0x3fff]; } // write 0000-1FFF void mbc_mbc3_write_ram_enable( struct controller *controller, uint16_t address, uint8_t data ) { // TODO } // write 2000-3FFF void mbc_mbc3_write_rom_bank_select( struct controller *controller, uint16_t address, uint8_t data ) { struct gb_cart *cart = &controller->cart; size_t offset; data &= 0x7F; cart->cart_bank_num = data; if( data == 0 ) offset = (size_t)16384; else offset = (size_t)data*16384 % cart->cartromsize; // printf( "switch cart bank num: %02X\n", cart->cart_bank_num ); // assert("MBC3 rom bank select: offset computation", offset <= (cart->cartromsize - 16384)); cart->cartrom_bank_n = cart->cartrom + offset; } // write 4000-5FFF void mbc_mbc3_write_ram_bank_select( struct controller *controller, uint16_t address, uint8_t data ) { struct gb_cart *cart = &controller->cart; int i; switch( data ) { case 0x00: case 0x01: case 0x02: case 0x03: // printf("Switching to RAM bank %02X \n", data ); cart->extram_bank_num = data; cart->extram_bank = cart->extram + data*8192; // read A000-BFFF: read extram // calculate the last address where extram is installed int extram_end = 0xA0 + (cart->extram_size>8192?8192:cart->extram_size)/256; for( i=0xA0; igb_readmem[i] = mbc_mbc3_read_extram; } for( i=extram_end; i<=0xBF; ++i ) { controller->gb_readmem[i] = mbc_mbc3_read_ff; } // write A000-BFFF: write extram for( i=0xA0; igb_writemem[i] = mbc_mbc3_write_extram; } for( i=extram_end; i<=0xBF; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_dummy; } break; case 0x08: // seconds case 0x09: // minutes case 0x0A: // hours case 0x0B: // day bits 0-7 case 0x0C: // day bit 8, carry bit, halt flag // printf("Switching to RTC bank %02X \n", data ); cart->extram_bank_num = data; // read A000-BFFF: read rtc for( i=0xA0; i<=0xBF; ++i ) { controller->gb_readmem[i] = mbc_mbc3_read_rtc; } // write A000-BFFF: write rtc for( i=0xA0; i<=0xBF; ++i ) { controller->gb_writemem[i] = mbc_mbc3_write_rtc; } break; default: printf("Switching to invalid extram bank %02X \n", data ); break; } } // write 6000-7FFF void mbc_mbc3_write_clock_data_latch( struct controller *controller, uint16_t address, uint8_t data ) { // TODO } // read A000-BFFF extram uint8_t mbc_mbc3_read_extram( struct controller *controller, uint16_t address ) { return controller->cart.extram_bank[address&0x1fff]; } // write A000-BFFF extram void mbc_mbc3_write_extram( struct controller *controller, uint16_t address, uint8_t data ) { controller->cart.extram_bank[address&0x1fff] = data; } // read A000-BFFF rtc uint8_t mbc_mbc3_read_rtc( struct controller *controller, uint16_t address ) { return 0x00; // TODO } // write A000-BFFF rtc void mbc_mbc3_write_rtc( struct controller *controller, uint16_t address, uint8_t data ) { // TODO }