Parcourir la source

Implement CRAM, some more loads and arithmetic operations.

master
Ben Kurtovic il y a 8 ans
Parent
révision
06b7dfaca3
4 fichiers modifiés avec 184 ajouts et 119 suppressions
  1. +32
    -9
      src/vdp.c
  2. +3
    -0
      src/vdp.h
  3. +123
    -84
      src/z80_ops.inc.c
  4. +26
    -26
      src/z80_tables.inc.c

+ 32
- 9
src/vdp.c Voir le fichier

@@ -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;



+ 3
- 0
src/vdp.h Voir le fichier

@@ -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 */


+ 123
- 84
src/z80_ops.inc.c Voir le fichier

@@ -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):


+ 26
- 26
src/z80_tables.inc.c Voir le fichier

@@ -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,


Chargement…
Annuler
Enregistrer