1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
//
// 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 <stddef.h>
#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; i<extram_end; ++i ) {
controller->gb_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; i<extram_end; ++i ) {
controller->gb_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; i<extram_end; ++i ) {
controller->gb_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; i<extram_end; ++i ) {
controller->gb_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
}
|