diff --git a/build/tb_top.Makefile b/build/tb_top.Makefile index 325ea7c..e14f81b 100644 --- a/build/tb_top.Makefile +++ b/build/tb_top.Makefile @@ -2,8 +2,10 @@ TB = tb_top SOURCES = gb.sv cpu.sv alu.sv registers.sv control.sv decode.sv rom.sv tb_top.sv clkgen.sv PATH_SRC = ../rtl:../rtl/cpu:../rtl/shared:../sim/tbench:../sim/shared -gb.sdb: cpu.sdb rom.sdb -cpu.sdb: control.sdb registers.sdb alu.sdb -control.sdb: decode.sdb +gb.sdb: cpu.sdb rom.sdb cpu_pkg.sdb +cpu.sdb: control.sdb registers.sdb alu.sdb cpu_pkg.sdb +control.sdb: decode.sdb cpu_pkg.sdb +alu.sdb: cpu_pkg.sdb +registers.sdb: cpu_pkg.sdb include ../synthflow/vivado/Makefile.rules \ No newline at end of file diff --git a/rtl/cpu/alu.sv b/rtl/cpu/alu.sv index 18901a4..987b2a4 100644 --- a/rtl/cpu/alu.sv +++ b/rtl/cpu/alu.sv @@ -25,15 +25,6 @@ module alu ( logic [ 7:0] a_xor; logic [ 7:0] f_xor; - `define DEF_FF(register, next, we, rst_value) \ - always_ff @(posedge clk_i or negedge nreset_i) begin \ - if (~nreset_i) begin \ - register <= (rst_value); \ - end else if ((we)) begin \ - register <= (next); \ - end \ - end - `DEF_FF(a_r, a_next, a_we, '0); `DEF_FF(f_r, f_next, f_we, '0); diff --git a/rtl/cpu/control.sv b/rtl/cpu/control.sv index 59f9189..19bf593 100644 --- a/rtl/cpu/control.sv +++ b/rtl/cpu/control.sv @@ -21,7 +21,10 @@ module control ( output logic alu_op_valid_o, output alu_op_t alu_op_o, output op_src_t op_src_o, - output op_dest_t op_dest_o + output op_dest_t op_dest_o, + output reg16_t reg16_dest_o, + + output adr_src_t adr_src_o ); logic nreset_r; @@ -61,6 +64,7 @@ module control ( logic decoder_need_instr1; logic decoder_need_instr2; logic decoder_is_undef; + adr_src_t decoder_adr_src; logic is_undef; logic pc_incr; @@ -68,15 +72,6 @@ module control ( sp_src_t sp_src; - `define DEF_FF(register, next, we, rst_value) \ - always_ff @(posedge clk_i or negedge nreset_i) begin \ - if (~nreset_i) begin \ - register <= (rst_value); \ - end else if ((we)) begin \ - register <= (next); \ - end \ - end - always_ff @(posedge clk_i) begin nreset_r <= nreset_i; end @@ -135,9 +130,10 @@ module control ( .alu_op_valid_o(alu_op_valid_o), .alu_op_o (alu_op_o), .op_src_o (op_src_o), - .op_dest_o (op_dest_o) - + .op_dest_o (op_dest_o), + .reg16_dest_o (reg16_dest_o), + .adr_src_o (decoder_adr_src) ); assign decoder_instr0_selected = (state_r == ST1_DEC) ? rdata_i : instr_r; @@ -145,7 +141,7 @@ module control ( assign decoder_instr2_selected = (state_r == ST3_DEC) ? rdata_i : operand1_r; assign is_undef = (state_r != ST0_ADDR & decoder_is_undef); - assign instr_valid = (state_r == ST4_EXEC); + assign instr_valid = (state_r == ST2_EXEC | state_r == ST4_EXEC); assign pc_incr = (state_r == ST0_ADDR) | (state_r == ST1_DEC & decoder_need_instr1) | (state_r == ST2_DEC & decoder_need_instr2); @@ -159,4 +155,7 @@ module control ( assign operand8_o = operand0_r; assign operand16_o = {operand1_r, operand0_r}; + assign adr_src_o = (state_r == ST2_EXEC) | (state_r == ST4_EXEC) ? decoder_adr_src : + ADR_SRC_PC; + endmodule : control diff --git a/rtl/cpu/cpu.sv b/rtl/cpu/cpu.sv index fdcc0e8..2d04d02 100644 --- a/rtl/cpu/cpu.sv +++ b/rtl/cpu/cpu.sv @@ -25,6 +25,23 @@ module cpu ( logic [15:0] pc; logic [15:0] sp; + logic instr_valid; + logic instr_undef; + + logic [ 7:0] operand8; + logic [15:0] operand16; + + reg8_t reg8_wselect; + logic reg8_we; + logic [ 7:0] reg8_wdata; + reg16_t reg16_wselect; + logic reg16_we; + logic [15:0] reg16_wdata; + reg8_t reg8_rselect; + reg16_t reg16_rselect; + logic [ 7:0] reg8_rdata; + logic [15:0] reg16_rdata; + control control_inst ( .clk_i (clk_i), .nreset_i (nreset_i), @@ -35,7 +52,12 @@ module cpu ( .alu_op_valid_o(alu_op_valid), .alu_op_o (alu_op), .op_src_o (op_src), - .op_dest_o (op_dest) + .op_dest_o (op_dest), + .instr_valid_o (instr_valid), + .instr_undef_o (instr_undef), + .operand8_o (operand8), + .operand16_o (operand16), + .reg16_dest_o (reg16_wselect) ); alu alu_inst ( @@ -50,12 +72,31 @@ module cpu ( registers registers_inst ( .clk_i (clk_i), - .nreset_i(nreset_i) + .nreset_i(nreset_i), + + .reg8_wselect_i (reg8_wselect), + .reg8_we_i (reg8_we), + .reg8_wdata_i (reg8_wdata), + .reg16_wselect_i(reg16_wselect), + .reg16_we_i (reg16_we), + .reg16_wdata_i (reg16_wdata), + .reg8_rselect_i (reg8_rselect), + .reg8_rdata_o (reg8_rdata), + .reg16_rselect_i(reg16_rselect), + .reg16_rdata_o (reg16_rdata) ); assign alu_operand = (op_src == OP_SRC_A) ? rega : '0; + assign reg8_wselect = reg8_t'('X); + assign reg8_we = '0; + assign reg8_wdata = operand8; + assign reg16_we = instr_valid & (op_dest == OP_DEST_R16); + assign reg16_wdata = operand16; + assign reg8_rselect = reg8_t'('X); + assign reg16_rselect = reg16_t'('X); + assign address_o = pc; endmodule : cpu diff --git a/rtl/cpu/cpu_pkg.svh b/rtl/cpu/cpu_pkg.svh index db29164..76050fd 100644 --- a/rtl/cpu/cpu_pkg.svh +++ b/rtl/cpu/cpu_pkg.svh @@ -22,6 +22,13 @@ package cpu_pkg; REG8_L = 3'h05 } reg8_t; + typedef enum logic [1:0] { + REG16_BC = 2'h00, + REG16_DE = 2'h01, + REG16_HL = 2'h02, + REG16_SP_AF = 2'h03 + } reg16_t; + typedef enum logic [2:0] { ALU_OP_ADD = 3'h00, ALU_OP_ADC = 3'h01, @@ -35,15 +42,31 @@ package cpu_pkg; typedef enum { OP_SRC_A, - OP_SRC_REG8 + OP_SRC_REG8, + OP_SRC_OPERAND16 } op_src_t; typedef enum { - OP_DEST_A + OP_DEST_A, + OP_DEST_R16 } op_dest_t; typedef enum { SP_SRC_OPERAND16 } sp_src_t; + typedef enum { + ADR_SRC_PC, + ADR_SRC_HL + } adr_src_t; + endpackage + +`define DEF_FF(register, next, we, rst_value) \ + always_ff @(posedge clk_i or negedge nreset_i) begin \ + if (~nreset_i) begin \ + register <= (rst_value); \ + end else if ((we)) begin \ + register <= (next); \ + end \ + end diff --git a/rtl/cpu/decode.sv b/rtl/cpu/decode.sv index ead796b..5c37cf1 100644 --- a/rtl/cpu/decode.sv +++ b/rtl/cpu/decode.sv @@ -19,7 +19,11 @@ module decode ( output logic alu_op_valid_o, output alu_op_t alu_op_o, output op_src_t op_src_o, - output op_dest_t op_dest_o + output op_dest_t op_dest_o, + + output reg16_t reg16_dest_o, + + output adr_src_t adr_src_o ); logic [1:0] dec_x; @@ -38,21 +42,30 @@ module decode ( assign dec_p = instr0_i[5:4]; assign dec_q = instr0_i[3]; - assign is_ld_rr_nnnn = (dec_z == 3'h1) & ~dec_q & (dec_p != 2'h3); - assign is_ld_sp_nnnn = (dec_z == 3'h1) & ~dec_q & (dec_p == 2'h3); + 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_alu_a_n = (dec_x == 3'h2); assign need_instr1_o = is_ld_sp_nnnn; assign need_instr2_o = is_ld_sp_nnnn; - assign undef_o = ~(is_ld_sp_nnnn | is_alu_a_n); + assign undef_o = ~(is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_n); assign sp_we_o = is_ld_sp_nnnn & (state_i == ST4_EXEC); assign alu_op_valid_o = is_alu_a_n; assign alu_op_o = alu_op_t'(dec_y); - assign op_dest_o = is_alu_a_n ? OP_DEST_A : op_dest_t'('X); - assign op_src_o = is_alu_a_n ? OP_SRC_REG8 : op_src_t'('X); + assign op_dest_o = is_alu_a_n ? OP_DEST_A : + is_ld_rr_nnnn ? OP_DEST_R16 : + op_dest_t'('X); + + assign op_src_o = is_alu_a_n ? OP_SRC_REG8 : + is_ld_rr_nnnn ? OP_SRC_OPERAND16 : + op_src_t'('X); + + assign reg16_dest_o = reg16_t'(dec_p); + + assign adr_src_o = ADR_SRC_PC; endmodule : decode \ No newline at end of file diff --git a/rtl/cpu/registers.sv b/rtl/cpu/registers.sv index cd72197..53cf6e8 100644 --- a/rtl/cpu/registers.sv +++ b/rtl/cpu/registers.sv @@ -1,6 +1,49 @@ +`include "cpu_pkg.svh" + +import cpu_pkg::*; + module registers ( input logic clk_i, - input logic nreset_i + input logic nreset_i, + + input reg8_t reg8_wselect_i, + input logic reg8_we_i, + input logic [ 7:0] reg8_wdata_i, + + input reg16_t reg16_wselect_i, + input logic reg16_we_i, + input logic [15:0] reg16_wdata_i, + + input reg8_t reg8_rselect_i, + input reg16_t reg16_rselect_i, + output logic [ 7:0] reg8_rdata_o, + output logic [15:0] reg16_rdata_o ); + logic [15:0] reg_r [0:2]; + logic [15:0] reg_next; + logic [ 1:0] reg_we [0:2]; + + generate for (genvar i = 0; i <= 2; i++) begin : gen_regs + always_ff @(posedge clk_i or negedge nreset_i) begin + if (~nreset_i) begin + reg_r[i] <= '0; + end else if (|reg_we[i]) begin + reg_r[i]<= reg_next; + end + end + + assign reg_we[i][0] = (reg16_we_i & (reg16_wselect_i == i)) | + (reg8_we_i & ({reg8_wselect_i, 1'b0} == i)); + assign reg_we[i][1] = (reg16_we_i & (reg16_wselect_i == i)) | + (reg8_we_i & ({reg8_wselect_i, 1'b1} == i)); + end endgenerate + + assign reg_next = ({16{reg8_we_i}} & {reg8_wdata_i, reg8_wdata_i}) | + ({16{reg16_we_i}} & reg16_wdata_i); + + assign reg8_rdata_o = reg8_rselect_i[0] ? reg_r[reg8_rselect_i[2:1]][15:8] : + reg_r[reg8_rselect_i[2:1]][ 7:0]; + assign reg16_rdata_o = reg_r[reg16_rselect_i]; + endmodule : registers diff --git a/sim/tbench/tb_top.sv b/sim/tbench/tb_top.sv index 3451729..27bb16a 100644 --- a/sim/tbench/tb_top.sv +++ b/sim/tbench/tb_top.sv @@ -13,5 +13,20 @@ module tb_top (); .nreset_i(nreset) ); + // Testbench code + logic instr_undef; + logic [15:0] last_pc; + logic [ 7:0] last_opcode; + + 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; + + always @(posedge clk) begin + if (nreset && instr_undef) begin + $info($sformatf("[%t] %X: Undefined opcode %X", $time(), last_pc, last_opcode)); + $fatal(0); + end + end endmodule : tb_top