MBC5 support, fixed F-1 Race issue, broke Pinball Deluxe
This commit is contained in:
parent
2aa61b22c6
commit
2fcf0b8376
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
Loading…
Reference in New Issue