mirror of
https://github.com/mlaux/gb6.git
synced 2024-09-28 01:54:29 +00:00
Compare commits
No commits in common. "4cde94d2847715b8b630d695f826679eb76882fa" and "580c349fc7d241fa51f308a2fc84529cf0575c65" have entirely different histories.
4cde94d284
...
580c349fc7
@ -20,7 +20,6 @@ add_executable(gb6
|
||||
../src/instructions.c
|
||||
../src/lcd.c
|
||||
../src/rom.c
|
||||
../src/mbc.c
|
||||
emulator.c
|
||||
lcd_imgui.c
|
||||
imgui/imgui_demo.cpp
|
||||
|
@ -13,7 +13,6 @@ extern "C" {
|
||||
#include "cpu.h"
|
||||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
#include "instructions.h"
|
||||
}
|
||||
|
||||
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 *SP_FORMAT = "SP: 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 visible_pixels[160 * 144 * 4];
|
||||
unsigned char vram_tiles[256 * 96 * 4];
|
||||
|
||||
struct key_input {
|
||||
@ -62,7 +59,7 @@ GLuint make_output_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) {
|
||||
int x, y;
|
||||
@ -78,17 +75,6 @@ void convert_output(struct lcd *lcd) {
|
||||
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) {
|
||||
@ -208,7 +194,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
// setup output
|
||||
GLuint texture = make_output_texture();
|
||||
GLuint vis_texture = make_output_texture();
|
||||
GLuint vram_texture = make_output_texture();
|
||||
|
||||
editor.ReadFn = read_mem;
|
||||
@ -291,9 +276,6 @@ int main(int argc, char *argv[])
|
||||
ImGui::SameLine();
|
||||
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::SameLine();
|
||||
ImGui::Checkbox("N", &n_flag);
|
||||
@ -320,10 +302,10 @@ int main(int argc, char *argv[])
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
convert_output(dmg.lcd);
|
||||
{
|
||||
ImGui::Begin("Output");
|
||||
|
||||
convert_output(dmg.lcd);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
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));
|
||||
@ -331,16 +313,6 @@ int main(int argc, char *argv[])
|
||||
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");
|
||||
|
||||
|
66
src/cpu.c
66
src/cpu.c
@ -213,7 +213,7 @@ static u8 srl(struct cpu *cpu, u8 value)
|
||||
}
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int sum_full = cpu->a + value;
|
||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||
if (carry) {
|
||||
if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
|
||||
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_SIGN);
|
||||
if (sum_full > 0xff) {
|
||||
if (sum_full > sum_trunc) {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
int sum_full = cpu->a - value;
|
||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||
if (carry) {
|
||||
if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
|
||||
sum_full--;
|
||||
}
|
||||
sum_trunc = (u8) sum_full;
|
||||
sum_trunc = (u8) (sum_full & 0xff);
|
||||
if (!sum_trunc) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} 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 check_interrupts(struct cpu *cpu)
|
||||
@ -542,9 +512,6 @@ 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;
|
||||
@ -569,13 +536,6 @@ void cpu_step(struct cpu *cpu)
|
||||
cpu->a = rotate_right(cpu, cpu->a);
|
||||
break;
|
||||
|
||||
case 0x37: // SCF
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
break;
|
||||
case 0x3f: // CCF
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
break;
|
||||
|
||||
// incs and decs
|
||||
case 0x03: write_bc(cpu, read_bc(cpu) + 1); 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
|
||||
temp16 = read16(cpu, cpu->pc);
|
||||
cpu->pc += 2;
|
||||
if (!flag_isset(cpu, FLAG_CARRY)) {
|
||||
if (flag_isset(cpu, FLAG_CARRY)) {
|
||||
cpu->pc = temp16;
|
||||
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;
|
||||
}
|
||||
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 0x81: add(cpu, cpu->c, 0); break;
|
||||
@ -870,7 +822,7 @@ void cpu_step(struct cpu *cpu)
|
||||
break;
|
||||
|
||||
case 0xde: // SBC A, u8
|
||||
subtract(cpu, read8(cpu, cpu->pc), 1, 0);
|
||||
subtract(cpu, read8(cpu, cpu->pc), 0, 1);
|
||||
cpu->pc++;
|
||||
break;
|
||||
|
||||
@ -932,7 +884,6 @@ 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
|
||||
@ -998,7 +949,6 @@ void cpu_step(struct cpu *cpu)
|
||||
break;
|
||||
case 0xf1: // POP AF
|
||||
write_af(cpu, pop(cpu));
|
||||
cpu->f &= 0xf0;
|
||||
break;
|
||||
case 0xf2: // LD A,(C)
|
||||
cpu->a = read8(cpu, 0xff00 + cpu->c);
|
||||
|
145
src/dmg.c
145
src/dmg.c
@ -5,7 +5,6 @@
|
||||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
#include "dmg.h"
|
||||
#include "mbc.h"
|
||||
#include "types.h"
|
||||
#include "bootstrap.h"
|
||||
|
||||
@ -55,24 +54,19 @@ 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) {
|
||||
if (address < 0x4000) {
|
||||
return dmg->rom->data[address];
|
||||
} else if (address < 0x8000) {
|
||||
// TODO switchable rom bank
|
||||
return dmg->rom->data[address];
|
||||
} else if (address < 0xa000) {
|
||||
return dmg->video_ram[address - 0x8000];
|
||||
} else if (address < 0xc000) {
|
||||
printf("RAM bank not handled by MBC\n");
|
||||
return 0xff;
|
||||
// TODO switchable ram bank
|
||||
return 0;
|
||||
} else if (address < 0xe000) {
|
||||
return dmg->main_ram[address - 0xc000];
|
||||
} 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)
|
||||
{
|
||||
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);
|
||||
dmg->rom->data[address] = data;
|
||||
} else if (address < 0x8000) {
|
||||
// TODO switchable rom bank
|
||||
printf("warning: writing 0x%04x in rom\n", address);
|
||||
dmg->rom->data[address] = data;
|
||||
} else if (address < 0xa000) {
|
||||
dmg->video_ram[address - 0x8000] = data;
|
||||
} else if (address < 0xc000) {
|
||||
@ -144,86 +135,6 @@ void dmg_request_interrupt(struct dmg *dmg, int 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)
|
||||
{
|
||||
struct dmg *dmg = (struct dmg *) _dmg;
|
||||
@ -254,7 +165,6 @@ void dmg_step(void *_dmg)
|
||||
lcd_set_mode(dmg->lcd, 1);
|
||||
}
|
||||
|
||||
// TODO: do all of this per-scanline instead of everything in vblank
|
||||
if (next_scanline == 144) {
|
||||
// vblank has started, draw all the stuff from ram into the lcd
|
||||
dmg_request_interrupt(dmg, INT_VBLANK);
|
||||
@ -263,20 +173,41 @@ void dmg_step(void *_dmg)
|
||||
}
|
||||
|
||||
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
|
||||
if (lcdc & LCDC_ENABLE_BG) {
|
||||
render_background(dmg, lcdc);
|
||||
}
|
||||
|
||||
if (lcdc & LCDC_ENABLE_WINDOW) {
|
||||
// printf("window\n");
|
||||
}
|
||||
|
||||
lcd_apply_scroll(dmg->lcd);
|
||||
|
||||
if (lcdc & LCDC_ENABLE_OBJ) {
|
||||
render_objs(dmg);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now copy 256x256 buf to 160x144 based on window registers
|
||||
lcd_copy(dmg->lcd);
|
||||
lcd_draw(dmg->lcd);
|
||||
}
|
||||
} else {
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef _DMG_H
|
||||
#define _DMG_H
|
||||
|
||||
#include "types.h"
|
||||
#include "cpu.h"
|
||||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#define FIELD_JOY 1
|
||||
#define FIELD_ACTION 2
|
||||
@ -15,10 +17,6 @@
|
||||
#define BUTTON_SELECT (1 << 2)
|
||||
#define BUTTON_START (1 << 3)
|
||||
|
||||
struct cpu;
|
||||
struct rom;
|
||||
struct lcd;
|
||||
|
||||
struct dmg {
|
||||
struct cpu *cpu;
|
||||
struct rom *rom;
|
||||
|
16
src/lcd.c
16
src/lcd.c
@ -66,20 +66,10 @@ void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 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);
|
||||
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];
|
||||
}
|
||||
}
|
||||
// use all the registers to compute the pixel data
|
||||
|
||||
}
|
||||
|
||||
int lcd_step(struct lcd *lcd)
|
||||
|
@ -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);
|
||||
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);
|
||||
void lcd_apply_scroll(struct lcd *lcd);
|
||||
void lcd_copy(struct lcd *lcd);
|
||||
|
||||
// output the pixels to the screen
|
||||
void lcd_draw(struct lcd *lcd);
|
||||
|
94
src/mbc.c
94
src/mbc.c
@ -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);
|
||||
}
|
22
src/mbc.h
22
src/mbc.h
@ -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
|
@ -17,15 +17,12 @@ 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;
|
||||
}
|
||||
|
@ -2,12 +2,11 @@
|
||||
#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);
|
||||
|
@ -12,7 +12,6 @@ add_application(Emulator
|
||||
../src/instructions.c
|
||||
../src/lcd.c
|
||||
../src/rom.c
|
||||
../src/mbc.c
|
||||
emulator.c
|
||||
lcd_mac.c
|
||||
resources.r
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "cpu.h"
|
||||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
#include "mbc.h"
|
||||
|
||||
WindowPtr g_wp;
|
||||
DialogPtr stateDialog;
|
||||
@ -53,9 +52,8 @@ void InitEverything(void)
|
||||
g_running = 1;
|
||||
}
|
||||
|
||||
// 160 pixels / 8 bits per pixel = 20 bytes per line
|
||||
char offscreen[20 * 144];
|
||||
Rect offscreenRect = { 0, 0, 144, 160 };
|
||||
char offscreen[32 * 256];
|
||||
Rect offscreenRect = { 0, 0, 256, 256 };
|
||||
|
||||
BitMap offscreenBmp;
|
||||
|
||||
@ -63,34 +61,26 @@ int lastTicks;
|
||||
|
||||
void Render(void)
|
||||
{
|
||||
long k = 0, dst, bit;
|
||||
for (dst = 0; dst < 20 * 144; dst++) {
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
offscreen[dst] |= lcd.pixels[k++];
|
||||
offscreen[dst] <<= 1;
|
||||
}
|
||||
dst++;
|
||||
long k = 0, dst;
|
||||
for (dst = 0; dst < 32 * 256; dst++) {
|
||||
offscreen[dst] = lcd.buf[k++] << 7
|
||||
| lcd.buf[k++] << 6
|
||||
| lcd.buf[k++] << 5
|
||||
| lcd.buf[k++] << 4
|
||||
| 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);
|
||||
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &offscreenRect, srcCopy, NULL);
|
||||
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &g_wp->portRect, srcCopy, NULL);
|
||||
|
||||
//EraseRect(&g_wp->portRect);
|
||||
// MoveTo(10, 160);
|
||||
// char debug[128];
|
||||
// sprintf(debug, "PC: %04x", cpu.pc);
|
||||
// C2PStr(debug);
|
||||
// DrawString(debug);
|
||||
MoveTo(10, 160);
|
||||
char debug[128];
|
||||
sprintf(debug, "PC: %04x", cpu.pc);
|
||||
C2PStr(debug);
|
||||
DrawString(debug);
|
||||
}
|
||||
|
||||
void StartEmulation(void)
|
||||
@ -101,7 +91,7 @@ void StartEmulation(void)
|
||||
|
||||
offscreenBmp.baseAddr = offscreen;
|
||||
offscreenBmp.bounds = offscreenRect;
|
||||
offscreenBmp.rowBytes = 20;
|
||||
offscreenBmp.rowBytes = 32;
|
||||
emulationOn = 1;
|
||||
}
|
||||
|
||||
@ -131,15 +121,8 @@ bool LoadRom(StrFileName fileName, short vRefNum)
|
||||
}
|
||||
|
||||
amtRead = rom.length;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -282,25 +265,24 @@ int main(int argc, char *argv[])
|
||||
lastTicks = now;
|
||||
Render();
|
||||
}
|
||||
if (Button()) g_running = false;
|
||||
} else {
|
||||
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
|
||||
if (IsDialogEvent(&evt)) {
|
||||
DialogRef hitBox;
|
||||
DialogItemIndex hitItem;
|
||||
if (DialogSelect(&evt, &hitBox, &hitItem)) {
|
||||
stateDialog = NULL;
|
||||
}
|
||||
} else switch(evt.what) {
|
||||
case mouseDown:
|
||||
OnMouseDown(&evt);
|
||||
break;
|
||||
case updateEvt:
|
||||
BeginUpdate((WindowPtr) evt.message);
|
||||
Render();
|
||||
EndUpdate((WindowPtr) evt.message);
|
||||
break;
|
||||
}
|
||||
|
||||
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
|
||||
if (IsDialogEvent(&evt)) {
|
||||
DialogRef hitBox;
|
||||
DialogItemIndex hitItem;
|
||||
if (DialogSelect(&evt, &hitBox, &hitItem)) {
|
||||
stateDialog = NULL;
|
||||
}
|
||||
} else switch(evt.what) {
|
||||
case mouseDown:
|
||||
OnMouseDown(&evt);
|
||||
break;
|
||||
case updateEvt:
|
||||
BeginUpdate((WindowPtr) evt.message);
|
||||
Render();
|
||||
EndUpdate((WindowPtr) evt.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "types.h"
|
||||
#include "dmg.h"
|
||||
|
||||
#define WINDOW_TITLE "\pOutput"
|
||||
#define WINDOW_TITLE "\pEmulator"
|
||||
|
||||
#define WINDOW_X 100
|
||||
#define WINDOW_Y 100
|
||||
|
Loading…
Reference in New Issue
Block a user