From 06b7dfaca3808bf53a890e5202aec3ce46072416 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 25 Apr 2016 13:34:10 -0500 Subject: [PATCH] Implement CRAM, some more loads and arithmetic operations. --- src/vdp.c | 41 +++++++--- src/vdp.h | 3 + src/z80_ops.inc.c | 207 ++++++++++++++++++++++++++++++--------------------- src/z80_tables.inc.c | 52 ++++++------- 4 files changed, 184 insertions(+), 119 deletions(-) diff --git a/src/vdp.c b/src/vdp.c index d4089e0..2f6cd1d 100644 --- a/src/vdp.c +++ b/src/vdp.c @@ -17,7 +17,9 @@ void vdp_init(VDP *vdp) { vdp->vram = cr_malloc(sizeof(uint8_t) * VDP_VRAM_SIZE); + vdp->cram = cr_malloc(sizeof(uint8_t) * VDP_CRAM_SIZE); memset(vdp->vram, 0x00, VDP_VRAM_SIZE); + memset(vdp->cram, 0x00, VDP_CRAM_SIZE); } /* @@ -54,19 +56,14 @@ void vdp_power(VDP *vdp) vdp->control_flag = false; vdp->stat_int = vdp->stat_ovf = vdp->stat_col = 0; vdp->read_buf = 0; + vdp->cram_latch = 0; } /* - Simulate one scanline within the VDP. - - TODO: elaborate + Advance the V counter for the next scanline. */ -void vdp_simulate_line(VDP *vdp) +static void advance_scanline(VDP *vdp) { - if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) { - // TODO: draw current line - } - if (vdp->v_counter == 0xDA) vdp->v_count_jump = !vdp->v_count_jump; @@ -77,6 +74,19 @@ void vdp_simulate_line(VDP *vdp) } /* + Simulate one scanline within the VDP. + + TODO: elaborate +*/ +void vdp_simulate_line(VDP *vdp) +{ + if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) { + // TODO: draw current line + } + advance_scanline(vdp); +} + +/* Read a byte from the VDP's control port, revealing status flags. The status byte consists of: @@ -150,6 +160,19 @@ void vdp_write_control(VDP *vdp, uint8_t byte) } /* + Write a byte into CRAM. Handles even/odd address latching. +*/ +static void write_cram(VDP *vdp, uint8_t byte) +{ + if (!(vdp->control_addr % 2)) { + vdp->cram_latch = byte; + } else { + vdp->cram[(vdp->control_addr - 1) % 0x3F] = vdp->cram_latch; + vdp->cram[ vdp->control_addr % 0x3F] = byte % 0x0F; + } +} + +/* Write a byte into the VDP's data port. Depending on the control code, this either writes into the VRAM or CRAM at @@ -159,7 +182,7 @@ void vdp_write_control(VDP *vdp, uint8_t byte) void vdp_write_data(VDP *vdp, uint8_t byte) { if (vdp->control_code == CODE_CRAM_WRITE) - FATAL("unimplemented: VDP CRAM write @ 0x%04X", vdp->control_addr) // TODO + write_cram(vdp, byte); else vdp->vram[vdp->control_addr] = byte; diff --git a/src/vdp.h b/src/vdp.h index fd45cdc..62e01af 100644 --- a/src/vdp.h +++ b/src/vdp.h @@ -8,12 +8,14 @@ #define VDP_LINES_PER_FRAME 262 #define VDP_VRAM_SIZE (16 * 1024) +#define VDP_CRAM_SIZE (64) #define VDP_REGS 11 /* Structs */ typedef struct { uint8_t *vram; + uint8_t *cram; uint8_t regs[VDP_REGS]; uint8_t h_counter; @@ -25,6 +27,7 @@ typedef struct { bool control_flag; bool stat_int, stat_ovf, stat_col; uint8_t read_buf; + uint8_t cram_latch; } VDP; /* Functions */ diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index b3cc9f5..ee7b4d3 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -74,14 +74,9 @@ static uint8_t z80_inst_ld_r_hl(Z80 *z80, uint8_t opcode) } /* - LD r, (IX+d) + LD r, (IXY+d) */ -// static uint8_t z80_inst_ld_r_ix(Z80 *z80, uint8_t opcode) - -/* - LD r, (IY+d) -*/ -// static uint8_t z80_inst_ld_r_iy(Z80 *z80, uint8_t opcode) +// static uint8_t z80_inst_ld_r_ixy(Z80 *z80, uint8_t opcode) /* LD (HL), r (0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x77): @@ -97,14 +92,9 @@ static uint8_t z80_inst_ld_hl_r(Z80 *z80, uint8_t opcode) } /* - LD (IX+d), r -*/ -// static uint8_t z80_inst_ld_ix_r(Z80 *z80, uint8_t opcode) - -/* - LD (IY+d), r + LD (IXY+d), r */ -// static uint8_t z80_inst_ld_iy_r(Z80 *z80, uint8_t opcode) +// static uint8_t z80_inst_ld_ixy_r(Z80 *z80, uint8_t opcode) /* LD (HL), n (0x36): @@ -121,43 +111,43 @@ static uint8_t z80_inst_ld_hl_n(Z80 *z80, uint8_t opcode) } /* - LD (IX+d), n -*/ -// static uint8_t z80_inst_ld_ix_n(Z80 *z80, uint8_t opcode) - -/* - LD (IY+d), n -*/ -// static uint8_t z80_inst_ld_iy_n(Z80 *z80, uint8_t opcode) - -/* - LD A, (BC) + LD (IXY+d), n */ -// static uint8_t z80_inst_ld_a_bc(Z80 *z80, uint8_t opcode) +// static uint8_t z80_inst_ld_ixy_n(Z80 *z80, uint8_t opcode) /* - LD A, (DE) + LD A, (BC/DE) */ -// static uint8_t z80_inst_ld_a_de(Z80 *z80, uint8_t opcode) +// static uint8_t z80_inst_ld_a_bcde(Z80 *z80, uint8_t opcode) /* - LD A, (nn) + LD A, (nn) (0x3A): + Load memory at address nn into A. */ -// static uint8_t z80_inst_ld_a_nn(Z80 *z80, uint8_t opcode) - -/* - LD (BC), A -*/ -// static uint8_t z80_inst_ld_bc_a(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_a_nn(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t addr = mmu_read_double(z80->mmu, ++z80->regfile.pc); + z80->regfile.a = mmu_read_byte(z80->mmu, addr); + z80->regfile.pc += 2; + return 13; +} /* - LD (DE), A + LD (BC/DE), A (0x02, 0x12): + Load A into the memory address pointed to by BC or DE. */ -// static uint8_t z80_inst_ld_de_a(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_bcde_a(Z80 *z80, uint8_t opcode) +{ + uint16_t addr = get_pair(z80, extract_pair(opcode)); + mmu_write_byte(z80->mmu, addr, z80->regfile.a); + z80->regfile.pc++; + return 7; +} /* LD (nn), A (0x32): - Load a into memory address nn. + Load A into memory address nn. */ static uint8_t z80_inst_ld_nn_a(Z80 *z80, uint8_t opcode) { @@ -200,31 +190,34 @@ static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) return 10; } -// LD IX, nn - -// LD IY, nn +// LD IXY, nn // LD HL, (nn) // LD dd, (nn) -// LD IX, (nn) - -// LD IY, (nn) +// LD IXY, (nn) -// LD (nn), HL +/* + LD (nn), HL: (0x22): + Load HL into memory address nn. +*/ +static uint8_t z80_inst_ld_nn_hl(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t addr = mmu_read_double(z80->mmu, ++z80->regfile.pc); + mmu_write_double(z80->mmu, addr, get_pair(z80, REG_HL)); + z80->regfile.pc += 2; + return 16; +} // LD (nn), dd -// LD (nn), IX - -// LD (nn), IY +// LD (nn), IXY // LD SP, HL -// LD SP, IX - -// LD SP, IY +// LD SP, IXY /* PUSH qq (0xC5, 0xD5, 0xE5, 0xF5): @@ -303,9 +296,7 @@ static uint8_t z80_inst_exx(Z80 *z80, uint8_t opcode) // EX (SP), HL -// EX (SP), IX - -// EX (SP), IY +// EX (SP), IXY /* LDI (0xEDA0): @@ -391,9 +382,7 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) // ADD A, (HL) -// ADD A, (IX + d) - -// ADD A, (IY + d) +// ADD A, (IXY+d) // ADC A, s @@ -405,6 +394,23 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) // OR s +/* + OR r (0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB7): + Bitwise OR a with r (8-bit register). +*/ +static uint8_t z80_inst_or_r(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode << 3); + uint8_t a = (z80->regfile.a ^= *reg); + + bool parity = !(__builtin_popcount(a) % 2); + update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 4; +} + // XOR s /* @@ -413,7 +419,7 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) */ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) { - uint8_t *reg = extract_reg(z80, opcode); + uint8_t *reg = extract_reg(z80, opcode << 3); uint8_t a = (z80->regfile.a ^= *reg); bool parity = !(__builtin_popcount(a) % 2); @@ -432,7 +438,7 @@ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) */ static uint8_t z80_inst_cp_r(Z80 *z80, uint8_t opcode) { - uint8_t *reg = extract_reg(z80, opcode); + uint8_t *reg = extract_reg(z80, opcode << 3); uint8_t d = z80->regfile.a - *reg; bool c = (z80->regfile.a - *reg) != d; @@ -483,11 +489,27 @@ static uint8_t z80_inst_inc_r(Z80 *z80, uint8_t opcode) // INC (HL) -// INC (IX+d) +// INC (IXY+d) + +/* + DEC r (0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, 0x3D): + Decrement r (8-bit register). +*/ +static uint8_t z80_inst_dec_r(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode); + bool halfcarry = !!(((*reg & 0x0F) - 1) & 0x10); + (*reg)--; + update_flags(z80, 0, 1, *reg == 0x7F, !!(*reg & 0x08), halfcarry, + !!(*reg & 0x20), *reg == 0, !!(*reg & 0x80), 0xFE); + + z80->regfile.pc++; + return 4; +} -// INC (IY+d) +// DEC (HL) -// DEC m +// DEC (IXY+d) // DAA @@ -581,11 +603,30 @@ static uint8_t z80_inst_im(Z80 *z80, uint8_t opcode) // ADC HL, ss -// SBC HL, ss +/* + SBC HL, ss (0xED42, 0xED52, 0xED62, 0xED72): + Subtract BC with carry from HL. +*/ +static uint8_t z80_inst_sbc_hl_ss(Z80 *z80, uint8_t opcode) +{ + uint8_t pair = extract_pair(opcode); + uint16_t minuend = get_pair(z80, REG_HL); + uint16_t subtrahend = get_pair(z80, pair) + get_flag(z80, FLAG_CARRY); + uint16_t value = minuend - subtrahend; + set_pair(z80, REG_HL, value); -// ADD IX, pp + bool c = (minuend - subtrahend) != value; + bool ov = (minuend - subtrahend) != ((int16_t) value); // TODO: verify these + bool hc = !!(((minuend & 0x0FFF) - (subtrahend & 0x0FFF)) & 0x1000); -// ADD IY, rr + update_flags(z80, c, 1, ov, !!(value & 0x0800), hc, + !!(value & 0x2000), value == 0, !!(value & 0x8000), 0xFF); + + z80->regfile.pc++; + return 15; +} + +// ADD IXY, pp /* INC ss (0x03, 0x13, 0x23, 0x33): @@ -599,15 +640,21 @@ static uint8_t z80_inst_inc_ss(Z80 *z80, uint8_t opcode) return 6; } -// INC IX - -// INC IY - -// DEC ss +// INC IXY -// DEC IX +/* + DEC ss (0x0B, 0x1B, 0x2B, 0x3B): + Decrement ss (16-bit register). +*/ +static uint8_t z80_inst_dec_ss(Z80 *z80, uint8_t opcode) +{ + uint8_t pair = extract_pair(opcode); + set_pair(z80, pair, get_pair(z80, pair) - 1); + z80->regfile.pc++; + return 6; +} -// DEC IY +// DEC IXY // RLCA @@ -621,9 +668,7 @@ static uint8_t z80_inst_inc_ss(Z80 *z80, uint8_t opcode) // RLC (HL) -// RLC (IX+d) - -// RLC (IY+d) +// RLC (IXY+d) // RL m @@ -645,17 +690,13 @@ static uint8_t z80_inst_inc_ss(Z80 *z80, uint8_t opcode) // BIT b, (HL) -// BIT b, (IX+d) - -// BIT b, (IY+d) +// BIT b, (IXY+d) // SET b, r // SET b, (HL) -// SET b, (IX+d) - -// SET b, (IY+d) +// SET b, (IXY+d) // RES b, m @@ -714,9 +755,7 @@ static uint8_t z80_inst_jr_cc_e(Z80 *z80, uint8_t opcode) // JP (HL) -// JP (IX) - -// JP (IY) +// JP (IXY) /* DJNZ, e (0x10): diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index fa57cf6..36921bb 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -4,50 +4,50 @@ static DispatchTable instruction_table = { [0x00] = z80_inst_nop, [0x01] = z80_inst_ld_dd_nn, - [0x02] = z80_inst_unimplemented, // TODO + [0x02] = z80_inst_ld_bcde_a, [0x03] = z80_inst_inc_ss, [0x04] = z80_inst_inc_r, - [0x05] = z80_inst_unimplemented, // TODO + [0x05] = z80_inst_dec_r, [0x06] = z80_inst_ld_r_n, [0x07] = z80_inst_unimplemented, // TODO [0x08] = z80_inst_unimplemented, // TODO [0x09] = z80_inst_unimplemented, // TODO [0x0A] = z80_inst_unimplemented, // TODO - [0x0B] = z80_inst_unimplemented, // TODO + [0x0B] = z80_inst_dec_ss, [0x0C] = z80_inst_inc_r, - [0x0D] = z80_inst_unimplemented, // TODO + [0x0D] = z80_inst_dec_r, [0x0E] = z80_inst_ld_r_n, [0x0F] = z80_inst_unimplemented, // TODO [0x10] = z80_inst_djnz_e, [0x11] = z80_inst_ld_dd_nn, - [0x12] = z80_inst_unimplemented, // TODO + [0x12] = z80_inst_ld_bcde_a, [0x13] = z80_inst_inc_ss, [0x14] = z80_inst_inc_r, - [0x15] = z80_inst_unimplemented, // TODO + [0x15] = z80_inst_dec_r, [0x16] = z80_inst_ld_r_n, [0x17] = z80_inst_unimplemented, // TODO [0x18] = z80_inst_jr_e, [0x19] = z80_inst_unimplemented, // TODO [0x1A] = z80_inst_unimplemented, // TODO - [0x1B] = z80_inst_unimplemented, // TODO + [0x1B] = z80_inst_dec_ss, [0x1C] = z80_inst_inc_r, - [0x1D] = z80_inst_unimplemented, // TODO + [0x1D] = z80_inst_dec_r, [0x1E] = z80_inst_ld_r_n, [0x1F] = z80_inst_unimplemented, // TODO [0x20] = z80_inst_jr_cc_e, [0x21] = z80_inst_ld_dd_nn, - [0x22] = z80_inst_unimplemented, // TODO + [0x22] = z80_inst_ld_nn_hl, [0x23] = z80_inst_inc_ss, [0x24] = z80_inst_inc_r, - [0x25] = z80_inst_unimplemented, // TODO + [0x25] = z80_inst_dec_r, [0x26] = z80_inst_ld_r_n, [0x27] = z80_inst_unimplemented, // TODO [0x28] = z80_inst_jr_cc_e, [0x29] = z80_inst_unimplemented, // TODO [0x2A] = z80_inst_unimplemented, // TODO - [0x2B] = z80_inst_unimplemented, // TODO + [0x2B] = z80_inst_dec_ss, [0x2C] = z80_inst_inc_r, - [0x2D] = z80_inst_unimplemented, // TODO + [0x2D] = z80_inst_dec_r, [0x2E] = z80_inst_ld_r_n, [0x2F] = z80_inst_unimplemented, // TODO [0x30] = z80_inst_jr_cc_e, @@ -60,10 +60,10 @@ static DispatchTable instruction_table = { [0x37] = z80_inst_unimplemented, // TODO [0x38] = z80_inst_jr_cc_e, [0x39] = z80_inst_unimplemented, // TODO - [0x3A] = z80_inst_unimplemented, // TODO - [0x3B] = z80_inst_unimplemented, // TODO + [0x3A] = z80_inst_ld_a_nn, + [0x3B] = z80_inst_dec_ss, [0x3C] = z80_inst_inc_r, - [0x3D] = z80_inst_unimplemented, // TODO + [0x3D] = z80_inst_dec_r, [0x3E] = z80_inst_ld_r_n, [0x3F] = z80_inst_unimplemented, // TODO [0x40] = z80_inst_ld_r_r, @@ -178,14 +178,14 @@ static DispatchTable instruction_table = { [0xAD] = z80_inst_xor_r, [0xAE] = z80_inst_unimplemented, // TODO [0xAF] = z80_inst_xor_r, - [0xB0] = z80_inst_unimplemented, // TODO - [0xB1] = z80_inst_unimplemented, // TODO - [0xB2] = z80_inst_unimplemented, // TODO - [0xB3] = z80_inst_unimplemented, // TODO - [0xB4] = z80_inst_unimplemented, // TODO - [0xB5] = z80_inst_unimplemented, // TODO + [0xB0] = z80_inst_or_r, + [0xB1] = z80_inst_or_r, + [0xB2] = z80_inst_or_r, + [0xB3] = z80_inst_or_r, + [0xB4] = z80_inst_or_r, + [0xB5] = z80_inst_or_r, [0xB6] = z80_inst_unimplemented, // TODO - [0xB7] = z80_inst_unimplemented, // TODO + [0xB7] = z80_inst_or_r, [0xB8] = z80_inst_cp_r, [0xB9] = z80_inst_cp_r, [0xBA] = z80_inst_cp_r, @@ -327,7 +327,7 @@ static DispatchTable instruction_table_extended = { [0x3F] = z80_inst_nop2, [0x40] = z80_inst_in_r_c, [0x41] = z80_inst_out_c_r, - [0x42] = z80_inst_unimplemented, // TODO + [0x42] = z80_inst_sbc_hl_ss, [0x43] = z80_inst_unimplemented, // TODO [0x44] = z80_inst_unimplemented, // TODO [0x45] = z80_inst_retn, @@ -343,7 +343,7 @@ static DispatchTable instruction_table_extended = { [0x4F] = z80_inst_unimplemented, // TODO [0x50] = z80_inst_in_r_c, [0x51] = z80_inst_out_c_r, - [0x52] = z80_inst_unimplemented, // TODO + [0x52] = z80_inst_sbc_hl_ss, [0x53] = z80_inst_unimplemented, // TODO [0x54] = z80_inst_unimplemented, // TODO [0x55] = z80_inst_retn, @@ -359,7 +359,7 @@ static DispatchTable instruction_table_extended = { [0x5F] = z80_inst_unimplemented, // TODO [0x60] = z80_inst_in_r_c, [0x61] = z80_inst_out_c_r, - [0x62] = z80_inst_unimplemented, // TODO + [0x62] = z80_inst_sbc_hl_ss, [0x63] = z80_inst_unimplemented, // TODO [0x64] = z80_inst_unimplemented, // TODO [0x65] = z80_inst_retn, @@ -375,7 +375,7 @@ static DispatchTable instruction_table_extended = { [0x6F] = z80_inst_unimplemented, // TODO [0x70] = z80_inst_in_r_c, [0x71] = z80_inst_out_c_r, - [0x72] = z80_inst_unimplemented, // TODO + [0x72] = z80_inst_sbc_hl_ss, [0x73] = z80_inst_unimplemented, // TODO [0x74] = z80_inst_unimplemented, // TODO [0x75] = z80_inst_retn,