MBC5 support, fixed F-1 Race issue, broke Pinball Deluxe

This commit is contained in:
flan 2022-04-06 17:43:10 -04:00
parent 2aa61b22c6
commit 2fcf0b8376
6 changed files with 116 additions and 42 deletions

View File

@ -24,7 +24,7 @@ a game boy emulator written in C
## features
- minimal UI (will upgrade eventually)
- support for no mapper, MBC1, MBC2, MBC3 (+RTC)
- support for no mapper, MBC1, MBC2, MBC3 (+RTC), MBC5
## how to use
@ -45,7 +45,6 @@ i use a scanline renderer, no fifo (yet)
## todo
- add support for MBC5 mapper
- add audio
- refactor
- add to UI

View File

@ -85,6 +85,11 @@ int cart_get_mbc_type(struct cart* cart)
cart->MBC = 3;
puts("mapper: mbc3");
break;
case 0x19: case 0x1a: case 0x1b:
case 0x1c: case 0x1d: case 0x1e:
cart->MBC = 5;
puts("mapper: mbc5");
break;
default:
printf("unsupported, type: %x\n", cart->ROM[0x147]);
cart->MBC = 0xff;
@ -114,25 +119,31 @@ void nombc_write(struct cart* cart, u16 addr, u8 val)
u8 mbc1_read(struct cart* cart, u16 addr)
{
/* rom bank 00 */
if (addr <= 0x3fff)
if (addr <= 0x3fff) {
if (cart->mode_select)
return cart->ROM[addr + (cart->zero_bank * 0x4000)];
else
return cart->ROM[addr];
}
/* rom bank 01-7f */
if (addr >= 0x4000 && addr <= 0x7fff)
return cart->ROM[(addr - 0x4000) + (cart->high_bank * 0x4000)];
/* ram bank 00-03 */
if (addr >= 0xa000 && addr <= 0xbfff)
if (cart->ram_enable && cart->RAM)
if (cart->ram_bank_count <= 2)
if (addr >= 0xa000 && addr <= 0xbfff) {
if (cart->ram_enable && cart->RAM) {
if (cart->ram_bank_count <= 2) {
return cart->RAM[(addr - 0xa000) % cart->ram_size];
else if (cart->ram_bank_count == 3 && cart->mode_select)
}
else if (cart->ram_bank_count == 3 && cart->mode_select) {
return cart->RAM[(addr - 0xa000) + (cart->ram_bank * 0x2000)];
else
}
else {
return cart->RAM[addr - 0xa000];
}
}
}
return 0xff;
}
@ -173,15 +184,19 @@ void mbc1_write(struct cart* cart, u16 addr, u8 val)
if (addr >= 0x6000 && addr <= 0x7fff)
cart->mode_select = val & 1;
if (addr >= 0xa000 && addr <= 0xbfff)
if (cart->ram_enable && cart->RAM)
if (cart->ram_bank_count <= 2)
if (addr >= 0xa000 && addr <= 0xbfff) {
if (cart->ram_enable && cart->RAM) {
if (cart->ram_bank_count <= 2) {
cart->RAM[(addr - 0xa000) % cart->ram_size] = val;
else if (cart->ram_bank_count == 3 && cart->mode_select)
}
else if (cart->ram_bank_count == 3 && cart->mode_select) {
cart->RAM[(addr - 0xa000) + (cart->ram_bank * 0x2000)] = val;
else
}
else {
cart->RAM[addr - 0xa000] = val;
}
}
}
}
u8 mbc2_read(struct cart* cart, u16 addr)
@ -195,9 +210,10 @@ u8 mbc2_read(struct cart* cart, u16 addr)
return cart->ROM[(addr - 0x4000) + (cart->rom_bank * 0x4000)];
/* internal RAM */
if (addr >= 0xa000 && addr <= 0xbfff)
if (addr >= 0xa000 && addr <= 0xbfff) {
if (cart->ram_enable)
return 0xf0 | cart->RAM[addr & 0x1ff];
}
return 0xff;
}
@ -279,7 +295,7 @@ u8 mbc3_read(struct cart* cart, u16 addr)
if (addr >= 0x4000 && addr <= 0x7fff)
return cart->ROM[(addr - 0x4000) + (cart->rom_bank * 0x4000)];
if (addr >= 0xa000 && addr <= 0xbfff)
if (addr >= 0xa000 && addr <= 0xbfff) {
if (cart->ram_enable) {
if (cart->rtc_supported && cart->rtc_mode)
switch (cart->rtc_register) {
@ -289,9 +305,10 @@ u8 mbc3_read(struct cart* cart, u16 addr)
case 0x0b: return cart->rtc_days & 0xff; break;
case 0x0c: return cart->rtc_ctrl & 0xc1; break;
}
else if(cart->RAM && !cart->rtc_mode)
else if (cart->RAM && !cart->rtc_mode)
return cart->RAM[(addr - 0xa000) + (cart->ram_bank * 0x2000)];
}
}
return 0xff;
}
@ -342,6 +359,42 @@ void mbc3_write(struct cart* cart, u16 addr, u8 val)
}
}
u8 mbc5_read(struct cart* cart, u16 addr)
{
if (addr <= 0x3fff)
return cart->ROM[addr];
if(addr >= 0x4000 && addr <= 0x7fff)
return cart->ROM[((addr - 0x4000) + (cart->rom_bank * 0x4000)) % cart->rom_size];
if(addr >= 0xa000 && addr <= 0xbfff) {
if (cart->RAM && cart->ram_enable)
return cart->RAM[(addr - 0xa000) + (cart->ram_bank * 0x2000)];
}
return 0xff;
}
void mbc5_write(struct cart* cart, u16 addr, u8 val)
{
if (addr <= 0x1fff)
cart->ram_enable = (val & 0xf) == 0xa;
if (addr >= 0x2000 && addr <= 0x2fff)
cart->rom_bank = (cart->rom_bank & 0x100) | val;
if (addr >= 0x3000 && addr <= 0x3fff)
cart->rom_bank = ((val & 1) << 8) | (cart->rom_bank & 0xff);
if (addr >= 0x4000 && addr <= 0x5fff)
cart->ram_bank = val & 0xf;
if (addr >= 0xa000 && addr <= 0xbfff) {
if (cart->RAM && cart->ram_enable)
cart->RAM[(addr - 0xa000) + (cart->ram_bank * 0x2000)] = val;
}
}
u8 cart_read(struct cart* cart, u16 addr)
{
switch (cart->MBC) {
@ -349,6 +402,7 @@ u8 cart_read(struct cart* cart, u16 addr)
case 1: return mbc1_read(cart, addr);
case 2: return mbc2_read(cart, addr);
case 3: return mbc3_read(cart, addr);
case 5: return mbc5_read(cart, addr);
}
return 0xff;
@ -361,5 +415,6 @@ void cart_write(struct cart* cart, u16 addr, u8 val)
case 1: mbc1_write(cart, addr, val); break;
case 2: mbc2_write(cart, addr, val); break;
case 3: mbc3_write(cart, addr, val); break;
case 5: mbc5_write(cart, addr, val); break;
}
}

View File

@ -4,7 +4,7 @@ void dbg_print_cpu_data(struct cpu* cpu, u8 op)
{
#ifdef _DEBUG
printf("AF=%04X BC=%04X DE=%04X "
"HL=%04X PC=%04X SP=%04X FL=%c%c%c%c iTIMA=%04X DIV=%02X TIMA=%02X : ",
"HL=%04X PC=%04X SP=%04X FL=%c%c%c%c iTIMA=%04X DIV=%02X TIMA=%02X (%02X %02X %02X %02X) : ",
cpu->AF, cpu->BC, cpu->DE,
cpu->HL, cpu->PC - 1, cpu->SP,
ISF(ZF) ? 'Z' : '-',
@ -12,7 +12,11 @@ void dbg_print_cpu_data(struct cpu* cpu, u8 op)
ISF(HF) ? 'H' : '-',
ISF(CF) ? 'C' : '-',
cpu->tima_internal,
cpu->div, cpu->tima
cpu->div, cpu->tima,
READ(cpu->PC - 1),
READ(cpu->PC),
READ(cpu->PC + 1),
READ(cpu->PC + 2)
);
if (op != 0xcb) {
@ -26,7 +30,7 @@ void dbg_print_cpu_data(struct cpu* cpu, u8 op)
}
}
else {
printf(op_cb_list[op].name);
printf(op_cb_list[READ(cpu->PC)].name);
}
printf("\n");

View File

@ -1,5 +1,4 @@
#include "lcd.h"
#include <conio.h>
const u32 colors[4] = {
0xff4fbc9b, /*white*/
@ -74,15 +73,41 @@ void lcd_destroy(struct lcd* lcd)
void lcd_check_lyc(struct lcd* lcd)
{
if (lcd->ly == lcd->lyc && lcd->stat & S_INT_LYC) {
if (lcd->ly == lcd->lyc) {
lcd->stat |= S_LYC;
lcd->cpu->IF |= STAT_INTERRUPT;
if (lcd->stat & S_INT_LYC)
lcd->cpu->IF |= STAT_INTERRUPT;
}
else {
lcd->stat &= ~S_LYC;
}
}
void lcd_mode(struct lcd* lcd, u8 mode)
{
u8 int_enabled = 0;
lcd->stat &= ~S_MODE;
lcd->stat |= mode;
switch (mode) {
case HBLANK:
int_enabled = lcd->stat & S_INT_HBLANK;
break;
case VBLANK:
int_enabled = lcd->stat & S_INT_VBLANK;
break;
case OAMSCAN:
int_enabled = lcd->stat & S_INT_OAM;
break;
}
if (int_enabled)
lcd->cpu->IF |= STAT_INTERRUPT;
}
void lcd_tick(struct lcd* lcd, u8 cycles)
{
lcd->cycles += cycles;
@ -92,7 +117,7 @@ void lcd_tick(struct lcd* lcd, u8 cycles)
case OAMSCAN:
if (lcd->cycles >= 80) {
lcd->cycles -= 80;
MODE(LCDTRANSFER, 0);
lcd_mode(lcd, LCDTRANSFER);
}
break;
@ -100,7 +125,7 @@ void lcd_tick(struct lcd* lcd, u8 cycles)
case LCDTRANSFER:
if (lcd->cycles >= 172) {
lcd->cycles -= 172;
MODE(HBLANK, 3);
lcd_mode(lcd, HBLANK);
lcd_draw(lcd);
}
@ -110,15 +135,16 @@ void lcd_tick(struct lcd* lcd, u8 cycles)
if (lcd->cycles >= 204) {
lcd->cycles -= 204;
if (++lcd->ly >= 144) {
MODE(VBLANK, 4);
lcd_mode(lcd, VBLANK);
lcd->cpu->IF |= VBLANK_INTERRUPT;
}
else {
MODE(OAMSCAN, 5);
lcd_mode(lcd, OAMSCAN);
}
lcd_check_lyc(lcd);
}
break;
case VBLANK:
@ -126,10 +152,9 @@ void lcd_tick(struct lcd* lcd, u8 cycles)
lcd->cycles -= 456;
if (++lcd->ly == 154) {
lcd->ly = 0;
lcd->il = 0;
lcd->wilc = 0xff;
lcd_check_lyc(lcd);
MODE(OAMSCAN, 5);
lcd_mode(lcd, OAMSCAN);
lcd_paint(lcd);
}
}

View File

@ -28,17 +28,11 @@
#define S_MODE 3
#define S_LYC (1 << 2)
#define S_INT_HBLANK (1 << 3)
#define S_INT_VBLANK (1 << 4)
#define S_INT_OAM (1 << 5)
#define S_INT_LYC (1 << 6)
#define MODE(n, i) \
lcd->o_il = lcd->il; \
lcd->stat &= ~S_MODE; \
lcd->stat |= n; \
if((lcd->il && !lcd->o_il) && lcd->stat & (1 << i)) { \
lcd->il = 1; \
lcd->cpu->IF |= STAT_INTERRUPT; \
}
#define lREAD(a) mmu_read(lcd->cpu->mmu, a)
#define lWRITE(a,w) mmu_write(lcd->cpu->mmu, a, w)
@ -70,9 +64,6 @@ struct lcd {
u8 wx;
u8 wilc; /* internal line counter */
u8 il; /* interrupt on line */
u8 o_il;
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Texture* texture;

View File

@ -178,7 +178,7 @@ void shift_rot(struct cpu*);
void bit_res_set(struct cpu*);
static struct cpu_op op_list[256] = {
{"NOP", 1, nop},
{"NOP", 1, nop},
{"LD BC, $%04X", 3, ld_r16_u16},
{"LD (BC), A", 1, ld_r16_a},
{"INC BC", 1, inc_r16},