Compare commits

..

No commits in common. "4cde94d2847715b8b630d695f826679eb76882fa" and "580c349fc7d241fa51f308a2fc84529cf0575c65" have entirely different histories.

14 changed files with 96 additions and 394 deletions

View File

@ -20,7 +20,6 @@ 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

View File

@ -13,7 +13,6 @@ extern "C" {
#include "cpu.h" #include "cpu.h"
#include "rom.h" #include "rom.h"
#include "lcd.h" #include "lcd.h"
#include "instructions.h"
} }
static const char *A_FORMAT = "A: 0x%02x"; static const char *A_FORMAT = "A: 0x%02x";
@ -25,10 +24,8 @@ static const char *H_FORMAT = "H: 0x%02x";
static const char *L_FORMAT = "L: 0x%02x"; static const char *L_FORMAT = "L: 0x%02x";
static const char *SP_FORMAT = "SP: 0x%02x"; static const char *SP_FORMAT = "SP: 0x%02x";
static const char *PC_FORMAT = "PC: 0x%02x"; static const char *PC_FORMAT = "PC: 0x%02x";
static const char *INSN_FORMAT = "Next instruction: %s";
unsigned char output_image[256 * 256 * 4]; unsigned char output_image[256 * 256 * 4];
unsigned char visible_pixels[160 * 144 * 4];
unsigned char vram_tiles[256 * 96 * 4]; unsigned char vram_tiles[256 * 96 * 4];
struct key_input { struct key_input {
@ -62,7 +59,7 @@ GLuint make_output_texture() {
return image_texture; return image_texture;
} }
unsigned char default_palette[] = { 0xff, 0xaa, 0x55, 0x00 }; unsigned char default_palette[] = { 0, 0x55, 0xaa, 0xff };
void convert_output(struct lcd *lcd) { void convert_output(struct lcd *lcd) {
int x, y; int x, y;
@ -78,17 +75,6 @@ void convert_output(struct lcd *lcd) {
output_image[out_index++] = 255; output_image[out_index++] = 255;
} }
} }
out_index = 0;
for (y = 0; y < 144; y++) {
for (x = 0; x < 160; x++) {
int val = lcd->pixels[y * 160 + x];
int fill = default_palette[val];
visible_pixels[out_index++] = fill;
visible_pixels[out_index++] = fill;
visible_pixels[out_index++] = fill;
visible_pixels[out_index++] = 255;
}
}
} }
void convert_vram(struct dmg *dmg) { void convert_vram(struct dmg *dmg) {
@ -208,7 +194,6 @@ int main(int argc, char *argv[])
// setup output // setup output
GLuint texture = make_output_texture(); GLuint texture = make_output_texture();
GLuint vis_texture = make_output_texture();
GLuint vram_texture = make_output_texture(); GLuint vram_texture = make_output_texture();
editor.ReadFn = read_mem; editor.ReadFn = read_mem;
@ -291,9 +276,6 @@ int main(int argc, char *argv[])
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text(PC_FORMAT, dmg.cpu->pc); ImGui::Text(PC_FORMAT, dmg.cpu->pc);
u8 opc = dmg_read(&dmg, dmg.cpu->pc);
ImGui::Text(INSN_FORMAT, instructions[opc].format);
ImGui::Checkbox("Z", &z_flag); ImGui::Checkbox("Z", &z_flag);
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("N", &n_flag); ImGui::Checkbox("N", &n_flag);
@ -320,10 +302,10 @@ int main(int argc, char *argv[])
ImGui::End(); ImGui::End();
} }
convert_output(dmg.lcd);
{ {
ImGui::Begin("Output"); ImGui::Begin("Output");
convert_output(dmg.lcd);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, output_image); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, output_image);
ImGui::Image((void*)(intptr_t) texture, ImVec2(512, 512)); ImGui::Image((void*)(intptr_t) texture, ImVec2(512, 512));
@ -331,16 +313,6 @@ int main(int argc, char *argv[])
ImGui::End(); ImGui::End();
} }
{
ImGui::Begin("LCD");
glBindTexture(GL_TEXTURE_2D, vis_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 144, 0, GL_RGBA, GL_UNSIGNED_BYTE, visible_pixels);
ImGui::Image((void*)(intptr_t) vis_texture, ImVec2(320, 288));
ImGui::End();
}
{ {
ImGui::Begin("VRAM"); ImGui::Begin("VRAM");

View File

@ -213,7 +213,7 @@ static u8 srl(struct cpu *cpu, u8 value)
} }
clear_flag(cpu, FLAG_SIGN); clear_flag(cpu, FLAG_SIGN);
clear_flag(cpu, FLAG_HALF_CARRY); clear_flag(cpu, FLAG_HALF_CARRY);
return result; return 0;
} }
static u8 swap(struct cpu *cpu, u8 value) static u8 swap(struct cpu *cpu, u8 value)
@ -269,8 +269,7 @@ static void add(struct cpu *cpu, u8 value, int with_carry)
{ {
u8 sum_trunc; u8 sum_trunc;
int sum_full = cpu->a + value; int sum_full = cpu->a + value;
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0; if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
if (carry) {
sum_full++; sum_full++;
} }
sum_trunc = (u8) sum_full; sum_trunc = (u8) sum_full;
@ -280,12 +279,12 @@ static void add(struct cpu *cpu, u8 value, int with_carry)
clear_flag(cpu, FLAG_ZERO); clear_flag(cpu, FLAG_ZERO);
} }
clear_flag(cpu, FLAG_SIGN); clear_flag(cpu, FLAG_SIGN);
if (sum_full > 0xff) { if (sum_full > sum_trunc) {
set_flag(cpu, FLAG_CARRY); set_flag(cpu, FLAG_CARRY);
} else { } else {
clear_flag(cpu, FLAG_CARRY); clear_flag(cpu, FLAG_CARRY);
} }
if (((cpu->a & 0xf) + (value & 0xf) + carry) & 0x10) { if (((cpu->a & 0xf) + (value & 0xf)) & 0x10) {
set_flag(cpu, FLAG_HALF_CARRY); set_flag(cpu, FLAG_HALF_CARRY);
} else { } else {
clear_flag(cpu, FLAG_HALF_CARRY); clear_flag(cpu, FLAG_HALF_CARRY);
@ -297,11 +296,10 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare
{ {
u8 sum_trunc; u8 sum_trunc;
int sum_full = cpu->a - value; int sum_full = cpu->a - value;
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0; if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
if (carry) {
sum_full--; sum_full--;
} }
sum_trunc = (u8) sum_full; sum_trunc = (u8) (sum_full & 0xff);
if (!sum_trunc) { if (!sum_trunc) {
set_flag(cpu, FLAG_ZERO); set_flag(cpu, FLAG_ZERO);
} else { } else {
@ -455,34 +453,6 @@ 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)
@ -542,9 +512,6 @@ 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;
@ -569,13 +536,6 @@ void cpu_step(struct cpu *cpu)
cpu->a = rotate_right(cpu, cpu->a); cpu->a = rotate_right(cpu, cpu->a);
break; break;
case 0x37: // SCF
set_flag(cpu, FLAG_CARRY);
break;
case 0x3f: // CCF
clear_flag(cpu, FLAG_CARRY);
break;
// incs and decs // incs and decs
case 0x03: write_bc(cpu, read_bc(cpu) + 1); break; case 0x03: write_bc(cpu, read_bc(cpu) + 1); break;
case 0x04: inc_with_carry(cpu, &cpu->b); break; case 0x04: inc_with_carry(cpu, &cpu->b); break;
@ -801,7 +761,7 @@ void cpu_step(struct cpu *cpu)
case 0xd2: // JP NC,a16 case 0xd2: // JP NC,a16
temp16 = read16(cpu, cpu->pc); temp16 = read16(cpu, cpu->pc);
cpu->pc += 2; cpu->pc += 2;
if (!flag_isset(cpu, FLAG_CARRY)) { if (flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = temp16; cpu->pc = temp16;
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles; cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
} }
@ -812,14 +772,6 @@ void cpu_step(struct cpu *cpu)
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles; cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
} }
break; break;
case 0xda: // JP C, u16
temp16 = read16(cpu, cpu->pc);
cpu->pc += 2;
if (flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = temp16;
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
break;
case 0x80: add(cpu, cpu->b, 0); break; case 0x80: add(cpu, cpu->b, 0); break;
case 0x81: add(cpu, cpu->c, 0); break; case 0x81: add(cpu, cpu->c, 0); break;
@ -870,7 +822,7 @@ void cpu_step(struct cpu *cpu)
break; break;
case 0xde: // SBC A, u8 case 0xde: // SBC A, u8
subtract(cpu, read8(cpu, cpu->pc), 1, 0); subtract(cpu, read8(cpu, cpu->pc), 0, 1);
cpu->pc++; cpu->pc++;
break; break;
@ -932,7 +884,6 @@ 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
@ -998,7 +949,6 @@ void cpu_step(struct cpu *cpu)
break; break;
case 0xf1: // POP AF case 0xf1: // POP AF
write_af(cpu, pop(cpu)); write_af(cpu, pop(cpu));
cpu->f &= 0xf0;
break; break;
case 0xf2: // LD A,(C) case 0xf2: // LD A,(C)
cpu->a = read8(cpu, 0xff00 + cpu->c); cpu->a = read8(cpu, 0xff00 + cpu->c);

145
src/dmg.c
View File

@ -5,7 +5,6 @@
#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"
@ -55,24 +54,19 @@ 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) {
if (address < 0x4000) { if (address < 0x4000) {
return dmg->rom->data[address]; return dmg->rom->data[address];
} else if (address < 0x8000) { } else if (address < 0x8000) {
// TODO switchable rom bank
return dmg->rom->data[address]; return dmg->rom->data[address];
} else if (address < 0xa000) { } else if (address < 0xa000) {
return dmg->video_ram[address - 0x8000]; return dmg->video_ram[address - 0x8000];
} else if (address < 0xc000) { } else if (address < 0xc000) {
printf("RAM bank not handled by MBC\n"); // TODO switchable ram bank
return 0xff; return 0;
} else if (address < 0xe000) { } else if (address < 0xe000) {
return dmg->main_ram[address - 0xc000]; return dmg->main_ram[address - 0xc000];
} else if (lcd_is_valid_addr(address)) { } else if (lcd_is_valid_addr(address)) {
@ -99,16 +93,13 @@ 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);
dmg->rom->data[address] = data;
} else if (address < 0x8000) { } else if (address < 0x8000) {
// TODO switchable rom bank // TODO switchable rom bank
printf("warning: writing 0x%04x in rom\n", address); printf("warning: writing 0x%04x in rom\n", address);
dmg->rom->data[address] = data;
} else if (address < 0xa000) { } else if (address < 0xa000) {
dmg->video_ram[address - 0x8000] = data; dmg->video_ram[address - 0x8000] = data;
} else if (address < 0xc000) { } else if (address < 0xc000) {
@ -144,86 +135,6 @@ void dmg_request_interrupt(struct dmg *dmg, int nr)
dmg->interrupt_requested |= nr; dmg->interrupt_requested |= nr;
} }
// TODO move to lcd.c, it needs to be able to access dmg_read though
static void render_background(struct dmg *dmg, int lcdc)
{
int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
int window_base = (lcdc & LCDC_WINDOW_TILE_MAP) ? 0x9c00 : 0x9800;
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
int tilebase = use_unsigned ? 0x8000 : 0x9000;
//printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
int k = 0, off = 0;
int tile_y = 0, tile_x = 0;
for (tile_y = 0; tile_y < 32; tile_y++) {
for (tile_x = 0; tile_x < 32; tile_x++) {
off = 256 * 8 * tile_y + 8 * tile_x;
int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x));
int eff_addr;
if (use_unsigned) {
eff_addr = tilebase + 16 * tile;
} else {
eff_addr = tilebase + 16 * (signed char) tile;
}
int b, i;
for (b = 0; b < 16; b += 2) {
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 7; i >= 0; i--) {
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0) << 1;
dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;
}
}
}
}
struct oam_entry {
u8 pos_y;
u8 pos_x;
u8 tile;
u8 attrs;
};
// TODO: only ten per scanline, priority
static void render_objs(struct dmg *dmg)
{
struct oam_entry *oam = (struct oam_entry *) dmg->lcd->oam;
int k, lcd_x, lcd_y, off;
for (k = 0; k < 40; k++, oam++) {
if (oam->pos_y == 0 || oam->pos_y >= 160) {
continue;
}
if (oam->pos_x == 0 || oam->pos_y >= 168) {
continue;
}
lcd_x = oam->pos_x - 8;
lcd_y = oam->pos_y - 16;
off = 160 * lcd_y + lcd_x;
int eff_addr = 0x8000 + 16 * oam->tile;
int b, i;
for (b = 0; b < 16; b += 2) {
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 7; i >= 0; i--) {
if (off < 0 || off >= 160 * 144) {
// terrible clipping. need to not have an if per-pixel
continue;
}
dmg->lcd->pixels[off] = ((data1 & (1 << i)) ? 1 : 0) << 1;
dmg->lcd->pixels[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 152;
}
}
}
void dmg_step(void *_dmg) void dmg_step(void *_dmg)
{ {
struct dmg *dmg = (struct dmg *) _dmg; struct dmg *dmg = (struct dmg *) _dmg;
@ -254,7 +165,6 @@ void dmg_step(void *_dmg)
lcd_set_mode(dmg->lcd, 1); lcd_set_mode(dmg->lcd, 1);
} }
// TODO: do all of this per-scanline instead of everything in vblank
if (next_scanline == 144) { if (next_scanline == 144) {
// vblank has started, draw all the stuff from ram into the lcd // vblank has started, draw all the stuff from ram into the lcd
dmg_request_interrupt(dmg, INT_VBLANK); dmg_request_interrupt(dmg, INT_VBLANK);
@ -263,20 +173,41 @@ void dmg_step(void *_dmg)
} }
int lcdc = lcd_read(dmg->lcd, REG_LCDC); int lcdc = lcd_read(dmg->lcd, REG_LCDC);
if (lcdc & LCDC_ENABLE_BG) { int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
render_background(dmg, lcdc); int window_base = (lcdc & LCDC_WINDOW_TILE_MAP) ? 0x9c00 : 0x9800;
} int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
int tilebase = use_unsigned ? 0x8000 : 0x9000;
if (lcdc & LCDC_ENABLE_WINDOW) {
// printf("window\n"); //printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
}
int k = 0, off = 0;
lcd_apply_scroll(dmg->lcd); int tile_y = 0, tile_x = 0;
for (tile_y = 0; tile_y < 32; tile_y++) {
if (lcdc & LCDC_ENABLE_OBJ) { for (tile_x = 0; tile_x < 32; tile_x++) {
render_objs(dmg); off = 256 * 8 * tile_y + 8 * tile_x;
int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x));
int eff_addr;
if (use_unsigned) {
eff_addr = tilebase + 16 * tile;
} else {
eff_addr = tilebase + 16 * (signed char) tile;
}
int b, i;
for (b = 0; b < 16; b += 2) {
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 7; i >= 0; i--) {
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0) << 1;
dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;
}
}
} }
// now copy 256x256 buf to 160x144 based on window registers
lcd_copy(dmg->lcd);
lcd_draw(dmg->lcd); lcd_draw(dmg->lcd);
} }
} else { } else {

View File

@ -1,7 +1,9 @@
#ifndef _DMG_H #ifndef _DMG_H
#define _DMG_H #define _DMG_H
#include "types.h" #include "cpu.h"
#include "rom.h"
#include "lcd.h"
#define FIELD_JOY 1 #define FIELD_JOY 1
#define FIELD_ACTION 2 #define FIELD_ACTION 2
@ -15,10 +17,6 @@
#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;

View File

@ -66,20 +66,10 @@ void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value)
lcd->pixels[y * LCD_WIDTH + x] = value; lcd->pixels[y * LCD_WIDTH + x] = value;
} }
void lcd_apply_scroll(struct lcd *lcd) void lcd_copy(struct lcd *lcd)
{ {
int scroll_y = lcd_read(lcd, REG_SCY); // use all the registers to compute the pixel data
int scroll_x = lcd_read(lcd, REG_SCX);
int lines;
for (lines = 0; lines < 144; lines++) {
int src_y = (scroll_y + lines) & 0xff;
int cols;
for (cols = 0; cols < 160; cols++) {
int src_off = (src_y << 8) + ((scroll_x + cols) & 0xff);
lcd->pixels[lines * 160 + cols] = lcd->buf[src_off];
}
}
} }
int lcd_step(struct lcd *lcd) int lcd_step(struct lcd *lcd)

View File

@ -58,8 +58,9 @@ void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit);
int lcd_isset(struct lcd *lcd, u16 addr, u8 bit); int lcd_isset(struct lcd *lcd, u16 addr, u8 bit);
void lcd_set_mode(struct lcd *lcd, int mode); void lcd_set_mode(struct lcd *lcd, int mode);
// i feel like i'm going to need to call this every cycle and update regs
int lcd_step(struct lcd *lcd); int lcd_step(struct lcd *lcd);
void lcd_apply_scroll(struct lcd *lcd); void lcd_copy(struct lcd *lcd);
// output the pixels to the screen // output the pixels to the screen
void lcd_draw(struct lcd *lcd); void lcd_draw(struct lcd *lcd);

View File

@ -1,94 +0,0 @@
#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;
if (!use_bank) {
use_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);
}

View File

@ -1,22 +0,0 @@
#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,15 +17,12 @@ 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;
} }

View File

@ -2,12 +2,11 @@
#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);

View File

@ -12,7 +12,6 @@ add_application(Emulator
../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_mac.c lcd_mac.c
resources.r resources.r

View File

@ -18,7 +18,6 @@
#include "cpu.h" #include "cpu.h"
#include "rom.h" #include "rom.h"
#include "lcd.h" #include "lcd.h"
#include "mbc.h"
WindowPtr g_wp; WindowPtr g_wp;
DialogPtr stateDialog; DialogPtr stateDialog;
@ -53,9 +52,8 @@ void InitEverything(void)
g_running = 1; g_running = 1;
} }
// 160 pixels / 8 bits per pixel = 20 bytes per line char offscreen[32 * 256];
char offscreen[20 * 144]; Rect offscreenRect = { 0, 0, 256, 256 };
Rect offscreenRect = { 0, 0, 144, 160 };
BitMap offscreenBmp; BitMap offscreenBmp;
@ -63,34 +61,26 @@ int lastTicks;
void Render(void) void Render(void)
{ {
long k = 0, dst, bit; long k = 0, dst;
for (dst = 0; dst < 20 * 144; dst++) { for (dst = 0; dst < 32 * 256; dst++) {
for (bit = 7; bit >= 0; bit--) { offscreen[dst] = lcd.buf[k++] << 7
offscreen[dst] |= lcd.pixels[k++]; | lcd.buf[k++] << 6
offscreen[dst] <<= 1; | lcd.buf[k++] << 5
} | lcd.buf[k++] << 4
dst++; | lcd.buf[k++] << 3
| lcd.buf[k++] << 2
| lcd.buf[k++] << 1
| lcd.buf[k++];
} }
/*
offscreen[dst] = lcd.pixels[k++] << 7;
offscreen[dst] |= lcd.pixels[k++] << 6;
offscreen[dst] |= lcd.pixels[k++] << 5;
offscreen[dst] |= lcd.pixels[k++] << 4;
offscreen[dst] |= lcd.pixels[k++] << 3;
offscreen[dst] |= lcd.pixels[k++] << 2;
offscreen[dst] |= lcd.pixels[k++] << 1;
offscreen[dst] |= lcd.pixels[k++];
*/
SetPort(g_wp); SetPort(g_wp);
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &offscreenRect, srcCopy, NULL); CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &g_wp->portRect, srcCopy, NULL);
//EraseRect(&g_wp->portRect); //EraseRect(&g_wp->portRect);
// MoveTo(10, 160); MoveTo(10, 160);
// char debug[128]; char debug[128];
// sprintf(debug, "PC: %04x", cpu.pc); sprintf(debug, "PC: %04x", cpu.pc);
// C2PStr(debug); C2PStr(debug);
// DrawString(debug); DrawString(debug);
} }
void StartEmulation(void) void StartEmulation(void)
@ -101,7 +91,7 @@ void StartEmulation(void)
offscreenBmp.baseAddr = offscreen; offscreenBmp.baseAddr = offscreen;
offscreenBmp.bounds = offscreenRect; offscreenBmp.bounds = offscreenRect;
offscreenBmp.rowBytes = 20; offscreenBmp.rowBytes = 32;
emulationOn = 1; emulationOn = 1;
} }
@ -131,15 +121,8 @@ bool LoadRom(StrFileName fileName, short vRefNum)
} }
amtRead = rom.length; amtRead = rom.length;
FSRead(fileNo, &amtRead, rom.data); FSRead(fileNo, &amtRead, rom.data);
rom.mbc = mbc_new(rom.data[0x147]);
if (!rom.mbc) {
ParamText("\pThis cartridge type is unsupported.", "\p", "\p", "\p");
Alert(ALRT_4_LINE, NULL);
return false;
}
return true; return true;
} }
@ -282,25 +265,24 @@ int main(int argc, char *argv[])
lastTicks = now; lastTicks = now;
Render(); Render();
} }
if (Button()) g_running = false; }
} else {
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) { if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
if (IsDialogEvent(&evt)) { if (IsDialogEvent(&evt)) {
DialogRef hitBox; DialogRef hitBox;
DialogItemIndex hitItem; DialogItemIndex hitItem;
if (DialogSelect(&evt, &hitBox, &hitItem)) { if (DialogSelect(&evt, &hitBox, &hitItem)) {
stateDialog = NULL; stateDialog = NULL;
}
} else switch(evt.what) {
case mouseDown:
OnMouseDown(&evt);
break;
case updateEvt:
BeginUpdate((WindowPtr) evt.message);
Render();
EndUpdate((WindowPtr) evt.message);
break;
} }
} else switch(evt.what) {
case mouseDown:
OnMouseDown(&evt);
break;
case updateEvt:
BeginUpdate((WindowPtr) evt.message);
Render();
EndUpdate((WindowPtr) evt.message);
break;
} }
} }
} }

View File

@ -7,7 +7,7 @@
#include "types.h" #include "types.h"
#include "dmg.h" #include "dmg.h"
#define WINDOW_TITLE "\pOutput" #define WINDOW_TITLE "\pEmulator"
#define WINDOW_X 100 #define WINDOW_X 100
#define WINDOW_Y 100 #define WINDOW_Y 100