From 49ce1631b3a45d5eee8ef47278f6485204b268b2 Mon Sep 17 00:00:00 2001 From: Koray Yanik Date: Sat, 20 Feb 2021 22:10:47 +0000 Subject: [PATCH] Implement LD ($FF00+C), A --- rtl/cpu/control.sv | 12 ++++++++++-- rtl/cpu/cpu.sv | 5 +++-- rtl/cpu/cpu_pkg.svh | 3 ++- rtl/cpu/decode.sv | 18 ++++++++++++------ rtl/gb.sv | 6 +++++- sim/tbench/tb_top.sv | 17 +++++++++++++++-- 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/rtl/cpu/control.sv b/rtl/cpu/control.sv index 3d7a370..3215ea7 100644 --- a/rtl/cpu/control.sv +++ b/rtl/cpu/control.sv @@ -35,6 +35,7 @@ module control ( ); logic nreset_r; + logic halted_r; logic state_we; state_t state_r; @@ -89,6 +90,13 @@ module control ( nreset_r <= nreset_i; end + always_ff @(posedge clk_i or negedge nreset_i) begin + if (~nreset_i) + halted_r <= 1'b0; + else if (is_undef) + halted_r <= halted_r | is_undef; + end + `DEF_FF(state_r, state_next, state_we, ST0_ADDR); `DEF_FF(pc_r, pc_next, pc_we, '0); `DEF_FF(sp_r, sp_next, sp_we, '0); @@ -97,7 +105,7 @@ module control ( `DEF_FF(operand0_r, operand0_next, operand0_we, '0); `DEF_FF(operand1_r, operand1_next, operand1_we, '0); - assign pc_we = (nreset_r & pc_incr & ~is_undef) | branch_taken; + assign pc_we = (nreset_r & ~is_undef & ~halted_r) & (pc_incr | branch_taken); assign pc_next = (branch_taken & pc_src == PC_SRC_OPERAND8) ? (pc_r + {{8{operand0_r[7]}}, operand0_r}) : (pc_r + 16'b1); @@ -115,7 +123,7 @@ module control ( assign operand1_we = (state_r == ST3_DEC); assign operand1_next = rdata_i; - assign state_we = nreset_r & ~is_undef; + assign state_we = nreset_r & ~is_undef & ~halted_r; always_comb begin case (state_r) ST0_ADDR: state_next = ST1_DEC; diff --git a/rtl/cpu/cpu.sv b/rtl/cpu/cpu.sv index bb4d783..c5c905a 100644 --- a/rtl/cpu/cpu.sv +++ b/rtl/cpu/cpu.sv @@ -120,8 +120,9 @@ module cpu ( assign reg16_wdata = (op_src == OP_SRC_OPERAND16) ? operand16 : alu_out16; assign reg16_rselect2 = reg16_wselect; - assign address_o = (adr_src == ADR_SRC_HL) ? hl : - pc; + assign address_o = (adr_src == ADR_SRC_HL) ? hl : + (adr_src == ADR_SRC_REG8) ? {8'hFF, reg8_rdata} : + pc; assign wdata_o = (op_dest == OP_DEST_MEMORY) ? alu_operand : rega; // ldi/ldd hl, a use the normal control paths for HL diff --git a/rtl/cpu/cpu_pkg.svh b/rtl/cpu/cpu_pkg.svh index 78943fb..3c18257 100644 --- a/rtl/cpu/cpu_pkg.svh +++ b/rtl/cpu/cpu_pkg.svh @@ -79,7 +79,8 @@ package cpu_pkg; typedef enum { ADR_SRC_PC, - ADR_SRC_HL + ADR_SRC_HL, + ADR_SRC_REG8 // extended with FF } adr_src_t; typedef enum { diff --git a/rtl/cpu/decode.sv b/rtl/cpu/decode.sv index 442ee5b..8563de0 100644 --- a/rtl/cpu/decode.sv +++ b/rtl/cpu/decode.sv @@ -43,6 +43,7 @@ module decode ( logic is_cb; logic is_ld_a_nn; logic is_ld_r_nn; + logic is_ldh_c_a; logic is_ld_rr_nnnn; logic is_ld_sp_nnnn; logic is_ldd_hl_a; @@ -66,20 +67,22 @@ module decode ( assign is_ld_rr_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p != 2'h3); assign is_ld_sp_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p == 2'h3); assign is_ldd_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h3); + assign is_ldh_c_a = instr0_i == 8'hE2; assign is_alu_a_r = (dec_x == 3'h2); assign is_bit_n_r = (is_cb & instr1_i[7:6] == 2'h1); assign is_jr_cc_n = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2]; - assign reg8_src = is_cb ? reg8_t'(instr1_i[2:0]) : - reg8_t'(dec_z); + assign reg8_src = is_cb ? reg8_t'(instr1_i[2:0]) : + is_ldh_c_a ? REG8_C : + reg8_t'(dec_z); assign reg8_dest = reg8_t'(dec_y); assign need_instr1_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_cb | is_jr_cc_n | is_ld_r_nn; assign need_instr2_o = is_ld_sp_nnnn | is_ld_rr_nnnn; - assign undef_o = ~(is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_r | is_ldd_hl_a | is_bit_n_r | is_jr_cc_n | is_ld_r_nn); + assign undef_o = ~(is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_r | is_ldd_hl_a | is_bit_n_r | is_jr_cc_n | is_ld_r_nn | is_ldh_c_a); assign sp_we_o = is_ld_sp_nnnn & (state_i == ST4_EXEC); @@ -91,6 +94,7 @@ module decode ( assign op_dest_o = (is_ld_r_nn & reg8_dest == REG8_PHL) ? OP_DEST_MEMORY : is_ld_a_nn ? OP_DEST_A : is_ld_r_nn ? OP_DEST_REG8 : + is_ldh_c_a ? OP_DEST_MEMORY : is_ld_rr_nnnn ? OP_DEST_REG16 : is_ldd_hl_a ? OP_DEST_REG16 : op_dest_t'('X); @@ -98,6 +102,7 @@ module decode ( assign op_src_o = (is_alu_a_r & reg8_src == REG8_A) ? OP_SRC_A : (is_alu_a_r & reg8_src != REG8_A) ? OP_SRC_REG8 : is_ld_r_nn ? OP_SRC_OPERAND8 : + is_ldh_c_a ? OP_SRC_A : is_ld_rr_nnnn ? OP_SRC_OPERAND16 : is_ldd_hl_a ? OP_SRC_REG16 : is_bit_n_r ? OP_SRC_REG8 : @@ -111,12 +116,13 @@ module decode ( assign pc_src_o = is_jr_cc_n ? PC_SRC_OPERAND8 : PC_SRC_SEQ; - assign adr_src_o = is_ldd_hl_a ? ADR_SRC_HL : - (is_ld_r_nn & reg8_dest == REG8_PHL) ? ADR_SRC_HL : + assign adr_src_o = is_ldd_hl_a ? ADR_SRC_HL : + (is_ld_r_nn & reg8_dest == REG8_PHL) ? ADR_SRC_HL : + is_ldh_c_a ? ADR_SRC_REG8 : ADR_SRC_PC; assign cc_o = cc_t'(dec_y[1:0]); - assign memory_we_o = is_ldd_hl_a | (is_ld_r_nn & reg8_dest == REG8_PHL); + assign memory_we_o = is_ldd_hl_a | is_ldh_c_a | (is_ld_r_nn & reg8_dest == REG8_PHL); endmodule : decode diff --git a/rtl/gb.sv b/rtl/gb.sv index 3b3e715..18e2e3d 100644 --- a/rtl/gb.sv +++ b/rtl/gb.sv @@ -3,14 +3,18 @@ module gb ( input logic nreset_i ); + logic we; logic [15:0] address; logic [ 7:0] rdata; + logic [ 7:0] wdata; cpu cpu_inst ( .clk_i (clk_i), .nreset_i (nreset_i), .address_o(address), - .rdata_i (rdata) + .rdata_i (rdata), + .we_o (we), + .wdata_o (wdata) ); rom #( diff --git a/sim/tbench/tb_top.sv b/sim/tbench/tb_top.sv index 27bb16a..ba4509a 100644 --- a/sim/tbench/tb_top.sv +++ b/sim/tbench/tb_top.sv @@ -15,18 +15,31 @@ module tb_top (); // Testbench code logic instr_undef; + logic halted; logic [15:0] last_pc; logic [ 7:0] last_opcode; + logic we; + logic [15:0] address; + logic [ 7:0] wdata; + + assign halted = gb_inst.cpu_inst.control_inst.halted_r; assign instr_undef = gb_inst.cpu_inst.control_inst.is_undef; assign last_pc = gb_inst.cpu_inst.control_inst.instr_pc_r; assign last_opcode = gb_inst.cpu_inst.control_inst.instr_r; + assign we = gb_inst.we; + assign address = gb_inst.address; + assign wdata = gb_inst.wdata; + always @(posedge clk) begin - if (nreset && instr_undef) begin - $info($sformatf("[%t] %X: Undefined opcode %X", $time(), last_pc, last_opcode)); + if (nreset && instr_undef & ~halted) begin + $display($sformatf("[%t] %X: Undefined opcode %X", $time(), last_pc, last_opcode)); $fatal(0); end + if (nreset && we) begin + $display($sformatf("[%t] Write: [%X] <= %X", $time(), address, wdata)); + end end endmodule : tb_top