mirror of
https://github.com/mlaux/gb6.git
synced 2025-01-05 05:29:31 +00:00
start on mbc1
This commit is contained in:
parent
0f43ebf4cc
commit
03ef4d1116
@ -20,6 +20,7 @@ add_executable(gb6
|
|||||||
../src/instructions.c
|
../src/instructions.c
|
||||||
../src/lcd.c
|
../src/lcd.c
|
||||||
../src/rom.c
|
../src/rom.c
|
||||||
|
../src/mbc.c
|
||||||
emulator.c
|
emulator.c
|
||||||
lcd_imgui.c
|
lcd_imgui.c
|
||||||
imgui/imgui_demo.cpp
|
imgui/imgui_demo.cpp
|
||||||
|
35
src/cpu.c
35
src/cpu.c
@ -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 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
|
||||||
|
|
||||||
static u16 check_interrupts(struct cpu *cpu)
|
static u16 check_interrupts(struct cpu *cpu)
|
||||||
@ -480,6 +508,9 @@ static u16 check_interrupts(struct cpu *cpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
void cpu_step(struct cpu *cpu)
|
void cpu_step(struct cpu *cpu)
|
||||||
{
|
{
|
||||||
u8 temp;
|
u8 temp;
|
||||||
@ -512,6 +543,9 @@ void cpu_step(struct cpu *cpu)
|
|||||||
case 0x0f: // RRCA
|
case 0x0f: // RRCA
|
||||||
cpu->a = rrc(cpu, cpu->a);
|
cpu->a = rrc(cpu, cpu->a);
|
||||||
break;
|
break;
|
||||||
|
case 0x10: // STOP
|
||||||
|
cpu->pc++;
|
||||||
|
break;
|
||||||
case 0x11: // LD DE,d16
|
case 0x11: // LD DE,d16
|
||||||
write_de(cpu, read16(cpu, cpu->pc));
|
write_de(cpu, read16(cpu, cpu->pc));
|
||||||
cpu->pc += 2;
|
cpu->pc += 2;
|
||||||
@ -892,6 +926,7 @@ void cpu_step(struct cpu *cpu)
|
|||||||
case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break;
|
case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break;
|
||||||
|
|
||||||
case 0x27: // DAA
|
case 0x27: // DAA
|
||||||
|
daa(cpu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x76: // HALT
|
case 0x76: // HALT
|
||||||
|
12
src/dmg.c
12
src/dmg.c
@ -5,6 +5,7 @@
|
|||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
#include "dmg.h"
|
#include "dmg.h"
|
||||||
|
#include "mbc.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "bootstrap.h"
|
#include "bootstrap.h"
|
||||||
|
|
||||||
@ -54,6 +55,12 @@ static int counter;
|
|||||||
u8 dmg_read(void *_dmg, u16 address)
|
u8 dmg_read(void *_dmg, u16 address)
|
||||||
{
|
{
|
||||||
struct dmg *dmg = (struct dmg *) _dmg;
|
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) {
|
// if (address < 0x100) {
|
||||||
// return dmg_boot_rom[address];
|
// return dmg_boot_rom[address];
|
||||||
// } else if (address < 0x4000) {
|
// } else if (address < 0x4000) {
|
||||||
@ -93,6 +100,11 @@ u8 dmg_read(void *_dmg, u16 address)
|
|||||||
void dmg_write(void *_dmg, u16 address, u8 data)
|
void dmg_write(void *_dmg, u16 address, u8 data)
|
||||||
{
|
{
|
||||||
struct dmg *dmg = (struct dmg *) _dmg;
|
struct dmg *dmg = (struct dmg *) _dmg;
|
||||||
|
|
||||||
|
if (mbc_write(dmg->rom->mbc, dmg, address, data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (address < 0x4000) {
|
if (address < 0x4000) {
|
||||||
printf("warning: writing 0x%04x in rom\n", address);
|
printf("warning: writing 0x%04x in rom\n", address);
|
||||||
} else if (address < 0x8000) {
|
} else if (address < 0x8000) {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#ifndef _DMG_H
|
#ifndef _DMG_H
|
||||||
#define _DMG_H
|
#define _DMG_H
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "types.h"
|
||||||
#include "rom.h"
|
|
||||||
#include "lcd.h"
|
|
||||||
|
|
||||||
#define FIELD_JOY 1
|
#define FIELD_JOY 1
|
||||||
#define FIELD_ACTION 2
|
#define FIELD_ACTION 2
|
||||||
@ -17,6 +15,10 @@
|
|||||||
#define BUTTON_SELECT (1 << 2)
|
#define BUTTON_SELECT (1 << 2)
|
||||||
#define BUTTON_START (1 << 3)
|
#define BUTTON_START (1 << 3)
|
||||||
|
|
||||||
|
struct cpu;
|
||||||
|
struct rom;
|
||||||
|
struct lcd;
|
||||||
|
|
||||||
struct dmg {
|
struct dmg {
|
||||||
struct cpu *cpu;
|
struct cpu *cpu;
|
||||||
struct rom *rom;
|
struct rom *rom;
|
||||||
|
91
src/mbc.c
Normal file
91
src/mbc.c
Normal 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
22
src/mbc.h
Normal 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
|
@ -17,12 +17,15 @@ int rom_load(struct rom *rom, const char *filename)
|
|||||||
len = ftell(fp);
|
len = ftell(fp);
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
|
|
||||||
rom->type = 0; // TODO read type from cart
|
|
||||||
rom->data = malloc(len);
|
rom->data = malloc(len);
|
||||||
rom->length = len;
|
rom->length = len;
|
||||||
if (fread(rom->data, 1, len, fp) < len) {
|
if (fread(rom->data, 1, len, fp) < len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
rom->mbc = mbc_new(rom->data[0x147]);
|
||||||
|
if (!rom->mbc) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
#define _ROM_H
|
#define _ROM_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "mbc.h"
|
||||||
|
|
||||||
struct rom {
|
struct rom {
|
||||||
u32 length;
|
u32 length;
|
||||||
int type;
|
|
||||||
u8 *data;
|
u8 *data;
|
||||||
|
struct mbc *mbc;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rom_load(struct rom *rom, const char *filename);
|
int rom_load(struct rom *rom, const char *filename);
|
||||||
|
Loading…
Reference in New Issue
Block a user