start on mbc1

This commit is contained in:
Matthew Laux 2022-08-01 22:45:37 -05:00
parent 0f43ebf4cc
commit 03ef4d1116
8 changed files with 172 additions and 5 deletions

View File

@ -20,6 +20,7 @@ add_executable(gb6
../src/instructions.c
../src/lcd.c
../src/rom.c
../src/mbc.c
emulator.c
lcd_imgui.c
imgui/imgui_demo.cpp

View File

@ -453,6 +453,34 @@ static void conditional_jump(struct cpu *cpu, u8 opc, u8 neg_op, int flag) {
}
}
static void daa(struct cpu *cpu)
{
// https://forums.nesdev.org/viewtopic.php?t=15944
if (!flag_isset(cpu, FLAG_SIGN)) {
if (flag_isset(cpu, FLAG_CARRY) || cpu->a > 0x99) {
cpu->a += 0x60;
set_flag(cpu, FLAG_CARRY);
}
if (flag_isset(cpu, FLAG_HALF_CARRY) || (cpu->a & 0x0f) > 0x09) {
cpu->a += 0x6;
}
} else {
if (flag_isset(cpu, FLAG_CARRY)) {
cpu->a -= 0x60;
}
if (flag_isset(cpu, FLAG_HALF_CARRY)) {
cpu->a -= 0x6;
}
}
if (cpu->a) {
set_flag(cpu, FLAG_ZERO);
} else {
clear_flag(cpu, FLAG_ZERO);
}
clear_flag(cpu, FLAG_HALF_CARRY);
}
static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
static u16 check_interrupts(struct cpu *cpu)
@ -480,6 +508,9 @@ static u16 check_interrupts(struct cpu *cpu)
return 0;
}
/*
*/
void cpu_step(struct cpu *cpu)
{
u8 temp;
@ -512,6 +543,9 @@ void cpu_step(struct cpu *cpu)
case 0x0f: // RRCA
cpu->a = rrc(cpu, cpu->a);
break;
case 0x10: // STOP
cpu->pc++;
break;
case 0x11: // LD DE,d16
write_de(cpu, read16(cpu, cpu->pc));
cpu->pc += 2;
@ -892,6 +926,7 @@ void cpu_step(struct cpu *cpu)
case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break;
case 0x27: // DAA
daa(cpu);
break;
case 0x76: // HALT

View File

@ -5,6 +5,7 @@
#include "rom.h"
#include "lcd.h"
#include "dmg.h"
#include "mbc.h"
#include "types.h"
#include "bootstrap.h"
@ -54,6 +55,12 @@ static int counter;
u8 dmg_read(void *_dmg, u16 address)
{
struct dmg *dmg = (struct dmg *) _dmg;
u8 mbc_data;
if (mbc_read(dmg->rom->mbc, dmg, address, &mbc_data)) {
return mbc_data;
}
// if (address < 0x100) {
// return dmg_boot_rom[address];
// } else if (address < 0x4000) {
@ -93,6 +100,11 @@ u8 dmg_read(void *_dmg, u16 address)
void dmg_write(void *_dmg, u16 address, u8 data)
{
struct dmg *dmg = (struct dmg *) _dmg;
if (mbc_write(dmg->rom->mbc, dmg, address, data)) {
return;
}
if (address < 0x4000) {
printf("warning: writing 0x%04x in rom\n", address);
} else if (address < 0x8000) {

View File

@ -1,9 +1,7 @@
#ifndef _DMG_H
#define _DMG_H
#include "cpu.h"
#include "rom.h"
#include "lcd.h"
#include "types.h"
#define FIELD_JOY 1
#define FIELD_ACTION 2
@ -17,6 +15,10 @@
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
struct cpu;
struct rom;
struct lcd;
struct dmg {
struct cpu *cpu;
struct rom *rom;

91
src/mbc.c Normal file
View File

@ -0,0 +1,91 @@
#include <stdlib.h>
#include <stdio.h>
#include "types.h"
#include "mbc.h"
#include "dmg.h"
#include "rom.h"
static int mbc_noop_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
return 0;
}
static int mbc_noop_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
{
return 0;
}
static int mbc1_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
if (addr >= 0x4000 && addr <= 0x7fff) {
int use_bank = mbc->rom_bank || 1;
*out_data = dmg->rom->data[0x4000 * use_bank + (addr & 0x3fff)];
return 1;
} else if (addr >= 0xa000 && addr <= 0xbfff) {
if (mbc->ram_enabled) {
*out_data = mbc->ram[0x2000 * mbc->ram_bank + (addr & 0x1fff)];
} else {
*out_data = 0xff;
}
return 1;
}
return 0;
}
static int mbc1_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
{
if (addr >= 0 && addr <= 0x1fff) {
mbc->ram_enabled = (data & 0xf) == 0xa;
return 1;
} else if (addr >= 0x2000 && addr <= 0x3fff) {
mbc->rom_bank = data & 0x1f;
return 1;
} else if (addr >= 0x4000 && addr <= 0x5fff) {
mbc->ram_bank = data & 0x03;
return 1;
} else if (addr >= 0x6000 && addr <= 0x7fff) {
//printf("sel %d\n", data);
return 1;
} else if (addr >= 0xa000 && addr <= 0xbfff) {
if (mbc->ram_enabled) {
mbc->ram[0x2000 * mbc->ram_bank + (addr & 0x1fff)] = data;
return 1;
}
}
return 0;
}
struct mbc mbc_noop = {
mbc_noop_read,
mbc_noop_write,
};
struct mbc mbc1 = {
mbc1_read,
mbc1_write,
};
struct mbc *mbc_new(int type)
{
switch (type) {
case 0:
return &mbc_noop;
case 1:
case 2:
case 3:
return &mbc1;
}
return NULL;
}
int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
return mbc->read_fn(mbc, dmg, addr, out_data);
}
int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
{
return mbc->write_fn(mbc, dmg, addr, data);
}

22
src/mbc.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _MBC_H
#define _MBC_H
#include "types.h"
struct dmg;
struct mbc {
int (*read_fn)(struct mbc *, struct dmg *, u16, u8 *);
int (*write_fn)(struct mbc *, struct dmg *, u16, u8);
int type;
int rom_bank;
int ram_bank;
int ram_enabled;
u8 ram[0x8000];
};
struct mbc *mbc_new(int type);
int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data);
int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data);
#endif

View File

@ -17,12 +17,15 @@ int rom_load(struct rom *rom, const char *filename)
len = ftell(fp);
rewind(fp);
rom->type = 0; // TODO read type from cart
rom->data = malloc(len);
rom->length = len;
if (fread(rom->data, 1, len, fp) < len) {
return 0;
}
rom->mbc = mbc_new(rom->data[0x147]);
if (!rom->mbc) {
return 0;
}
return 1;
}

View File

@ -2,11 +2,12 @@
#define _ROM_H
#include "types.h"
#include "mbc.h"
struct rom {
u32 length;
int type;
u8 *data;
struct mbc *mbc;
};
int rom_load(struct rom *rom, const char *filename);