diff --git a/src/cpu.c b/src/cpu.c index 594950d..2cf6f6c 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -137,24 +137,41 @@ static void dec_with_carry(struct cpu *regs, u8 *reg) set_flag(regs, FLAG_ZERO); } -static void rotate_left(struct cpu *regs, u8 *reg) +static u8 rotate_left(struct cpu *regs, u8 reg) { // copy old leftmost bit to carry flag - regs->f = (*reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY); + regs->f = (reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY); // rotate - *reg <<= 1; + int result = reg << 1; // restore leftmost (now rightmost) bit - *reg |= (regs->f & FLAG_CARRY) >> 4; + result |= (regs->f & FLAG_CARRY) >> 4; + return result; } -static void rotate_right(struct cpu *regs, u8 *reg) +static u8 rotate_right(struct cpu *regs, u8 reg) { // copy old rightmost bit to carry flag - regs->f = (*reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY); + regs->f = (reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY); // rotate - *reg >>= 1; + int result = reg >> 1; // restore rightmost bit to left - *reg |= (regs->f & FLAG_CARRY) << 3; + result |= (regs->f & FLAG_CARRY) << 3; + return result; +} + +static u8 shift_left(struct cpu *cpu, u8 value) +{ + return 0; +} + +static u8 shift_right(struct cpu *cpu, u8 value) +{ + return 0; +} + +static u8 swap(struct cpu *cpu, u8 value) +{ + return ((value & 0xf0) >> 4) | ((value & 0x0f) << 4); } static void xor(struct cpu *regs, u8 value) @@ -223,15 +240,21 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare static void push(struct cpu *cpu, u16 value) { - write16(cpu, cpu->sp - 2, value & 0xff); - write16(cpu, cpu->sp - 1, value >> 8); + printf("sp=%04x\n", cpu->sp); + printf("memory[sp-2] = %02x\n", value & 0xff); + printf("memory[sp-1] = %02x\n", value >> 8); + write8(cpu, cpu->sp - 2, value & 0xff); + write8(cpu, cpu->sp - 1, value >> 8); cpu->sp -= 2; } static u16 pop(struct cpu *cpu) { cpu->sp += 2; - return read16(cpu, cpu->sp - 1) << 8 | read16(cpu, cpu->sp - 2); + printf("sp=%04x\n", cpu->sp); + printf("read memory[sp-2] = %02x\n", read8(cpu, cpu->sp - 2)); + printf("read memory[sp-1] = %02x\n", read8(cpu, cpu->sp - 1)); + return read8(cpu, cpu->sp - 1) << 8 | read8(cpu, cpu->sp - 2); } static void add16(struct cpu *cpu, u16 src) @@ -290,8 +313,20 @@ static void extended_insn(struct cpu *cpu, u8 insn) int bit = (insn >> 3) & 0x7; int reg = insn & 0x7; + u8 (*funcs[8])(struct cpu *, u8) = { + rotate_left, + rotate_right, + rotate_left, // TODO non-carry version + rotate_right, + shift_left, + shift_right, + swap, + shift_right // TODO SRL + }; + switch (op) { case 0: + write_reg(cpu, reg, funcs[bit](cpu, read_reg(cpu, reg))); break; case 1: // BIT temp = read_reg(cpu, reg); @@ -332,7 +367,7 @@ void cpu_step(struct cpu *cpu) cpu->pc += 2; break; case 0x07: // RLCA - rotate_left(cpu, &cpu->a); + cpu->a = rotate_left(cpu, cpu->a); break; case 0x08: // LD (a16),SP write16(cpu, read16(cpu, cpu->pc), cpu->sp); @@ -341,8 +376,11 @@ void cpu_step(struct cpu *cpu) case 0x19: // ADD HL,DE add16(cpu, read_de(cpu)); break; + case 0x17: // RLA + cpu->a = rotate_left(cpu, cpu->a); + break; case 0x1f: // RRA - rotate_right(cpu, &cpu->a); + cpu->a = rotate_right(cpu, cpu->a); break; // incs and decs @@ -481,7 +519,7 @@ void cpu_step(struct cpu *cpu) case 0x20: // JR NZ,r8 temp = read8(cpu, cpu->pc); if (!flag_isset(cpu, FLAG_ZERO)) { - cpu->pc += *((signed char *) &temp); + cpu->pc += *((signed char *) &temp) + 1; } else { cpu->pc++; } @@ -500,6 +538,10 @@ void cpu_step(struct cpu *cpu) cpu->sp = read16(cpu, cpu->pc); cpu->pc += 2; break; + case 0x22: // LD (HL+), A + write8(cpu, read_hl(cpu), cpu->a); + write_hl(cpu, read_hl(cpu) + 1); + break; case 0x32: // LD (HL-), A write8(cpu, read_hl(cpu), cpu->a); write_hl(cpu, read_hl(cpu) - 1); @@ -613,6 +655,12 @@ void cpu_step(struct cpu *cpu) case 0xf7: push(cpu, cpu->pc); cpu->pc = 0x30; break; case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break; + case 0xc1: // POP BC + write_bc(cpu, pop(cpu)); + break; + case 0xc5: // PUSH BC + push(cpu, read_bc(cpu)); + break; case 0xcb: extended_insn(cpu, read8(cpu, cpu->pc)); cpu->pc++; @@ -626,7 +674,7 @@ void cpu_step(struct cpu *cpu) cpu->pc++; break; case 0xe2: // LD (C),A - write8(cpu, cpu->c, cpu->a); + write8(cpu, 0xff00 + cpu->c, cpu->a); break; case 0xea: // LD (a16),A write16(cpu, read16(cpu, cpu->pc), cpu->a); @@ -641,6 +689,9 @@ void cpu_step(struct cpu *cpu) } cpu->pc++; break; + case 0xf2: // LD A,(C) + cpu->a = read8(cpu, 0xff00 + cpu->c); + break; case 0xf3: // DI break; case 0xfb: // EI diff --git a/src/dmg.c b/src/dmg.c index ca4f5ad..f6468e6 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -15,6 +15,9 @@ void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom) u8 dmg_read(void *_dmg, u16 address) { struct dmg *dmg = (struct dmg *) _dmg; + if (address < 0x100) { + return dmg_boot_rom[address]; + } if (address < 0x4000) { return dmg->rom->data[address]; } else if (address < 0x8000) { @@ -27,6 +30,8 @@ u8 dmg_read(void *_dmg, u16 address) return 0; } else if (address < 0xe000) { return dmg->main_ram[address - 0xc000]; + } else if (address >= 0xff80 && address <= 0xfffe) { + return dmg->zero_page[address - 0xff80]; } else { // not sure about any of this yet return 0; @@ -49,6 +54,8 @@ void dmg_write(void *_dmg, u16 address, u8 data) // TODO switchable ram bank } else if (address < 0xe000) { dmg->main_ram[address - 0xc000] = data; + } else if (address >= 0xff80 && address <= 0xfffe) { + dmg->zero_page[address - 0xff80] = data; } else { // not sure about any of this yet } diff --git a/src/dmg.h b/src/dmg.h index 2070a48..da5a765 100644 --- a/src/dmg.h +++ b/src/dmg.h @@ -7,8 +7,10 @@ struct dmg { struct cpu *cpu; struct rom *rom; + struct lcd *lcd; u8 main_ram[0x2000]; u8 video_ram[0x2000]; + u8 zero_page[0x80]; }; void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom); diff --git a/src/lcd.c b/src/lcd.c new file mode 100644 index 0000000..f0774ec --- /dev/null +++ b/src/lcd.c @@ -0,0 +1,13 @@ +#include + +#include "types.h" +#include "lcd.h" + +void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value) +{ + if (x >= LCD_WIDTH || y >= LCD_HEIGHT) { + printf("warning: trying to write to (%d, %d) outside of lcd bounds\n", x, y); + return; + } + lcd->pixels[y * LCD_WIDTH + x] = value; +} \ No newline at end of file diff --git a/src/lcd.h b/src/lcd.h new file mode 100644 index 0000000..c0a228e --- /dev/null +++ b/src/lcd.h @@ -0,0 +1,15 @@ +#ifndef _LCD_H +#define _LCD_H + +#include "types.h" + +#define LCD_WIDTH 160 +#define LCD_HEIGHT 144 + +struct lcd { + u8 *pixels; +}; + +void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index 997bb6a..d608f2b 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,7 @@ int main(int argc, char *argv[]) struct cpu cpu; struct rom rom; struct dmg dmg; + int executed = 0; if (argc < 2) { printf("no rom specified\n"); @@ -26,9 +27,9 @@ int main(int argc, char *argv[]) dmg_new(&dmg, &cpu, &rom); cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write); - cpu.pc = 0x100; + cpu.pc = 0; - while (1) { + for (; executed < 100000; executed++) { cpu_step(&cpu); }