From fda176d3b533aa9839b8a406b5d1fdd97d290981 Mon Sep 17 00:00:00 2001 From: Koray Yanik Date: Sun, 1 Oct 2023 23:00:56 +0100 Subject: [PATCH] Complete rewrite from scratch, bootstrap WIP Rewrite to use several bus multiplexers, resulting into a less messy microarchitecture (hopefully). Some more room for cleanup though... Supports every instruction from the bootstrap rom, more or less. LY hacked at 0x90 to progress through vsync instantly. No cartridge is present yet, so we will always fail checksum test and lock up. --- .gitignore | 1 + build/tb_top.Makefile | 9 +- rtl/cpu/alu.sv | 212 ++++++++++----- rtl/cpu/alu16.sv | 21 ++ rtl/cpu/control.sv | 222 ---------------- rtl/cpu/cpu.sv | 384 ++++++++++++++++++--------- rtl/cpu/cpu_pkg.svh | 242 +++++++++-------- rtl/cpu/ctrl.sv | 180 +++++++++++++ rtl/cpu/decode.sv | 233 ---------------- rtl/cpu/idec.sv | 347 ++++++++++++++++++++++++ rtl/cpu/{registers.sv => regbank.sv} | 43 ++- rtl/gb.sv | 137 +++++++--- rtl/ppu.sv | 30 +++ rtl/ram.sv | 28 ++ rtl/rom.sv | 26 ++ rtl/shared/ram.sv | 34 --- rtl/shared/rom.sv | 29 -- rtl/sva_common.svh | 39 +++ sim/clkgen.sv | 18 ++ sim/shared/clkgen.sv | 18 -- sim/tb_top.sv | 76 ++++++ sim/tbench/tb_top.sv | 50 ---- synthflow | 2 +- 23 files changed, 1425 insertions(+), 956 deletions(-) create mode 100644 rtl/cpu/alu16.sv delete mode 100644 rtl/cpu/control.sv create mode 100644 rtl/cpu/ctrl.sv delete mode 100644 rtl/cpu/decode.sv create mode 100644 rtl/cpu/idec.sv rename rtl/cpu/{registers.sv => regbank.sv} (68%) create mode 100644 rtl/ppu.sv create mode 100644 rtl/ram.sv create mode 100644 rtl/rom.sv delete mode 100644 rtl/shared/ram.sv delete mode 100644 rtl/shared/rom.sv create mode 100644 rtl/sva_common.svh create mode 100644 sim/clkgen.sv delete mode 100644 sim/shared/clkgen.sv create mode 100644 sim/tb_top.sv delete mode 100644 sim/tbench/tb_top.sv diff --git a/.gitignore b/.gitignore index 548bd9e..85c55a8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/.Xil build/xsim.dir build/*.wcfg build/vivado_* +build/vivado.* diff --git a/build/tb_top.Makefile b/build/tb_top.Makefile index b7290f0..77c6487 100644 --- a/build/tb_top.Makefile +++ b/build/tb_top.Makefile @@ -1,7 +1,8 @@ TB = tb_top -SOURCES = gb.sv cpu.sv alu.sv registers.sv control.sv decode.sv rom.sv ram.sv tb_top.sv clkgen.sv -INCLUDES = cpu_pkg.svh -PATH_SRC = ../rtl:../rtl/cpu:../rtl/shared:../sim/tbench:../sim/shared +SOURCES = gb.sv cpu.sv ppu.sv idec.sv ctrl.sv alu.sv alu16.sv regbank.sv rom.sv ram.sv tb_top.sv clkgen.sv +INCLUDES = cpu_pkg.svh sva_common.svh +PATH_SRC = ../rtl:../rtl/cpu:../sim + +DEFINES = SVA_ENABLE include ../synthflow/vivado/Makefile.rules - diff --git a/rtl/cpu/alu.sv b/rtl/cpu/alu.sv index 1793bf7..e7bbd99 100644 --- a/rtl/cpu/alu.sv +++ b/rtl/cpu/alu.sv @@ -3,95 +3,167 @@ import cpu_pkg::*; module alu ( - input logic clk_i, - input logic nreset_i, + input logic clk, + input logic nreset, - input logic alu_op_valid_i, - input alu_op_t alu_op_i, - input logic [7:0] operand_i, - input logic [2:0] inx8_i, // Only used for bit/set/res + input alu_ctrl_t alu_ctrl_i, - input logic rot_op_valid_i, - input rot_op_t rot_op_i, + input logic [ 7:0] operand_in_i, + output logic [ 7:0] operand_out_o, - input alu16_op_t alu16_op_i, - input logic [15:0] inx16_i, - input logic [15:0] iny16_i, - - output logic [ 7:0] a_o, - output logic [ 7:0] f_o, - - output logic [ 7:0] out8_o, // Only used for inc/dec reg8 and rot - output logic [15:0] out16_o + output logic [ 7:0] reg_a_o, + output logic [ 7:0] reg_f_o ); - logic a_we; - logic [ 7:0] a_r; - logic [ 7:0] a_next; - logic f_we; - logic [ 7:0] f_r; - logic [ 7:0] f_next; +logic nop_valid; +logic a_we; +logic [ 7:0] a_r; +logic [ 7:0] a_next; - logic [ 7:0] a_inc; - logic [ 7:0] f_inc; +logic f_we; +logic [ 7:0] f_r; +logic [ 7:0] f_next; - logic [ 7:0] a_xor; - logic [ 7:0] f_xor; +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + a_r <= '0; + else if (a_we) + a_r <= a_next; +end - logic [ 7:0] a_bit; // Never written, only to test - logic [ 7:0] f_bit; +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + f_r <= '0; + else if (f_we) + f_r <= f_next; +end + +assign a_we = alu_ctrl_i.update_a; +assign f_we = alu_ctrl_i.update_f; + +assign reg_a_o = a_r; +assign reg_f_o = f_r; + +logic [ 7:0] alu_a; +logic [ 7:0] alu_f; + +logic [ 7:0] shift_a; +logic [ 7:0] shift_f; + +logic [ 7:0] bsr_a; +logic [ 7:0] bsr_f; + +logic [ 7:0] incdec_a; +logic [ 7:0] incdec_f; + +assign nop_valid = ~alu_ctrl_i.alu_op_valid & + ~alu_ctrl_i.shift_op_valid & + ~alu_ctrl_i.bsr_op_valid & + ~alu_ctrl_i.incdec_op_valid; + +assign a_next = ({8{alu_ctrl_i.alu_op_valid }} & alu_a) | + ({8{alu_ctrl_i.shift_op_valid }} & shift_a) | + ({8{alu_ctrl_i.bsr_op_valid }} & bsr_a) | + ({8{alu_ctrl_i.incdec_op_valid}} & incdec_a) | + ({8{nop_valid }} & operand_in_i); + +assign f_next = ({8{alu_ctrl_i.alu_op_valid }} & alu_f) | + ({8{alu_ctrl_i.shift_op_valid }} & shift_f) | + ({8{alu_ctrl_i.bsr_op_valid }} & bsr_f) | + ({8{alu_ctrl_i.incdec_op_valid}} & incdec_f) | + ({8{nop_valid }} & operand_in_i); + +logic [ 8:0] add_a; +logic [ 7:0] add_f; +logic [ 8:0] sub_a; +logic [ 7:0] sub_f; +logic [ 7:0] xor_a; +logic [ 7:0] xor_f; +logic [ 7:0] cp_a; +logic [ 7:0] cp_f; + +assign alu_a = ({8{alu_ctrl_i.alu_op == ALU_OP_ADD}} & add_a) | + ({8{alu_ctrl_i.alu_op == ALU_OP_SUB}} & sub_a) | + ({8{alu_ctrl_i.alu_op == ALU_OP_XOR}} & xor_a) | + ({8{alu_ctrl_i.alu_op == ALU_OP_CP }} & cp_a); +assign alu_f = ({8{alu_ctrl_i.alu_op == ALU_OP_ADD}} & add_f) | + ({8{alu_ctrl_i.alu_op == ALU_OP_SUB}} & sub_f) | + ({8{alu_ctrl_i.alu_op == ALU_OP_XOR}} & xor_f) | + ({8{alu_ctrl_i.alu_op == ALU_OP_CP }} & cp_f); + +assign add_a = {1'b0, a_r} + {1'b0, operand_in_i}; +assign add_f = {~(|sub_a[7:0]), 1'b0, 1'b0, sub_a[8], f_r[3:0]}; // TODO: implement H + +assign sub_a = {1'b0, a_r} - {1'b0, operand_in_i}; +assign sub_f = {~(|sub_a[7:0]), 1'b1, 1'b0, sub_a[8], f_r[3:0]}; // TODO: implement H + +assign xor_a = a_r ^ operand_in_i; +assign xor_f = {~(|xor_a), 3'b0, f_r[3:0]}; + +assign cp_a = a_r; +assign cp_f = sub_f; + +logic [ 7:0] bit_a; +logic [ 7:0] bit_f; + +assign bsr_a = ({8{alu_ctrl_i.bsr_op.b}} & bit_a); +assign bsr_f = ({8{alu_ctrl_i.bsr_op.b}} & bit_f); + +assign bit_a = {7'b0, ~operand_in_i[alu_ctrl_i.bsr_op.operand]}; +assign bit_f = {bit_a[0], 2'b10, f_r[4:0]}; + +logic [ 7:0] rl_a; +logic [ 7:0] rl_f; + +assign shift_a = ({8{alu_ctrl_i.shift_op == SHIFT_OP_RL}} & rl_a); +assign shift_f = ({8{alu_ctrl_i.shift_op == SHIFT_OP_RL}} & rl_f); + +assign rl_a = {operand_in_i[6:0], f_r[4]}; +assign rl_f = {~(|rl_a), 2'b0, operand_in_i[7], f_r[3:0]}; - logic [ 7:0] out8_incr; - logic [ 7:0] f_incr; +logic [ 7:0] incdec_input; +logic [ 7:0] inc_a; +logic [ 7:0] inc_f; +logic [ 7:0] dec_a; +logic [ 7:0] dec_f; - logic [ 7:0] out8_rl; - logic [ 7:0] f_rl; +assign incdec_input = alu_ctrl_i.incdec_op.dst_a ? a_r : + operand_in_i; - logic [15:0] out16_inc; - logic [15:0] out16_dec; +assign incdec_a = ({8{alu_ctrl_i.incdec_op.inc}} & inc_a) | + ({8{alu_ctrl_i.incdec_op.dec}} & dec_a); - `DEF_FF(a_r, a_next, a_we, '0); - `DEF_FF(f_r, f_next, f_we, '0); +assign incdec_f = ({8{alu_ctrl_i.incdec_op.inc}} & inc_f) | + ({8{alu_ctrl_i.incdec_op.dec}} & dec_f); - assign a_we = alu_op_valid_i; - assign a_next = (alu_op_valid_i & (alu_op_i == ALU_OP_XOR)) ? a_xor : - (alu_op_valid_i & (alu_op_i == ALU_OP_NOP)) ? operand_i : - (alu_op_valid_i & (alu_op_i == ALU_OP_INC)) ? a_inc : - (alu_op_valid_i & (alu_op_i == ALU_OP_ROT) & (rot_op_i == ROT_OP_RL)) ? out8_rl : - a_r; +assign inc_a = incdec_input + 8'h01; +assign inc_f = {~(|inc_a), 1'b0, inc_a[4], f_r[4], f_r[3:0]}; - assign f_we = alu_op_valid_i | rot_op_valid_i; - assign f_next = (alu_op_valid_i & (alu_op_i == ALU_OP_XOR)) ? f_xor : - (alu_op_valid_i & (alu_op_i == ALU_OP_BIT)) ? f_bit : - (alu_op_valid_i & (alu_op_i == ALU_OP_INC)) ? f_inc : - (alu_op_valid_i & (alu_op_i == ALU_OP_INCR)) ? f_incr : - (rot_op_valid_i & (rot_op_i == ROT_OP_RL)) ? f_rl : - f_r; +assign dec_a = incdec_input - 8'h01; +assign dec_f = {~(|dec_a), 1'b1, dec_a[4], f_r[4], f_r[3:0]}; - assign a_xor = (a_r ^ operand_i); - assign f_xor = {~(|a_xor), 3'b0, f_r[3:0]}; +assign operand_out_o = ({8{alu_ctrl_i.shift_op_valid }} & shift_a) | + ({8{alu_ctrl_i.incdec_op_valid}} & incdec_a); - assign a_inc = (a_r + 8'h01); - assign f_inc = {~(|a_inc), 1'b0, a_inc[4], f_r[3:0]}; +`include "sva_common.svh" +`SVA_DEF_CLK(clk); +`SVA_DEF_NRESET(nreset); - assign a_bit = (operand_i - {4'b0, inx8_i}); - assign f_bit = {~(|a_bit), 2'b10, f_r[4:0]}; +`SVA_ASSERT_PROP_FATAL(undefined_alu_op, + tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.alu_op_valid |-> alu_ctrl_i.alu_op inside {ALU_OP_ADD, ALU_OP_SUB, ALU_OP_XOR, ALU_OP_CP}, + $sformatf("Undefined alu operation pushed: 0x%X", alu_ctrl_i.alu_op) +); - assign out8_rl = {operand_i[6:0], f_r[4]}; - assign f_rl = {~(|out8_rl), 2'b0, operand_i[7], f_r[3:0]}; +`SVA_ASSERT_PROP_FATAL(undefined_shift_op, + tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.shift_op_valid |-> alu_ctrl_i.shift_op inside {SHIFT_OP_RL}, + $sformatf("Undefined shift operation pushed: 0x%X", alu_ctrl_i.shift_op) +); +`SVA_ASSERT_PROP_FATAL(undefined_bsr_op, + tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.bsr_op_valid |-> alu_ctrl_i.bsr_op.b, + $sformatf("Undefined bsr operation pushed: 0x%X", alu_ctrl_i.bsr_op) +); - assign out8_incr = (operand_i + 8'h01); - assign f_incr = {~(|out8_incr), 1'b0, out8_incr[4], f_r[3:0]}; - - assign out16_dec = (inx16_i - 16'h01); - - assign a_o = a_r; - assign f_o = f_r; - - assign out8_o = ({8{alu_op_valid_i}} & out8_incr) | {8{rot_op_valid_i}} & out8_rl; - assign out16_o = out16_dec; - -endmodule : alu \ No newline at end of file +endmodule : alu diff --git a/rtl/cpu/alu16.sv b/rtl/cpu/alu16.sv new file mode 100644 index 0000000..1adcbb5 --- /dev/null +++ b/rtl/cpu/alu16.sv @@ -0,0 +1,21 @@ +`include "cpu_pkg.svh" + +import cpu_pkg::*; + +module alu16 ( + input logic [15:0] operand_in_i, + output logic [15:0] operand_out_o, + + input logic increment_i, + input logic decrement_i +); + +logic [15:0] op_inc; +logic [15:0] op_dec; + +assign op_inc = (operand_in_i + 16'h01); +assign op_dec = (operand_in_i - 16'h01); + +assign operand_out_o = ({16{increment_i}} & op_inc) | + ({16{decrement_i}} & op_dec); +endmodule : alu16 diff --git a/rtl/cpu/control.sv b/rtl/cpu/control.sv deleted file mode 100644 index 1414413..0000000 --- a/rtl/cpu/control.sv +++ /dev/null @@ -1,222 +0,0 @@ -`include "cpu_pkg.svh" - -import cpu_pkg::*; - -module control ( - input logic clk_i, - input logic nreset_i, - - input logic [ 7:0] rdata_i, - - input logic [ 7:0] f_i, - - output state_t state_o, - - output logic [15:0] pc_o, - output logic [15:0] sp_o, - - output logic instr_valid_o, - output logic instr_undef_o, - output logic [ 7:0] operand8_o, - output logic [15:0] operand16_o, - - output logic alu_op_valid_o, - output alu_op_t alu_op_o, - output logic reg_write_alu_o, - output logic rot_op_valid_o, - output rot_op_t rot_op_o, - output op_src_t op_src_o, - output op_dest_t op_dest_o, - output reg8_t reg8_dest_o, - output reg8_t reg8_src_o, - output alu16_op_t alu16_op_o, - output reg16_t reg16_src_o, - output reg16_t reg16_dest_o, - - output logic memory_we_o, - output adr_src_t adr_src_o -); - - logic nreset_r; - logic halted_r; - - logic state_we; - state_t state_r; - state_t state_next; - - logic pc_we; - logic [15:0] pc_r; - logic [15:0] pc_next; - - - logic sp_we; - logic [15:0] sp_r; - logic [15:0] sp_next; - - logic instr_pc_we; - logic [15:0] instr_pc_r; - logic [15:0] instr_pc_next; - - logic instr_we; - logic [ 7:0] instr_r; - logic [ 7:0] instr_next; - - logic operand0_we; - logic [ 7:0] operand0_r; - logic [ 7:0] operand0_next; - - logic operand1_we; - logic [ 7:0] operand1_r; - logic [ 7:0] operand1_next; - - logic [ 7:0] decoder_instr0_selected; - logic [ 7:0] decoder_instr1_selected; - logic [ 7:0] decoder_instr2_selected; - logic decoder_need_instr1; - logic decoder_need_instr2; - logic decoder_is_multicycle; - logic decoder_is_multicycle2; - logic decoder_is_undef; - logic decoder_alu_op_valid; - logic decoder_rot_op_valid; - logic decoder_memory_we; - adr_src_t decoder_adr_src; - logic decoder_sp_we; - - logic is_undef; - logic pc_incr; - logic instr_valid; - logic branch_taken; - logic branch_cc_true; - logic branch_always; - - sp_src_t sp_src; - pc_src_t pc_src; - cc_t cc; - - always_ff @(posedge clk_i) begin - 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); - `DEF_FF(instr_pc_r, instr_pc_next, instr_pc_we, '0); - `DEF_FF(instr_r, instr_next, instr_we, '0); - `DEF_FF(operand0_r, operand0_next, operand0_we, '0); - `DEF_FF(operand1_r, operand1_next, operand1_we, '0); - - 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}) : - (branch_taken & pc_src == PC_SRC_OPERAND16) ? {operand1_r, operand0_r} : - (pc_r + 16'b1); - - assign sp_we = instr_valid & decoder_sp_we; - assign sp_next = (sp_src == SP_SRC_OPERAND16) ? {operand1_r, operand0_r} : - (sp_src == SP_SRC_INC) ? (sp_r + 16'h01) : - (sp_src == SP_SRC_DEC) ? (sp_r + 16'hFFFF) : - '0; - - assign instr_we = (state_r == ST1_DEC); - assign instr_next = rdata_i; - - assign instr_pc_we = (state_r == ST0_ADDR); - assign instr_pc_next = pc_r; - - assign operand0_we = (state_r == ST2_DEC); - assign operand0_next = rdata_i; - - assign operand1_we = (state_r == ST3_DEC); - assign operand1_next = rdata_i; - - assign state_we = nreset_r & ~is_undef & ~halted_r; - always_comb begin - case (state_r) - ST0_ADDR: state_next = ST1_DEC; - ST1_DEC: state_next = decoder_need_instr1 ? ST2_DEC : ST2_EXEC; - ST2_EXEC: state_next = decoder_is_multicycle ? ST3_EXEC : ST0_ADDR; - - ST2_DEC: state_next = decoder_need_instr2 ? ST3_DEC : ST3_EXEC; - ST3_DEC: state_next = ST4_EXEC; - ST3_EXEC: state_next = decoder_is_multicycle2 ? ST4_EXEC : ST0_ADDR; - ST4_EXEC: state_next = decoder_need_instr2 & decoder_is_multicycle ? ST5_EXEC : ST0_ADDR; - ST5_EXEC: state_next = ST0_ADDR; - endcase - end - - decode decode_inst ( - .instr0_i (decoder_instr0_selected), - .instr1_i (decoder_instr1_selected), - .instr2_i (decoder_instr2_selected), - .state_i (state_r), - - .need_instr1_o (decoder_need_instr1), - .need_instr2_o (decoder_need_instr2), - .is_multicycle_o(decoder_is_multicycle), - .is_multicycle2_o(decoder_is_multicycle2), - .undef_o (decoder_is_undef), - - .sp_we_o (decoder_sp_we), - .sp_src_o (sp_src), - - .alu_op_valid_o(decoder_alu_op_valid), - .alu_op_o (alu_op_o), - .reg_write_alu_o(reg_write_alu_o), - .rot_op_valid_o(decoder_rot_op_valid), - .rot_op_o (rot_op_o), - .op_src_o (op_src_o), - .op_dest_o (op_dest_o), - - .reg8_dest_o (reg8_dest_o), - .reg8_src_o (reg8_src_o), - - .alu16_op_o (alu16_op_o), - .reg16_src_o (reg16_src_o), - .reg16_dest_o (reg16_dest_o), - - .memory_we_o (decoder_memory_we), - .adr_src_o (decoder_adr_src), - .branch_always_o(branch_always), - .cc_o (cc), - .pc_src_o (pc_src) - ); - - assign decoder_instr0_selected = (state_r == ST1_DEC) ? rdata_i : instr_r; - assign decoder_instr1_selected = (state_r == ST2_DEC) ? rdata_i : operand0_r; - assign decoder_instr2_selected = (state_r == ST3_DEC) ? rdata_i : operand1_r; - - assign is_undef = instr_valid & decoder_is_undef; - assign instr_valid = (state_r == ST2_EXEC | state_r == ST3_EXEC | state_r == ST4_EXEC | state_r == ST5_EXEC); - assign alu_op_valid_o = decoder_alu_op_valid & instr_valid; - assign rot_op_valid_o = decoder_rot_op_valid & instr_valid; - - assign pc_incr = (state_r == ST0_ADDR) | (state_r == ST1_DEC & decoder_need_instr1) | (state_r == ST2_DEC & decoder_need_instr2); - - assign branch_taken = instr_valid & (pc_src != PC_SRC_SEQ) & (branch_cc_true | branch_always); - assign branch_cc_true = ((cc == CC_NZ) & ~f_i[7]) | - ((cc == CC_Z) & f_i[7]) | - ((cc == CC_NC) & ~f_i[4]) | - ((cc == CC_C) & f_i[4]); - - assign state_o = state_r; - assign pc_o = pc_r; - assign sp_o = sp_r; - - assign instr_valid_o = instr_valid; - assign instr_undef_o = is_undef; - - assign operand8_o = operand0_r; - assign operand16_o = {operand1_r, operand0_r}; - - assign memory_we_o = instr_valid & decoder_memory_we; - assign adr_src_o = instr_valid ? decoder_adr_src : - ADR_SRC_PC; - -endmodule : control diff --git a/rtl/cpu/cpu.sv b/rtl/cpu/cpu.sv index 602f27b..34c4032 100644 --- a/rtl/cpu/cpu.sv +++ b/rtl/cpu/cpu.sv @@ -3,150 +3,280 @@ import cpu_pkg::*; module cpu ( - input logic clk_i, - input logic nreset_i, + input logic clk, + input logic nreset, - output logic [15:0] address_o, - input logic [ 7:0] rdata_i, - output logic we_o, - output logic [ 7:0] wdata_o + output logic [15:0] addr_o, + input logic [ 7:0] rdata_i, + output logic we_o, + output logic [ 7:0] wdata_o ); - state_t state; - logic alu_op_valid; - alu_op_t alu_op; - op_src_t op_src; - op_dest_t op_dest; - adr_src_t adr_src; - logic reg_write_alu; - logic rot_op_valid; - rot_op_t rot_op; +logic instr_valid; +logic [ 7:0] instr[2:0]; - logic [ 7:0] alu_operand; +logic incr_pc; +logic pc_we; +logic [15:0] pc_r; +logic [15:0] pc_next; +logic [15:0] pc_bus; - logic [ 7:0] rega; - logic [ 7:0] regf; +cc_t ctrl_cc; +logic ctrl_pc_we; +logic ctrl_pc_we_cc; +pc_src_t ctrl_pc_src; - logic [15:0] pc; - logic [15:0] sp; - logic [15:0] hl; +logic [ 1:0] sp_we; +logic [15:0] sp_r; +logic [15:0] sp_next; - logic [15:0] sp_p1; +reg8_t reg8_rsel; +reg8_t reg8_wsel; +logic reg8_we; +logic [7:0] reg8_wdata; +logic [7:0] reg8_rdata; - logic instr_valid; - logic instr_undef; +reg16_t reg16_sel; +logic reg16_we; +logic [15:0] reg16_wdata; +logic [15:0] reg16_rdata; - logic [ 7:0] operand8; - logic [15:0] operand16; +addr_src_t addr_src; - 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; - reg16_t reg16_rselect2; - logic [ 7:0] reg8_rdata; - logic [15:0] reg16_rdata; - logic [15:0] reg16_rdata2; - alu16_op_t alu16_op; - logic [ 7:0] alu_out8; - logic [15:0] alu_out16; +logic [ 7:0] reg_a; +logic [ 7:0] reg_f; - control control_inst ( - .clk_i (clk_i), - .nreset_i (nreset_i), - .rdata_i (rdata_i), - .state_o (state), - .f_i (regf), - .pc_o (pc), - .sp_o (sp), - .alu_op_valid_o(alu_op_valid), - .alu_op_o (alu_op), - .reg_write_alu_o(reg_write_alu), - .rot_op_valid_o(rot_op_valid), - .rot_op_o (rot_op), - .op_src_o (op_src), - .op_dest_o (op_dest), - .instr_valid_o (instr_valid), - .instr_undef_o (instr_undef), - .operand8_o (operand8), - .operand16_o (operand16), - .reg8_dest_o (reg8_wselect), - .reg8_src_o (reg8_rselect), - .alu16_op_o (alu16_op), - .reg16_src_o (reg16_rselect), - .reg16_dest_o (reg16_wselect), - .memory_we_o (we_o), - .adr_src_o (adr_src) - ); +logic alu_update_a; +logic alu_update_f; +alu_ctrl_t ctrl_alu_ctrl; +alu_ctrl_t alu_ctrl; +logic [ 7:0] alu_operand_in; +logic [ 7:0] alu_operand_out; - alu alu_inst ( - .clk_i (clk_i), - .nreset_i (nreset_i), - .alu_op_valid_i(alu_op_valid), - .alu_op_i (alu_op), - .rot_op_valid_i(rot_op_valid), - .rot_op_i (rot_op), - .operand_i (alu_operand), - .inx8_i (operand8[5:3]), // Used for bit/set/res - .a_o (rega), - .f_o (regf), - .alu16_op_i (alu16_op), - .inx16_i (reg16_rdata2), - .iny16_i (reg16_rdata), - .out8_o (alu_out8), - .out16_o (alu_out16) - ); +logic alu16_en; +logic [15:0] alu16_in; +logic [15:0] alu16_out; +logic alu16_inc; +logic alu16_dec; - registers registers_inst ( - .clk_i (clk_i), - .nreset_i(nreset_i), +bus_ctrl_t bus_x_ctrl; +bus_ctrl_t bus_y_ctrl; +bus16_ctrl_t bus_p_ctrl; +bus16_ctrl_t bus_q_ctrl; +logic [ 7:0] bus_x; +logic [ 7:0] bus_y; +logic [15:0] bus_p; +logic [15:0] bus_q; - .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), - .reg16_rselect2_i(reg16_rselect2), - .reg16_rdata2_o (reg16_rdata2), - .hl_o (hl) - ); +logic cc_true; - assign sp_p1 = (sp + 16'h01); +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + pc_r <= '0; + else if (pc_we) + pc_r <= pc_next; +end - assign alu_operand = (op_src == OP_SRC_A) ? rega : - (op_src == OP_SRC_F) ? regf : - (op_src == OP_SRC_OPERAND8) ? operand8 : - (op_src == OP_SRC_REG8) ? reg8_rdata : - (op_src == OP_SRC_MEMORY) ? rdata_i : - (op_src == OP_SRC_PC_L) ? pc[7:0] : - (op_src == OP_SRC_PC_H) ? pc[15:8] : - 'X; +assign pc_we = ctrl_pc_we | (ctrl_pc_we_cc & cc_true); - assign reg8_we = instr_valid & (op_dest == OP_DEST_REG8); - assign reg8_wdata = reg_write_alu ? alu_out8 : alu_operand; - assign reg16_we = instr_valid & (op_dest == OP_DEST_REG16); - assign reg16_wdata = (op_src == OP_SRC_OPERAND16) ? operand16 : alu_out16; - assign reg16_rselect2 = reg16_wselect; +assign pc_next = (ctrl_pc_src == PC_SRC_OPERAND8 ) ? (pc_r + {{8{instr[1][7]}}, instr[1]}) : + (ctrl_pc_src == PC_SRC_OPERAND16) ? {instr[2], instr[1]} : + (ctrl_pc_src == PC_SRC_BUS) ? pc_bus : + pc_r + 16'h01; - assign address_o = (adr_src == ADR_SRC_HL) ? hl : - (adr_src == ADR_SRC_SP) ? sp : - (adr_src == ADR_SRC_SP_P1) ? sp_p1 : - (adr_src == ADR_SRC_REG8) ? {8'hFF, reg8_rdata} : - (adr_src == ADR_SRC_REG16) ? reg16_rdata : - (adr_src == ADR_SRC_OPERAND8) ? {8'hFF, operand8} : - (adr_src == ADR_SRC_OPERAND16) ? operand16 : - pc; - assign wdata_o = (op_dest == OP_DEST_MEMORY) ? alu_operand : - rega; // ldi/ldd hl, a use the normal control paths for HL +assign cc_true = ((ctrl_cc == CC_NZ) & ~reg_f[7]) | + ((ctrl_cc == CC_Z) & reg_f[7]) | + ((ctrl_cc == CC_NC) & ~reg_f[4]) | + ((ctrl_cc == CC_C) & reg_f[4]); -endmodule : cpu +assign pc_bus[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_PC_H}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_PC_H}} & bus_y); + +assign pc_bus[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_PC_L}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_PC_L}} & bus_y); + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + sp_r[15:0] <= '0; + else if (sp_we[1]) + sp_r[15:0] <= sp_next; +end +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + sp_r[ 7:0] <= '0; + else if (sp_we[0]) + sp_r[ 7:0] <= sp_next; +end + +assign sp_we[1] = instr_valid & ( + (bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_SP_H)) | + (bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_SP_H)) | + (bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_SP)) | + (bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_SP))); + +assign sp_we[0] = instr_valid & ( + (bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_SP_L)) | + (bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_SP_L)) | + (bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_SP)) | + (bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_SP))); + +assign sp_next[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_SP_H}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_SP_H}} & bus_y) | + ({8{bus_p_ctrl.dst == BUS16_DST_SP}} & bus_p[15:8]) | + ({8{bus_q_ctrl.dst == BUS16_DST_SP}} & bus_q[15:8]); +assign sp_next[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_SP_L}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_SP_L}} & bus_y) | + ({8{bus_p_ctrl.dst == BUS16_DST_SP}} & bus_p[ 7:0]) | + ({8{bus_q_ctrl.dst == BUS16_DST_SP}} & bus_q[ 7:0]); + +ctrl ctrl_inst ( + .clk (clk), + .nreset (nreset), + + .rdata_i (rdata_i), + + .instr_valid_o(instr_valid), + .instr_o (instr), + + .pc_we_o (ctrl_pc_we), + .pc_we_cc_o (ctrl_pc_we_cc), + .pc_src_o (ctrl_pc_src), + .cc_o (ctrl_cc), + + .reg8_src_o (reg8_rsel), + .reg8_dest_o (reg8_wsel), + .reg16_sel_o (reg16_sel), + + .alu_ctrl_o (ctrl_alu_ctrl), + + .addr_src_o (addr_src), + + .alu16_inc_o (alu16_inc), + .alu16_dec_o (alu16_dec), + + .bus_x_ctrl_o (bus_x_ctrl), + .bus_y_ctrl_o (bus_y_ctrl), + .bus_p_ctrl_o (bus_p_ctrl), + .bus_q_ctrl_o (bus_q_ctrl) +); + + +regbank regbank_inst ( + .clk (clk), + .nreset (nreset), + + + .reg16_wselect_i (reg16_sel), + .reg16_rselect_i (reg16_sel), + .reg16_we_i (reg16_we), + .reg16_wdata_i (reg16_wdata), + .reg16_rdata_o (reg16_rdata), + + .reg8_wselect_i (reg8_wsel), + .reg8_we_i (reg8_we), + .reg8_wdata_i (reg8_wdata), + .reg8_rselect_i (reg8_rsel), + .reg8_rdata_o (reg8_rdata) +); + +assign reg8_we = instr_valid & ( + (bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_REG8)) | + (bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_REG8))); + +assign reg8_wdata = ({8{bus_x_ctrl.dst == BUS_DST_REG8}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_REG8}} & bus_y); + +assign reg16_we = + instr_valid & ( + (bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_REG16_H | bus_x_ctrl.dst == BUS_DST_REG16_L)) | + (bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_REG16_H | bus_y_ctrl.dst == BUS_DST_REG16_L)) | + (bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_REG16)) | + (bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_REG16))); + +assign reg16_wdata[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_REG16_H}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_REG16_H}} & bus_y) | + ({8{bus_p_ctrl.dst == BUS16_DST_REG16}} & bus_p[15:8]) | + ({8{bus_q_ctrl.dst == BUS16_DST_REG16}} & bus_q[15:8]); +assign reg16_wdata[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_REG16_L}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_REG16_L}} & bus_y) | + ({8{bus_p_ctrl.dst == BUS16_DST_REG16}} & bus_p[ 7:0]) | + ({8{bus_q_ctrl.dst == BUS16_DST_REG16}} & bus_q[ 7:0]); + +alu alu_inst ( + .clk (clk), + .nreset (nreset), + + .alu_ctrl_i (alu_ctrl), + + .operand_in_i (alu_operand_in), + .operand_out_o(alu_operand_out), + + .reg_a_o (reg_a), + .reg_f_o (reg_f) +); + +always_comb begin + alu_ctrl = ctrl_alu_ctrl; + alu_ctrl.update_a = instr_valid & alu_ctrl.update_a; + alu_ctrl.update_f = instr_valid & alu_ctrl.update_f; +end + +assign alu_operand_in = ({8{bus_x_ctrl.dst == BUS_DST_ALU}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_ALU}} & bus_y); + +alu16 alu16_inst ( + .operand_in_i (alu16_in), + .operand_out_o(alu16_out), + .increment_i (alu16_inc), + .decrement_i (alu16_dec) +); +assign alu16_en = alu16_inc | alu16_dec; + +assign alu16_in = ({16{bus_p_ctrl.dst == BUS16_DST_ALU16}} & bus_p) | + ({16{bus_q_ctrl.dst == BUS16_DST_ALU16}} & bus_q); + +assign addr_o = ({16{addr_src == ADDR_SRC_PC }} & pc_r ) | + ({16{addr_src == ADDR_SRC_SP }} & sp_r ) | + ({16{addr_src == ADDR_SRC_REG16 }} & reg16_rdata) | + ({16{addr_src == ADDR_SRC_REG8 }} & { 8'hFF, reg8_rdata}) | + ({16{addr_src == ADDR_SRC_BUS_P }} & bus_p ) | + ({16{addr_src == ADDR_SRC_BUS_Q }} & bus_q ) | + ({16{addr_src == ADDR_SRC_OPERAND8 }} & { 8'hFF, instr[1] }) | + ({16{addr_src == ADDR_SRC_OPERAND16}} & {instr[2], instr[1] }); + +assign we_o = instr_valid & ( + (bus_x_ctrl.wen & bus_x_ctrl.dst == BUS_DST_MEM) | + (bus_y_ctrl.wen & bus_y_ctrl.dst == BUS_DST_MEM)); + +assign wdata_o = ({8{bus_x_ctrl.dst == BUS_DST_MEM}} & bus_x) | + ({8{bus_y_ctrl.dst == BUS_DST_MEM}} & bus_y); + +`define INST_BUS(x) \ + assign bus_``x = ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_OPERAND8_H)}} & instr[2]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_OPERAND8_L)}} & instr[1]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG8 )}} & reg8_rdata) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_A )}} & reg_a) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_PC_H )}} & pc_r[15:8]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_PC_L )}} & pc_r[ 7:0]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG16_H )}} & reg16_rdata[15:8]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG16_L )}} & reg16_rdata[ 7:0]) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_MEM )}} & rdata_i ) | \ + ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_ALU )}} & alu_operand_out); + +`INST_BUS(x); +`INST_BUS(y); + +`undef INST_BUS + +`define INST_BUS16(x) \ + assign bus_``x = ({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_REG16)}} & reg16_rdata) | \ + ({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_ALU16)}} & alu16_out ) | \ + ({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_SP )}} & sp_r); + +`INST_BUS16(p); +`INST_BUS16(q); + +`undef INST_BUS16 + +endmodule : cpu \ No newline at end of file diff --git a/rtl/cpu/cpu_pkg.svh b/rtl/cpu/cpu_pkg.svh index 25c7517..a310fb0 100644 --- a/rtl/cpu/cpu_pkg.svh +++ b/rtl/cpu/cpu_pkg.svh @@ -1,128 +1,144 @@ package cpu_pkg; - // - // 4 | ST0_ADDR -> ST1_DEC -> ST2_EXEC -> ST3_NOP - // 12 | '-> ST2_DEC -> ST3_DEC -> ST4_EXEC -> .... -> ST11_NOP - // - typedef enum { - ST0_ADDR, - ST1_DEC, - ST2_EXEC, - ST2_DEC, - ST3_DEC, - ST3_EXEC, - ST4_EXEC, - ST5_EXEC - } state_t; +typedef enum logic [2:0] { + REG8_B = 3'h00, + REG8_C = 3'h01, + REG8_D = 3'h02, + REG8_E = 3'h03, + REG8_H = 3'h04, + REG8_L = 3'h05, + REG8_PHL = 3'h06, + REG8_A = 3'h07 +} reg8_t; - typedef enum logic [2:0] { - REG8_B = 3'h00, - REG8_C = 3'h01, - REG8_D = 3'h02, - REG8_E = 3'h03, - REG8_H = 3'h04, - REG8_L = 3'h05, - REG8_PHL = 3'h06, - REG8_A = 3'h07 - } 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 [1:0] { - REG16_BC = 2'h00, - REG16_DE = 2'h01, - REG16_HL = 2'h02, - REG16_SP_AF = 2'h03 - } reg16_t; +typedef enum logic [1:0] { + CC_NZ = 2'h00, + CC_Z = 2'h01, + CC_NC = 2'h02, + CC_C = 2'h03 +} cc_t; - typedef enum logic [1:0] { - CC_NZ = 2'h00, - CC_Z = 2'h01, - CC_NC = 2'h02, - CC_C = 2'h03 - } cc_t; +typedef enum logic [2:0] { + ALU_OP_ADD = 3'h00, + ALU_OP_ADC = 3'h01, + ALU_OP_SUB = 3'h02, + ALU_OP_SBC = 3'h03, + ALU_OP_AND = 3'h04, + ALU_OP_XOR = 3'h05, + ALU_OP_OR = 3'h06, + ALU_OP_CP = 3'h07 +} alu_op_t; - typedef enum logic [4:0] { - ALU_OP_ADD = 5'h00, - ALU_OP_ADC = 5'h01, - ALU_OP_SUB = 5'h02, - ALU_OP_SBC = 5'h03, - ALU_OP_AND = 5'h04, - ALU_OP_XOR = 5'h05, - ALU_OP_OR = 5'h06, - ALU_OP_CP = 5'h07, - ALU_OP_BIT = 5'h08, - ALU_OP_NOP = 5'h09, // Write operand to a - ALU_OP_NOPF = 5'h0a, // Write operand to f - ALU_OP_ROT = 5'h0b, - ALU_OP_INC = 5'h0c, - ALU_OP_INCR = 5'h0d // Increment register instead of a - } alu_op_t; +typedef enum logic [2:0] { + SHIFT_OP_RLC = 3'h00, + SHIFT_OP_RRC = 3'h01, + SHIFT_OP_RL = 3'h02, + SHIFT_OP_RR = 3'h03, + SHIFT_OP_SLA = 3'h04, + SHIFT_OP_SRA = 3'h05, + SHIFT_OP_SLL = 3'h06, + SHIFT_OP_SRL = 3'h07 +} shift_op_t; - typedef enum logic [2:0] { - ROT_OP_RLC = 3'h00, - ROT_OP_RRC = 3'h01, - ROT_OP_RL = 3'h02, - ROT_OP_RR = 3'h03, - ROT_OP_SLA = 3'h04, - ROT_OP_SRA = 3'h05, - ROT_OP_SLL = 3'h06, - ROT_OP_SRL = 3'h07 - } rot_op_t; +typedef struct packed { + logic b; + logic s; + logic r; + logic [2:0] operand; +} bsr_op_t; - typedef enum logic [1:0] { - ALU16_OP_ADD = 2'h00, - ALU16_INC = 2'h01, - ALU16_DEC = 2'h02 - } alu16_op_t; +typedef struct packed { + logic inc; + logic dec; + logic dst_a; +} incdec_op_t; - typedef enum { - OP_SRC_A, - OP_SRC_F, - OP_SRC_REG8, - OP_SRC_OPERAND8, - OP_SRC_MEMORY, - OP_SRC_OPERAND16, - OP_SRC_REG16, - OP_SRC_PC_L, - OP_SRC_PC_H - } op_src_t; +typedef struct packed { + logic update_a; + logic update_f; + logic alu_op_valid; + alu_op_t alu_op; + logic shift_op_valid; + shift_op_t shift_op; + logic bsr_op_valid; + bsr_op_t bsr_op; + logic incdec_op_valid; + incdec_op_t incdec_op; +} alu_ctrl_t; - typedef enum { - OP_DEST_A, - OP_DEST_REG8, - OP_DEST_REG16, - OP_DEST_MEMORY - } op_dest_t; +typedef enum { + ADDR_SRC_PC, + ADDR_SRC_SP, + ADDR_SRC_REG16, // TODO reuse BUS_Q + ADDR_SRC_REG8, // TODO reuse BUS_Q + ADDR_SRC_OPERAND8, + ADDR_SRC_OPERAND16, + ADDR_SRC_BUS_P, + ADDR_SRC_BUS_Q +} addr_src_t; - typedef enum { - SP_SRC_OPERAND16, - SP_SRC_INC, - SP_SRC_DEC - } sp_src_t; +typedef enum { + BUS_SRC_A, + BUS_SRC_F, + BUS_SRC_REG8, + BUS_SRC_OPERAND8_H, + BUS_SRC_OPERAND8_L, + BUS_SRC_ALU, + BUS_SRC_MEM, + BUS_SRC_PC_H, + BUS_SRC_PC_L, + BUS_SRC_REG16_H, + BUS_SRC_REG16_L +} bus_src_t; - typedef enum { - ADR_SRC_PC, - ADR_SRC_HL, - ADR_SRC_SP, - ADR_SRC_SP_P1, // SP + 1 for pop - ADR_SRC_REG8, // extended with FF - ADR_SRC_REG16, - ADR_SRC_OPERAND8, // extended with FF - ADR_SRC_OPERAND16 - } adr_src_t; +typedef enum { + BUS_DST_SP_H, + BUS_DST_SP_L, + BUS_DST_ALU, + BUS_DST_REG8, + BUS_DST_REG16_H, + BUS_DST_REG16_L, + BUS_DST_PC_H, + BUS_DST_PC_L, + BUS_DST_MEM +} bus_dst_t; - typedef enum { - PC_SRC_SEQ, - PC_SRC_OPERAND8, - PC_SRC_OPERAND16 - } pc_src_t; +typedef struct packed { + bus_src_t src; + bus_dst_t dst; + logic wen; +} bus_ctrl_t; -endpackage +typedef enum { + BUS16_SRC_REG16, + BUS16_SRC_ALU16, + BUS16_SRC_SP +} bus16_src_t; -`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 +typedef enum { + BUS16_DST_REG16, + BUS16_DST_ALU16, + BUS16_DST_SP +} bus16_dst_t; + +typedef struct packed { + bus16_src_t src; + bus16_dst_t dst; + logic wen; +} bus16_ctrl_t; + +typedef enum { + PC_SRC_INC, + PC_SRC_OPERAND8, + PC_SRC_OPERAND16, + PC_SRC_BUS +} pc_src_t; + +endpackage : cpu_pkg diff --git a/rtl/cpu/ctrl.sv b/rtl/cpu/ctrl.sv new file mode 100644 index 0000000..50b0847 --- /dev/null +++ b/rtl/cpu/ctrl.sv @@ -0,0 +1,180 @@ +`include "cpu_pkg.svh" + +import cpu_pkg::*; + +module ctrl ( + input logic clk, + input logic nreset, + + input logic [ 7:0] rdata_i, + + output logic instr_valid_o, + output logic [ 7:0] instr_o [2:0], + + output logic pc_we_o, // update PC always + output logic pc_we_cc_o, // update PC conditionally + output pc_src_t pc_src_o, + output cc_t cc_o, + + output reg8_t reg8_src_o, + output reg8_t reg8_dest_o, + output reg16_t reg16_sel_o, + + output alu_ctrl_t alu_ctrl_o, + + output logic alu16_inc_o, + output logic alu16_dec_o, + + output addr_src_t addr_src_o, + + output bus_ctrl_t bus_x_ctrl_o, + output bus_ctrl_t bus_y_ctrl_o, + output bus16_ctrl_t bus_p_ctrl_o, + output bus16_ctrl_t bus_q_ctrl_o +); + +typedef enum { + ST_RESET, + ST_ADDR, + ST_FETCH0, + ST_FETCH1, + ST_FETCH2, + ST_EXEC1, + ST_EXEC2, + ST_EXEC3 +} state_t; + +logic halt; +logic instr_undef; + +logic halted_r; + +logic state_en; +state_t state_r; +state_t state_next; +logic state_ex; + +logic instr_we [2:0]; +logic [ 7:0] instr_r [2:0]; +logic [ 7:0] instr [2:0]; + +logic req_instr1; +logic req_instr2; +logic req_ex2; +logic req_ex3; + +addr_src_t instr_addr_src; + +logic is_ex1; +logic is_ex2; +logic is_ex3; + +logic incr_pc; +logic idec_pc_we; +logic idec_pc_we_cc; +pc_src_t idec_pc_src; + +idec idec_inst ( + .instr_i (instr), + .is_ex1_i (is_ex1), + .is_ex2_i (is_ex2), + .is_ex3_i (is_ex3), + + .req_instr1_o (req_instr1), + .req_instr2_o (req_instr2), + .req_ex2_o (req_ex2), + .req_ex3_o (req_ex3), + + .reg8_src_o (reg8_src_o), + .reg8_dest_o (reg8_dest_o), + .reg16_sel_o (reg16_sel_o), + + .bus_x_ctrl_o (bus_x_ctrl_o), + .bus_y_ctrl_o (bus_y_ctrl_o), + .bus_p_ctrl_o (bus_p_ctrl_o), + .bus_q_ctrl_o (bus_q_ctrl_o), + + .alu_ctrl_o (alu_ctrl_o), + + .alu16_inc_o (alu16_inc_o), + .alu16_dec_o (alu16_dec_o), + + .addr_src_o (instr_addr_src), + + .pc_we_o (idec_pc_we), + .pc_we_cc_o (idec_pc_we_cc), + .cc_o (cc_o), + .pc_src_o (idec_pc_src), + + .instr_undef_o (instr_undef) +); + +assign is_ex1 = state_r == ST_EXEC1; +assign is_ex2 = state_r == ST_EXEC2; +assign is_ex3 = state_r == ST_EXEC3; + +assign halt = instr_undef & is_ex1; + +assign state_en = ~halted_r; + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + state_r <= ST_RESET; + else if (state_en) + state_r <= state_next; +end + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + halted_r <= 1'b0; + else if (halt) + halted_r <= 1'b1; +end + +generate for (genvar i = 0; i < 3; i++) begin : gen_instr_r + always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + instr_r[i] <= 8'h0; + else if (instr_we[i]) + instr_r[i] <= rdata_i; + end +end endgenerate + +assign instr_we[0] = (state_r == ST_FETCH0); +assign instr_we[1] = (state_r == ST_FETCH1); +assign instr_we[2] = (state_r == ST_FETCH2); + +always_comb begin + case (state_r) + ST_RESET: state_next = ST_ADDR; + ST_ADDR: state_next = ST_FETCH0; + ST_FETCH0: state_next = req_instr1 ? ST_FETCH1 : ST_EXEC1; + ST_FETCH1: state_next = req_instr2 ? ST_FETCH2 : ST_EXEC1; + ST_FETCH2: state_next = ST_EXEC1; + ST_EXEC1: state_next = req_ex2 ? ST_EXEC2 : ST_ADDR; + ST_EXEC2: state_next = req_ex3 ? ST_EXEC3 : ST_ADDR; + ST_EXEC3: state_next = ST_ADDR; + endcase +end + +assign state_ex = is_ex1 | is_ex2 | is_ex3; + +assign incr_pc = (state_r == ST_ADDR) | + (state_r == ST_FETCH0 & req_instr1) | + (state_r == ST_FETCH1 & req_instr2); + +assign pc_we_o = state_ex ? idec_pc_we : incr_pc; +assign pc_we_cc_o = state_ex & idec_pc_we_cc; +assign pc_src_o = state_ex ? idec_pc_src : PC_SRC_INC; + +assign instr_valid_o = state_ex & ~instr_undef; + +assign instr[0] = (state_r == ST_FETCH0) ? rdata_i : instr_r[0]; +assign instr[1] = (state_r == ST_FETCH1) ? rdata_i : instr_r[1]; +assign instr[2] = (state_r == ST_FETCH2) ? rdata_i : instr_r[2]; + +assign instr_o = instr; + +assign addr_src_o = state_ex ? instr_addr_src : ADDR_SRC_PC; + +endmodule : ctrl diff --git a/rtl/cpu/decode.sv b/rtl/cpu/decode.sv deleted file mode 100644 index 32d2b0f..0000000 --- a/rtl/cpu/decode.sv +++ /dev/null @@ -1,233 +0,0 @@ -`include "cpu_pkg.svh" - -import cpu_pkg::*; - -module decode ( - input logic [7:0] instr0_i, - input logic [7:0] instr1_i, - input logic [7:0] instr2_i, - - input state_t state_i, - - output logic need_instr1_o, - output logic need_instr2_o, - output logic is_multicycle_o, - output logic is_multicycle2_o, - output logic undef_o, - - output logic sp_we_o, - output sp_src_t sp_src_o, - - output logic alu_op_valid_o, - output alu_op_t alu_op_o, - output logic reg_write_alu_o, - output logic rot_op_valid_o, - output rot_op_t rot_op_o, - output op_src_t op_src_o, - output op_dest_t op_dest_o, - - output reg8_t reg8_dest_o, - output reg8_t reg8_src_o, - output alu16_op_t alu16_op_o, - output reg16_t reg16_dest_o, - output reg16_t reg16_src_o, - - output logic branch_always_o, - output cc_t cc_o, - - output pc_src_t pc_src_o, - output adr_src_t adr_src_o, - output logic memory_we_o -); - - logic [1:0] dec_x; - logic [2:0] dec_y; - logic [2:0] dec_z; - logic [1:0] dec_p; - logic dec_q; - - logic is_cb; - logic is_ld_r_r; - logic is_ld_a_n; - logic is_ld_r_n; - logic is_ldh_c_a; - logic is_ldh_n_a; - logic is_ld_rr_a; - logic is_ld_nn_a; - logic is_ld_a_rr; - logic is_ld_a_nn; - logic is_ld_rr_nn; - logic is_ld_sp_nn; - logic is_ldd_hl_a; - logic is_alu_a_r; - logic is_bit_n_r; - logic is_rot_r; - logic is_rla; - logic is_inc_a; - logic is_inc_r; - logic is_jr_cc_n; - logic is_call_nn; - logic is_push_rr; - logic is_pop_rr; - - reg8_t reg8_dest; - reg8_t reg8_src; - reg16_t reg16_src; - - assign dec_x = instr0_i[7:6]; - assign dec_y = instr0_i[5:3]; - assign dec_z = instr0_i[2:0]; - assign dec_p = instr0_i[5:4]; - assign dec_q = instr0_i[3]; - - assign is_cb = (instr0_i == 8'hCB); - - assign is_ld_r_r = (dec_x == 2'h1) & ((dec_z != 3'h6) | (dec_y != 3'h6)); - assign is_ld_a_n = is_ld_r_n & (reg8_dest == REG8_A); - assign is_ld_r_n = (dec_x == 2'h0) & (dec_z == 3'h6); - assign is_ld_rr_nn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p != 2'h3); - assign is_ld_sp_nn = (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_ld_rr_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p != 2'h3); - assign is_ld_nn_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h2); - assign is_ld_a_rr = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p != 2'h3); - assign is_ld_a_nn = (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_ldh_n_a = instr0_i == 8'hE0; - - assign is_alu_a_r = (dec_x == 3'h2); - assign is_bit_n_r = (is_cb & instr1_i[7:6] == 2'h1); - assign is_rot_r = (is_cb & instr1_i[7:6] == 2'h0); - - assign is_rla = (dec_x == 3'h0) & (dec_z == 3'h7) & (dec_y == 3'h2); - - assign is_inc_a = is_inc_r & (reg8_dest == REG8_A); - assign is_inc_r = (dec_x == 2'h0) & (dec_z == 3'h4); - - assign is_jr_cc_n = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2]; - assign is_call_nn = (instr0_i == 8'hCD); - assign is_push_rr = (dec_x == 2'h3) & (dec_z == 3'h5) & ~dec_q; - assign is_pop_rr = (dec_x == 2'h3) & (dec_z == 3'h1) & ~dec_q; - - assign reg8_src = is_cb ? reg8_t'(instr1_i[2:0]) : - is_ldh_c_a ? REG8_C : - is_inc_r ? reg8_t'(dec_y) : - (is_push_rr & state_i == ST2_EXEC) ? reg8_t'({dec_p, 1'b0}) : - (is_push_rr & state_i == ST3_EXEC) ? reg8_t'({dec_p, 1'b1}) : - reg8_t'(dec_z); - assign reg8_dest = is_rot_r ? reg8_t'(dec_z) : - (is_pop_rr & state_i == ST3_EXEC) ? reg8_t'({dec_p, 1'b1}) : - (is_pop_rr & state_i == ST4_EXEC) ? reg8_t'({dec_p, 1'b0}) : - reg8_t'(dec_y); - - assign reg16_src = is_ldd_hl_a ? REG16_HL : reg16_t'(dec_p); - - assign need_instr1_o = is_ld_sp_nn | is_ld_rr_nn | is_ld_a_nn | is_call_nn | is_cb | is_jr_cc_n | is_ld_r_n | is_ldh_n_a; - assign need_instr2_o = is_ld_sp_nn | is_ld_rr_nn | is_ld_a_nn | is_call_nn; - assign is_multicycle_o = is_ld_a_rr | is_call_nn | is_push_rr | is_pop_rr; - assign is_multicycle2_o = is_pop_rr; - - assign undef_o = ~(is_ldh_n_a | is_ld_r_r | is_ld_sp_nn | is_ld_rr_nn | is_alu_a_r | is_ldd_hl_a | is_bit_n_r | - is_jr_cc_n | is_ld_r_n | is_ldh_c_a | is_inc_r | is_ld_rr_a | is_ld_a_rr | is_call_nn | - is_push_rr | is_pop_rr | (is_rot_r & (instr1_i[5:3] == 3'h02)) | is_rla); - - assign sp_we_o = is_ld_sp_nn | is_call_nn | is_push_rr | (is_pop_rr & ((state_i == ST2_EXEC) | (state_i == ST3_EXEC))); - assign sp_src_o = is_ld_sp_nn ? SP_SRC_OPERAND16 : - is_call_nn ? SP_SRC_DEC : - is_push_rr ? SP_SRC_DEC : - is_pop_rr ? SP_SRC_INC : - sp_src_t'('X); - - assign alu_op_valid_o = is_alu_a_r | is_bit_n_r | is_ld_a_n | is_ld_a_rr | is_ld_a_nn | is_inc_r | is_rla | (is_pop_rr & reg16_src == REG16_SP_AF); - assign alu_op_o = is_bit_n_r ? ALU_OP_BIT : - is_ld_a_n ? ALU_OP_NOP : - is_ld_a_nn ? ALU_OP_NOP : - is_ld_a_rr ? ALU_OP_NOP : - is_inc_a ? ALU_OP_INC : - is_inc_r ? ALU_OP_INCR : - is_rla ? ALU_OP_ROT : - (is_pop_rr & reg16_src == REG16_SP_AF & state_i == ST2_EXEC) ? ALU_OP_NOP : - (is_pop_rr & reg16_src == REG16_SP_AF & state_i == ST3_EXEC) ? ALU_OP_NOPF : - alu_op_t'({1'b0, dec_y}); - assign reg_write_alu_o = is_inc_r | is_rot_r; - - assign rot_op_valid_o = is_rot_r | is_rla; - assign rot_op_o = is_rla ? ROT_OP_RL : - rot_op_t'(instr1_i[5:3]); - - assign op_dest_o = (is_ld_r_r & reg8_dest == REG8_PHL) ? OP_DEST_MEMORY : - (is_ld_r_n & reg8_dest == REG8_PHL) ? OP_DEST_MEMORY : - (is_ld_r_r & reg8_dest == REG8_A) ? OP_DEST_A : - is_ld_r_r ? OP_DEST_REG8 : - is_ld_a_n ? OP_DEST_A : - is_ld_a_rr ? OP_DEST_A : - is_ld_a_nn ? OP_DEST_A : - is_ld_r_n ? OP_DEST_REG8 : - is_ldh_c_a ? OP_DEST_MEMORY : - is_ldh_n_a ? OP_DEST_MEMORY : - is_ld_rr_nn ? OP_DEST_REG16 : - is_ldd_hl_a ? OP_DEST_REG16 : - is_inc_a ? OP_DEST_A : - is_inc_r ? OP_DEST_REG8 : - is_call_nn ? OP_DEST_MEMORY : - is_push_rr ? OP_DEST_MEMORY : - (is_pop_rr & reg16_src != REG16_SP_AF) ? OP_DEST_REG8 : - (is_pop_rr & reg16_src == REG16_SP_AF) ? OP_DEST_A : - is_rot_r ? OP_DEST_REG8 : - is_rla ? OP_DEST_A : - op_dest_t'('X); - - assign op_src_o = (is_ld_r_r & reg8_src == REG8_A) ? OP_SRC_A : - (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_r & reg8_src == REG8_PHL) ? OP_SRC_MEMORY : - is_inc_r ? OP_SRC_REG8 : - is_ld_r_n ? OP_SRC_OPERAND8 : - is_ldh_c_a ? OP_SRC_A : - is_ldh_n_a ? OP_SRC_A : - is_ld_a_rr ? OP_SRC_MEMORY : - is_ld_a_nn ? OP_SRC_MEMORY : - is_ld_rr_nn ? OP_SRC_OPERAND16 : - is_ldd_hl_a ? OP_SRC_REG16 : - is_bit_n_r ? OP_SRC_REG8 : - is_rot_r ? OP_SRC_REG8 : - is_rla ? OP_SRC_A : - (is_call_nn & state_i == ST4_EXEC) ? OP_SRC_PC_L : - (is_call_nn & state_i == ST5_EXEC) ? OP_SRC_PC_H : - (is_push_rr & reg16_src != REG16_SP_AF) ? OP_SRC_REG8 : - (is_push_rr & reg16_src == REG16_SP_AF & state_i == ST2_EXEC) ? OP_SRC_A : - (is_push_rr & reg16_src == REG16_SP_AF & state_i == ST3_EXEC) ? OP_SRC_F : - is_pop_rr ? OP_SRC_MEMORY : - op_src_t'('X); - - assign reg8_dest_o = reg8_dest; - assign reg8_src_o = reg8_src; - assign reg16_src_o = reg16_src; - assign reg16_dest_o = reg16_src; - - assign pc_src_o = is_jr_cc_n ? PC_SRC_OPERAND8 : - is_call_nn ? PC_SRC_OPERAND16 : - PC_SRC_SEQ; - - assign adr_src_o = (is_ld_r_r & reg8_dest == REG8_PHL) ? ADR_SRC_HL : - (is_ld_r_r & reg8_src == REG8_PHL) ? ADR_SRC_HL : - is_ldd_hl_a ? ADR_SRC_HL : - (is_ld_r_n & reg8_dest == REG8_PHL) ? ADR_SRC_HL : - is_ldh_c_a ? ADR_SRC_REG8 : - is_ldh_n_a ? ADR_SRC_OPERAND8 : - is_ld_nn_a ? ADR_SRC_OPERAND16 : - is_ld_a_nn ? ADR_SRC_OPERAND16 : - is_ld_a_rr ? ADR_SRC_REG16 : - is_ld_rr_a ? ADR_SRC_REG16 : - is_call_nn ? ADR_SRC_SP : - is_push_rr ? ADR_SRC_SP : - is_pop_rr ? ADR_SRC_SP_P1 : - ADR_SRC_PC; - - assign branch_always_o = is_call_nn; - assign cc_o = cc_t'(dec_y[1:0]); - - assign memory_we_o = is_ldd_hl_a | is_ldh_c_a | is_ldh_n_a | is_ld_rr_a | (is_ld_r_n & reg8_dest == REG8_PHL) | (is_ld_r_r & reg8_dest == REG8_PHL) | - is_call_nn | is_push_rr; - -endmodule : decode diff --git a/rtl/cpu/idec.sv b/rtl/cpu/idec.sv new file mode 100644 index 0000000..652db9e --- /dev/null +++ b/rtl/cpu/idec.sv @@ -0,0 +1,347 @@ +`include "cpu_pkg.svh" + +import cpu_pkg::*; + +module idec ( + input logic [7:0] instr_i[2:0], + + input logic is_ex1_i, + input logic is_ex2_i, + input logic is_ex3_i, + + output logic req_instr1_o, + output logic req_instr2_o, + output logic req_ex2_o, + output logic req_ex3_o, + + output bus_ctrl_t bus_x_ctrl_o, + output bus_ctrl_t bus_y_ctrl_o, + output bus16_ctrl_t bus_p_ctrl_o, + output bus16_ctrl_t bus_q_ctrl_o, + + output reg8_t reg8_src_o, + output reg8_t reg8_dest_o, + output reg16_t reg16_sel_o, + + output alu_ctrl_t alu_ctrl_o, + + output logic alu16_inc_o, + output logic alu16_dec_o, + + output addr_src_t addr_src_o, + + output logic pc_we_o, + output logic pc_we_cc_o, + output cc_t cc_o, + output pc_src_t pc_src_o, + + output logic instr_undef_o + +); + +logic [1:0] dec_x; +logic [2:0] dec_y; +logic [2:0] dec_z; +logic [1:0] dec_p; +logic dec_q; + +logic is_alu_a_r; +logic is_alu_a_n; +logic is_ld_sp_nnnn; +logic is_ld_rr_nnnn; +logic is_ld_pnnnn_a; +logic is_ldd_hl_a; +logic is_ldi_hl_a; +logic is_ldd_a_hl; +logic is_ldi_a_hl; +logic is_cb; +logic is_ld_r_r; +logic is_ld_r_n; +logic is_ldh_c_a; +logic is_ldh_n_a; +logic is_ldh_a_n; +logic is_ld_rr_a; +logic is_ld_a_pbc; +logic is_ld_a_pde; +logic is_ld_a_nn; +logic is_bit_n_r; +logic is_shift_r; +logic is_rla; +logic is_inc_r; +logic is_dec_r; +logic is_jr_cc_nn; +logic is_jr_nn; +logic is_call_nn; +logic is_ret; +logic is_push_rr; +logic is_pop_rr; +logic is_inc_rr; +logic is_dec_rr; + +reg8_t reg8_src; +reg8_t reg8_dest; +reg16_t reg16_sel; + +assign req_instr1_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_call_nn | is_ld_pnnnn_a | is_cb | is_jr_nn | is_jr_cc_nn | is_ld_r_n | is_ldh_n_a | is_ldh_a_n | is_alu_a_n; +assign req_instr2_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_call_nn | is_ld_pnnnn_a; +assign req_ex2_o = is_call_nn | is_ret | is_push_rr | is_pop_rr | ((is_ld_r_r | is_alu_a_r) & (reg8_src == REG8_PHL)); +assign req_ex3_o = is_ret | is_pop_rr; + +assign dec_x = instr_i[0][7:6]; +assign dec_y = instr_i[0][5:3]; +assign dec_z = instr_i[0][2:0]; +assign dec_p = instr_i[0][5:4]; +assign dec_q = instr_i[0][3]; + +assign is_jr_nn = instr_i[0] == 8'h18; +assign is_cb = instr_i[0] == 8'hCB; +assign is_call_nn = instr_i[0] == 8'hCD; +assign is_ret = instr_i[0] == 8'hC9; +assign is_ldh_c_a = instr_i[0] == 8'hE2; +assign is_ldh_n_a = instr_i[0] == 8'hE0; +assign is_ldh_a_n = instr_i[0] == 8'hF0; +assign is_ld_pnnnn_a = instr_i[0] == 8'hEA; + +assign is_jr_cc_nn = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2]; +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_ldi_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h2); +assign is_ldd_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h3); +assign is_ld_a_pbc = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h0); +assign is_ld_a_pde = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h1); +assign is_ldi_a_hl = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h2); +assign is_ldd_a_hl = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h3); +assign is_inc_rr = (dec_x == 2'h0) & (dec_z == 3'h3) & ~dec_q; +assign is_dec_rr = (dec_x == 2'h0) & (dec_z == 3'h3) & dec_q; +assign is_inc_r = (dec_x == 2'h0) & (dec_z == 3'h4); +assign is_dec_r = (dec_x == 2'h0) & (dec_z == 3'h5); +assign is_ld_r_n = (dec_x == 2'h0) & (dec_z == 3'h6); +assign is_ld_rr_a = '0; +assign is_rla = (dec_x == 3'h0) & (dec_z == 3'h7) & (dec_y == 3'h2); + +assign is_ld_r_r = (dec_x == 2'h1) & ((dec_z != 3'h6) | (dec_y != 3'h6)); + +assign is_alu_a_r = (dec_x == 2'h2); + +assign is_pop_rr = (dec_x == 2'h3) & (dec_z == 3'h1) & ~dec_q; +assign is_push_rr = (dec_x == 2'h3) & (dec_z == 3'h5) & ~dec_q; +assign is_alu_a_n = (dec_x == 2'h3) & (dec_z == 3'h6); + +assign is_bit_n_r = (is_cb & instr_i[1][7:6] == 2'h1); +assign is_shift_r = (is_cb & instr_i[1][7:6] == 2'h0) | is_rla; + + +assign bus_x_ctrl_o.src = (is_ld_sp_nnnn ) ? BUS_SRC_OPERAND8_H : + (is_ld_rr_nnnn ) ? BUS_SRC_OPERAND8_H : + (is_ld_pnnnn_a ) ? BUS_SRC_A : + (is_ldd_hl_a ) ? BUS_SRC_A : + (is_ldi_hl_a ) ? BUS_SRC_A : + (is_ldh_c_a ) ? BUS_SRC_A : + (is_ldh_n_a ) ? BUS_SRC_A : + (is_ldh_a_n ) ? BUS_SRC_MEM : + (is_alu_a_r & (reg8_src == REG8_A )) ? BUS_SRC_A : + (is_alu_a_r & (reg8_src == REG8_PHL)) ? BUS_SRC_MEM : + (is_alu_a_r ) ? BUS_SRC_REG8 : + (is_alu_a_n ) ? BUS_SRC_OPERAND8_L : + (is_bit_n_r & (reg8_src == REG8_A )) ? BUS_SRC_A : + (is_bit_n_r & (reg8_src != REG8_A )) ? BUS_SRC_REG8 : + (is_ld_r_n ) ? BUS_SRC_OPERAND8_L : + (is_inc_r ) ? BUS_SRC_REG8 : + (is_dec_r ) ? BUS_SRC_REG8 : + (is_ld_r_r & (reg8_src == REG8_A )) ? BUS_SRC_A : + (is_ld_r_r & (reg8_src == REG8_PHL)) ? BUS_SRC_MEM : + (is_ld_r_r ) ? BUS_SRC_REG8 : + (is_ld_a_pbc ) ? BUS_SRC_MEM : + (is_ld_a_pde ) ? BUS_SRC_MEM : + (is_call_nn & ~is_ex2_i ) ? BUS_SRC_PC_L : + (is_call_nn & is_ex2_i ) ? BUS_SRC_PC_H : + (is_push_rr & ~is_ex2_i ) ? BUS_SRC_REG16_L : + (is_push_rr & is_ex2_i ) ? BUS_SRC_REG16_H : + (is_pop_rr ) ? BUS_SRC_MEM : + (is_ret ) ? BUS_SRC_MEM : + (is_shift_r & (reg8_src == REG8_A )) ? BUS_SRC_A : + (is_shift_r & (reg8_src != REG8_A )) ? BUS_SRC_REG8 : + BUS_SRC_MEM; + +assign bus_x_ctrl_o.dst = is_ld_sp_nnnn ? BUS_DST_SP_H : + is_ld_rr_nnnn ? BUS_DST_REG16_H : + is_ld_pnnnn_a ? BUS_DST_MEM : + is_ldd_hl_a ? BUS_DST_MEM : + is_ldi_hl_a ? BUS_DST_MEM : + is_ldh_c_a ? BUS_DST_MEM : + is_ldh_n_a ? BUS_DST_MEM : + is_ldh_a_n ? BUS_DST_ALU : + is_alu_a_r ? BUS_DST_ALU : + is_alu_a_n ? BUS_DST_ALU : + is_bit_n_r ? BUS_DST_ALU : + is_inc_r ? BUS_DST_ALU : + is_dec_r ? BUS_DST_ALU : + is_ld_a_pbc ? BUS_DST_ALU : + is_ld_a_pde ? BUS_DST_ALU : + is_call_nn ? BUS_DST_MEM : + is_push_rr ? BUS_DST_MEM : + is_pop_rr & is_ex2_i ? BUS_DST_REG16_H : + is_pop_rr & is_ex3_i ? BUS_DST_REG16_L : + is_ret & is_ex2_i ? BUS_DST_PC_H : + is_ret & is_ex3_i ? BUS_DST_PC_L : + (is_ld_r_n & (reg8_dest == REG8_A )) ? BUS_DST_ALU : + (is_ld_r_n & (reg8_dest != REG8_A )) ? BUS_DST_REG8 : + (is_ld_r_r & (reg8_dest == REG8_A )) ? BUS_DST_ALU : + (is_ld_r_r & (reg8_dest == REG8_PHL)) ? BUS_DST_MEM : + (is_ld_r_r ) ? BUS_DST_REG8 : + (is_shift_r ) ? BUS_DST_ALU : + BUS_DST_SP_H; +assign bus_x_ctrl_o.wen = + is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_n | is_ldd_hl_a | + is_ldi_hl_a | is_bit_n_r | is_ld_r_n | is_ldh_c_a | is_ldh_n_a | is_ldh_a_n | + is_call_nn | is_ret | is_push_rr | (is_pop_rr & (is_ex2_i | is_ex3_i)) | + (is_ret & (is_ex2_i | is_ex3_i)) | is_shift_r | is_inc_r | is_dec_r | is_ld_pnnnn_a | + (is_ld_r_r & (reg8_src != REG8_PHL)) | + (is_ld_r_r & (reg8_src == REG8_PHL) & is_ex2_i) | + (is_alu_a_r & (reg8_src != REG8_PHL)) | + (is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i); + +assign bus_y_ctrl_o.src = is_ld_sp_nnnn ? BUS_SRC_OPERAND8_L : + is_ld_rr_nnnn ? BUS_SRC_OPERAND8_L : + is_inc_r ? BUS_SRC_ALU : + is_dec_r ? BUS_SRC_ALU : + is_shift_r ? BUS_SRC_ALU : + is_pop_rr & is_ex2_i ? BUS_SRC_REG16_L : + is_pop_rr & is_ex3_i ? BUS_SRC_REG16_H : + is_ret & is_ex2_i ? BUS_SRC_PC_L : + is_ret & is_ex3_i ? BUS_SRC_PC_H : + BUS_SRC_MEM; + +assign bus_y_ctrl_o.dst = is_ld_sp_nnnn ? BUS_DST_SP_L : + is_ld_rr_nnnn ? BUS_DST_REG16_L : + is_inc_r ? BUS_DST_REG8 : + is_dec_r ? BUS_DST_REG8 : + is_shift_r ? BUS_DST_REG8 : + is_pop_rr & is_ex2_i ? BUS_DST_REG16_L : + is_pop_rr & is_ex3_i ? BUS_DST_REG16_H : + is_ret & is_ex2_i ? BUS_DST_PC_L : + is_ret & is_ex3_i ? BUS_DST_PC_H : + BUS_DST_REG8; +assign bus_y_ctrl_o.wen = is_ld_sp_nnnn | is_ld_rr_nnnn | (is_inc_r & reg8_dest != REG8_A) | (is_shift_r & reg8_dest != REG8_A) | (is_dec_r & reg8_dest != REG8_A) | (is_pop_rr & (is_ex2_i | is_ex3_i)) | (is_ret & (is_ex2_i | is_ex3_i)); + +assign bus_p_ctrl_o.src = is_ldd_hl_a ? BUS16_SRC_REG16 : + is_ldi_hl_a ? BUS16_SRC_REG16 : + is_call_nn ? BUS16_SRC_SP : + is_ret ? BUS16_SRC_SP : + is_push_rr ? BUS16_SRC_SP : + is_pop_rr ? BUS16_SRC_SP : + is_inc_rr & (reg16_sel == REG16_SP_AF) ? BUS16_SRC_SP : + is_inc_rr & (reg16_sel != REG16_SP_AF) ? BUS16_SRC_REG16 : + is_dec_rr & (reg16_sel == REG16_SP_AF) ? BUS16_SRC_SP : + is_dec_rr & (reg16_sel != REG16_SP_AF) ? BUS16_SRC_REG16 : + BUS16_SRC_REG16; +assign bus_p_ctrl_o.dst = BUS16_DST_ALU16; +assign bus_p_ctrl_o.wen = is_ldd_hl_a | is_ldi_hl_a | is_call_nn | is_ret | is_push_rr | is_pop_rr | is_inc_rr | is_dec_rr; + +assign bus_q_ctrl_o.src = BUS16_SRC_ALU16; +assign bus_q_ctrl_o.dst = is_ldd_hl_a ? BUS16_DST_REG16 : + is_ldi_hl_a ? BUS16_DST_REG16 : + is_call_nn ? BUS16_DST_SP : + is_ret ? BUS16_DST_SP : + is_push_rr ? BUS16_DST_SP : + is_pop_rr ? BUS16_DST_SP : + is_inc_rr & (reg16_sel == REG16_SP_AF) ? BUS16_DST_SP : + is_inc_rr & (reg16_sel != REG16_SP_AF) ? BUS16_DST_REG16 : + is_dec_rr & (reg16_sel == REG16_SP_AF) ? BUS16_DST_SP : + is_dec_rr & (reg16_sel != REG16_SP_AF) ? BUS16_DST_REG16 : + BUS16_DST_REG16; +assign bus_q_ctrl_o.wen = is_ldd_hl_a | is_ldi_hl_a | is_call_nn | (is_ret & (is_ex1_i | is_ex2_i)) | is_push_rr | (is_pop_rr & (is_ex1_i | is_ex2_i)) | is_inc_rr | is_dec_rr; + +assign reg8_src = is_ldh_c_a ? REG8_C : + is_rla ? REG8_A : + is_inc_r ? reg8_dest : + is_dec_r ? reg8_dest : + is_cb ? reg8_t'(instr_i[1][2:0]) : + reg8_t'(dec_z); + +assign reg8_dest = is_rla ? REG8_A : + is_cb ? reg8_t'(instr_i[1][2:0]) : + reg8_t'(dec_y); + +assign reg16_sel = is_ldd_hl_a ? REG16_HL : + is_ldi_hl_a ? REG16_HL : + is_ld_r_r & ((reg8_src == REG8_PHL) | (reg8_dest == REG8_PHL)) ? REG16_HL : + is_alu_a_r & (reg8_src == REG8_PHL) ? REG16_HL : + is_ld_a_pbc ? REG16_BC : + is_ld_a_pde ? REG16_DE : + reg16_t'(dec_p); + +assign reg8_src_o = reg8_src; +assign reg8_dest_o = reg8_dest; +assign reg16_sel_o = reg16_sel; + +assign alu_ctrl_o.alu_op_valid = + is_alu_a_n | + (is_alu_a_r & (reg8_src != REG8_PHL)) | + (is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i); + +assign alu_ctrl_o.alu_op = alu_op_t'(dec_y); + +assign alu_ctrl_o.shift_op_valid = is_shift_r; +assign alu_ctrl_o.shift_op = is_rla ? SHIFT_OP_RL : + shift_op_t'(instr_i[1][5:3]); + +assign alu_ctrl_o.bsr_op_valid = is_bit_n_r; +assign alu_ctrl_o.bsr_op.b = is_bit_n_r; +assign alu_ctrl_o.bsr_op.s = '0; +assign alu_ctrl_o.bsr_op.r = '0; +assign alu_ctrl_o.bsr_op.operand = instr_i[1][5:3]; + +assign alu_ctrl_o.incdec_op_valid = is_inc_r | is_dec_r; +assign alu_ctrl_o.incdec_op.inc = is_inc_r; +assign alu_ctrl_o.incdec_op.dec = is_dec_r; +assign alu_ctrl_o.incdec_op.dst_a = reg8_dest == REG8_A; + +assign alu_ctrl_o.update_a = + is_alu_a_n | + (is_alu_a_r & (reg8_src != REG8_PHL)) | + (is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i) | + (is_ld_r_n & (reg8_dest == REG8_A)) | (is_ld_r_r & (reg8_dest == REG8_A)) | + (is_inc_r & (reg8_dest == REG8_A)) | (is_dec_r & (reg8_dest == REG8_A)) | + is_ld_a_pbc | is_ld_a_pde | (is_shift_r & (reg8_dest == REG8_A)) | + is_ldh_a_n; +assign alu_ctrl_o.update_f = is_alu_a_n | is_bit_n_r | is_inc_r | is_dec_r | is_shift_r | + (is_alu_a_r & (reg8_src != REG8_PHL)) | + (is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i); + +assign alu16_inc_o = is_ldi_hl_a | is_ret | is_pop_rr | is_inc_rr; +assign alu16_dec_o = is_ldd_hl_a | is_call_nn | is_push_rr | is_dec_rr; + +assign pc_we_o = is_call_nn | (is_ret & (is_ex2_i | is_ex3_i)) | is_jr_nn; +assign pc_we_cc_o = is_jr_cc_nn; +assign cc_o = cc_t'(dec_y[1:0]); +assign pc_src_o = is_ret ? PC_SRC_BUS : + is_call_nn ? PC_SRC_OPERAND16 : + PC_SRC_OPERAND8; + +assign addr_src_o = is_ldd_hl_a ? ADDR_SRC_REG16 : + is_ldi_hl_a ? ADDR_SRC_REG16 : + is_ld_a_pbc ? ADDR_SRC_REG16 : + is_ld_a_pde ? ADDR_SRC_REG16 : + is_ldh_c_a ? ADDR_SRC_REG8 : + is_ldh_n_a ? ADDR_SRC_OPERAND8 : + is_ldh_a_n ? ADDR_SRC_OPERAND8 : + is_call_nn ? ADDR_SRC_SP : + is_ret & is_ex3_i ? ADDR_SRC_BUS_P : + is_ret ? ADDR_SRC_BUS_Q : + is_push_rr ? ADDR_SRC_SP : + is_pop_rr & is_ex3_i ? ADDR_SRC_BUS_P : + is_pop_rr ? ADDR_SRC_BUS_Q : + is_ld_r_r & ((reg8_src == REG8_PHL) | (reg8_dest == REG8_PHL)) ? ADDR_SRC_REG16 : + is_alu_a_r & (reg8_src == REG8_PHL) ? ADDR_SRC_REG16 : + is_ld_pnnnn_a ? ADDR_SRC_OPERAND16: + ADDR_SRC_PC; + +assign instr_undef_o = ~( + is_ld_sp_nnnn | is_alu_a_r | is_alu_a_n | is_ld_rr_nnnn | is_ldd_hl_a | is_ldi_hl_a | + is_bit_n_r | is_jr_nn | is_jr_cc_nn | is_ld_r_n | is_ldh_c_a | is_inc_r | is_dec_r | is_ld_r_r | + is_ldh_n_a | is_ldh_a_n | is_ld_a_pbc | is_ld_a_pde | is_call_nn | is_push_rr | is_pop_rr | + (is_shift_r & (instr_i[1][5:3] == 3'h02)) | is_rla | is_inc_rr | is_dec_rr | is_ret | + is_ld_pnnnn_a); + +endmodule : idec diff --git a/rtl/cpu/registers.sv b/rtl/cpu/regbank.sv similarity index 68% rename from rtl/cpu/registers.sv rename to rtl/cpu/regbank.sv index fff95c4..3de6da7 100644 --- a/rtl/cpu/registers.sv +++ b/rtl/cpu/regbank.sv @@ -2,9 +2,9 @@ import cpu_pkg::*; -module registers ( - input logic clk_i, - input logic nreset_i, +module regbank ( + input logic clk, + input logic nreset, input reg8_t reg8_wselect_i, input logic reg8_we_i, @@ -29,15 +29,15 @@ module registers ( 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 + always_ff @(posedge clk or negedge nreset) begin + if (!nreset) begin reg_r[i][7:0] <= '0; end else if (reg_we[i][0]) begin reg_r[i][7:0] <= reg_next[7:0]; end end - always_ff @(posedge clk_i or negedge nreset_i) begin - if (~nreset_i) begin + always_ff @(posedge clk or negedge nreset) begin + if (!nreset) begin reg_r[i][15:8] <= '0; end else if (reg_we[i][1]) begin reg_r[i][15:8] <= reg_next[15:8]; @@ -45,19 +45,38 @@ module registers ( end assign reg_we[i][0] = (reg16_we_i & (reg16_wselect_i == i[1:0])) | - (reg8_we_i & (reg8_wselect_i == {i[1:0], 1'b0})); - assign reg_we[i][1] = (reg16_we_i & (reg16_wselect_i == i[1:0])) | (reg8_we_i & (reg8_wselect_i == {i[1:0], 1'b1})); + assign reg_we[i][1] = (reg16_we_i & (reg16_wselect_i == i[1:0])) | + (reg8_we_i & (reg8_wselect_i == {i[1:0], 1'b0})); 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 reg8_rdata_o = reg8_rselect_i[0] ? reg_r[reg8_rselect_i[2:1]][ 7:0] : + reg_r[reg8_rselect_i[2:1]][15:8]; assign reg16_rdata_o = reg_r[reg16_rselect_i]; assign reg16_rdata2_o = reg_r[reg16_rselect2_i]; assign hl_o = reg_r[REG16_HL]; -endmodule : registers +`include "sva_common.svh" +`SVA_DEF_CLK(clk) +`SVA_DEF_NRESET(nreset) + +`SVA_ASSERT_PROP_FATAL(regbank_write_reg_a, + reg8_we_i |-> (reg8_wselect_i != REG8_A), + "Register bank received write to register A" +) + +`SVA_ASSERT_PROP_FATAL(regbank_write_reg_phl, + reg8_we_i |-> (reg8_wselect_i != REG8_PHL), + "Register bank received write to register (HL)" +) + +`SVA_ASSERT_PROP_FATAL(regbank_write_reg_sp_af, + reg16_we_i |-> (reg16_wselect_i != REG16_SP_AF), + "Register bank received write to register SP/AF" +) + +endmodule : regbank diff --git a/rtl/gb.sv b/rtl/gb.sv index ef34564..76f2bcb 100644 --- a/rtl/gb.sv +++ b/rtl/gb.sv @@ -1,54 +1,105 @@ +// Top level gb module module gb ( - input logic clk_i, - input logic nreset_i + input logic clk, + input logic nreset, + + // Cartridge bus + output logic cart_clk_o, + output logic cart_nreset_o, + output logic cart_nrd_o, + output logic cart_nwr_o, + output logic cart_ncs_o, + output logic [15:0] cart_addr_o, + input logic [ 7:0] cart_data_i + ); - logic we; - logic [15:0] address; - logic [ 7:0] rdata; - logic [ 7:0] wdata; +logic [15:0] cpu_addr; +logic [ 7:0] cpu_rdata; +logic cpu_we; +logic [ 7:0] cpu_wdata; - logic rom_cs; - logic [ 7:0] rom_rdata; +logic [ 7:0] cpu_ppu_rdata; - logic hi_ram_cs; - logic [ 7:0] hi_ram_rdata; +logic rom_enable_r; +logic rom_sel; +logic [ 7:0] rom_rdata; - cpu cpu_inst ( - .clk_i (clk_i), - .nreset_i (nreset_i), - .address_o(address), - .rdata_i (rdata), - .we_o (we), - .wdata_o (wdata) - ); +logic hiram_sel; +logic hiram_we; +logic [ 7:0] hiram_rdata; - rom #( - .FILE_NAME("DMG_ROM.bin"), - .ADDR_W (8), - .DATA_W (8) - ) rom_inst ( - .clk_i (clk_i), - .cs_i (rom_cs), - .address_i(address[7:0]), - .rdata_o (rom_rdata) - ); +logic vram_sel; +logic vram_we; +logic [ 7:0] vram_rdata; - ram #( - .ADDR_W (7), - .DATA_W (8) - ) hi_ram_inst ( - .clk_i (clk_i), - .cs_i (hi_ram_cs), - .address_i (address[6:0]), - .rdata_o (hi_ram_rdata), - .we_i (we), - .wdata_i (wdata) - ); +cpu cpu_inst ( + .clk (clk), + .nreset (nreset), - assign rom_cs = ~(|address[15:8]); - assign hi_ram_cs = (&address[15:7]) & ~(&address[6:0]); + .addr_o (cpu_addr), + .rdata_i(cpu_rdata), + .we_o (cpu_we), + .wdata_o(cpu_wdata) +); - assign rdata = rom_rdata | hi_ram_rdata; +ppu ppu_inst ( + .clk (clk), + .nreset (nreset), -endmodule : gb + .cpu_addr_i (cpu_addr), + .cpu_rdata_o(cpu_ppu_rdata), + .cpu_we_i (cpu_we), + .cpu_wdata_i(cpu_wdata), + .cpu_addr_sel_o(ppu_sel) +); + +assign rom_enable_r = '1; + +assign rom_sel = rom_enable_r & ~(|cpu_addr[15:8]); +assign vram_sel = (cpu_addr[15:13] == 3'b100); +assign hiram_sel = (&cpu_addr[15:7]) & ~(&cpu_addr[6:0]); + +assign vram_we = vram_sel & cpu_we; +assign hiram_we = hiram_sel & cpu_we; + +assign cpu_rdata = ({8{ rom_sel}} & rom_rdata) | + ({8{ vram_sel}} & vram_rdata) | + ({8{hiram_sel}} & hiram_rdata)| + ({8{ ppu_sel}} & cpu_ppu_rdata); + +rom #( + .FILE_NAME("DMG_ROM.bin"), + .ADDR_W (8), + .DATA_W (8) +) rom_inst ( + .clk (clk), + .address_i(cpu_addr[7:0]), + .rdata_o (rom_rdata) +); + +ram #( + .ADDR_W (13), + .DATA_W (8) +) vram_inst ( + .clk (clk), + .address_i (cpu_addr[12:0]), + .rdata_o (vram_rdata), + .we_i (vram_we), + .wdata_i (cpu_wdata) +); + +ram #( + .ADDR_W (7), + .DATA_W (8) +) hiram_inst ( + .clk (clk), + .address_i (cpu_addr[6:0]), + .rdata_o (hiram_rdata), + .we_i (hiram_we), + .wdata_i (cpu_wdata) +); + + + +endmodule : gb \ No newline at end of file diff --git a/rtl/ppu.sv b/rtl/ppu.sv new file mode 100644 index 0000000..bfa6303 --- /dev/null +++ b/rtl/ppu.sv @@ -0,0 +1,30 @@ +module ppu ( + input logic clk, + input logic nreset, + + input logic [15:0] cpu_addr_i, + output logic [ 7:0] cpu_rdata_o, + input logic cpu_we_i, + input logic [ 7:0] cpu_wdata_i, + + output logic cpu_addr_sel_o +); + +logic ly_sel; + +logic ly_r; +logic ly_we; + +assign ly_sel = (cpu_addr_i == 16'hFF44); +assign ly_we = ly_sel & cpu_we_i; + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + ly_r <= 8'h90; // vsync hack + else if (ly_we) + ly_r <= 8'h90; +end + +assign cpu_addr_sel_o = ly_sel; + +endmodule : ppu diff --git a/rtl/ram.sv b/rtl/ram.sv new file mode 100644 index 0000000..1a97f44 --- /dev/null +++ b/rtl/ram.sv @@ -0,0 +1,28 @@ +module ram #( + parameter DATA_W = 8, + parameter ADDR_W = 8 +)( + input logic clk, + + input logic [ADDR_W-1:0] address_i, + input logic we_i, + input logic [DATA_W-1:0] wdata_i, + output logic [DATA_W-1:0] rdata_o +); + +localparam RAM_SIZE = 2**ADDR_W; + +logic [DATA_W-1:0] ram [RAM_SIZE-1:0]; + +logic [DATA_W-1:0] rdata; + +always_ff @(posedge clk) + if (we_i) + ram[address_i] <= wdata_i; + +always_ff @(posedge clk) + rdata <= ram[address_i]; + +assign rdata_o = rdata; + +endmodule diff --git a/rtl/rom.sv b/rtl/rom.sv new file mode 100644 index 0000000..4ee3cae --- /dev/null +++ b/rtl/rom.sv @@ -0,0 +1,26 @@ +module rom #( + parameter string FILE_NAME = "", + parameter integer unsigned ADDR_W = 8, + parameter integer unsigned DATA_W = 8 +) ( + input logic clk, + input logic [ADDR_W-1:0] address_i, + output logic [DATA_W-1:0] rdata_o +); + +localparam ROM_SIZE = 2**ADDR_W; + +logic [DATA_W-1:0] rom [ROM_SIZE-1:0]; +logic [DATA_W-1:0] rdata; + +always_ff @(posedge clk) + rdata <= rom[address_i]; + +assign rdata_o = rdata; + +initial begin + static integer fd = $fopen(FILE_NAME, "rb"); + static integer rv = $fread(rom, fd); +end + +endmodule : rom diff --git a/rtl/shared/ram.sv b/rtl/shared/ram.sv deleted file mode 100644 index a105c69..0000000 --- a/rtl/shared/ram.sv +++ /dev/null @@ -1,34 +0,0 @@ -module ram #( - parameter DATA_W = 8, - parameter ADDR_W = 8 -)( - input logic clk_i, - - input logic cs_i, - - input logic [ADDR_W-1:0] address_i, - input logic we_i, - input logic [DATA_W-1:0] wdata_i, - output logic [DATA_W-1:0] rdata_o -); - -localparam RAM_SIZE = 2**ADDR_W; - -logic [DATA_W-1:0] ram [RAM_SIZE-1:0]; - -logic wenable; -logic [DATA_W-1:0] rdata; - -assign wenable = cs_i & we_i; - -always_ff @(posedge clk_i) - if (wenable) - ram[address_i] <= wdata_i; - -always_ff @(posedge clk_i) - if (cs_i) - rdata <= ram[address_i]; - -assign rdata_o = {DATA_W{cs_i}} & rdata; - -endmodule diff --git a/rtl/shared/rom.sv b/rtl/shared/rom.sv deleted file mode 100644 index 2a9b460..0000000 --- a/rtl/shared/rom.sv +++ /dev/null @@ -1,29 +0,0 @@ -module rom #( - parameter string FILE_NAME = "", - parameter integer unsigned ADDR_W = 8, - parameter integer unsigned DATA_W = 8 -) ( - input logic clk_i, - input logic cs_i, - input logic [ADDR_W-1:0] address_i, - - output logic [DATA_W-1:0] rdata_o -); - -localparam ROM_SIZE = 2**ADDR_W; - -logic [DATA_W-1:0] rom [ROM_SIZE-1:0]; -logic [DATA_W-1:0] rdata; - -always_ff @(posedge clk_i) - if (cs_i) - rdata <= rom[address_i]; - -assign rdata_o = {DATA_W{cs_i}} & rdata; - -initial begin - static integer fd = $fopen(FILE_NAME, "rb"); - static integer rv = $fread(rom, fd); -end - -endmodule : rom diff --git a/rtl/sva_common.svh b/rtl/sva_common.svh new file mode 100644 index 0000000..3bf180d --- /dev/null +++ b/rtl/sva_common.svh @@ -0,0 +1,39 @@ +`ifndef SVA_COMMON_SVH +`define SVA_COMMON_SVH + +`ifdef SVA_ENABLE +`define SVA_DEF_CLK(clk) \ + logic sva_clk; \ + assign sva_clk = clk; + +`define SVA_DEF_NRESET(nrst) \ + logic sva_nreset; \ + assign sva_nreset = nrst; + +`define SVA_ASSERT_PROP(label, prop, err) \ + property label``_prop; \ + @(posedge sva_clk) disable iff (!nreset) \ + (prop); \ + endproperty \ + label``_sva: assert property (label``_prop) else $display($sformatf("[%0t] %s", $time, err)); + +`define SVA_ASSERT_PROP_FATAL(label, prop, err) \ + property label``_prop; \ + @(posedge sva_clk) disable iff (!nreset) \ + (prop); \ + endproperty \ + label``_sva: assert property (label``_prop) else begin \ + $display($sformatf("[%0t] %s", $time, err)); \ + $fatal(); \ + end + +`else /* SVA_ENABLE */ + +`define SVA_DEF_CLK(clk) +`define SVA_DEF_NRESET(nrst) +`define SVA_ASSERT_PROP(label, prop, err) +`define SVA_ASSERT_PROP_FATAL(label, prop, err) + +`endif /* SVA_ENABLE */ + +`endif /* SVA_COMMON_SVH */ diff --git a/sim/clkgen.sv b/sim/clkgen.sv new file mode 100644 index 0000000..ff3acfe --- /dev/null +++ b/sim/clkgen.sv @@ -0,0 +1,18 @@ +module clkgen #( +PERIOD_NS = 10, +RESET_DELAY_NS = 45 +) ( + output logic clk, + output logic nreset +); + +initial begin + clk <= 1'b1; + nreset <= 1'b0; + #RESET_DELAY_NS nreset <= 1'b1; +end + +always + #(PERIOD_NS/2) clk <= ~clk; + +endmodule diff --git a/sim/shared/clkgen.sv b/sim/shared/clkgen.sv deleted file mode 100644 index 851d10d..0000000 --- a/sim/shared/clkgen.sv +++ /dev/null @@ -1,18 +0,0 @@ -module clkgen #( - PERIOD_NS = 10, - RESET_DELAY_NS = 100 -) ( - output logic clk_o, - output logic nreset_o -); - - initial begin - clk_o <= 1'b1; - nreset_o <= 1'b0; - #RESET_DELAY_NS nreset_o <= 1'b1; - end - - always - #(PERIOD_NS/2) clk_o <= ~clk_o; - -endmodule diff --git a/sim/tb_top.sv b/sim/tb_top.sv new file mode 100644 index 0000000..88b0ef9 --- /dev/null +++ b/sim/tb_top.sv @@ -0,0 +1,76 @@ +module tb_top; + +logic clk; +logic nreset; + +clkgen clkgen_inst ( + .clk (clk), + .nreset(nreset) +); + +gb gb_inst ( + .clk (clk), + .nreset(nreset) +); + +logic instr_valid; +logic instr_undef; +logic halted; +logic [15:0] current_pc; +logic [ 7:0] current_opcode[2:0]; + +logic we; +logic [15:0] last_write_address; +logic [ 7:0] last_write_value; + +logic vram_sel; +logic hiram_sel; + +assign halted = gb_inst.cpu_inst.ctrl_inst.halted_r; +assign instr_valid = gb_inst.cpu_inst.instr_valid; +assign instr_undef = gb_inst.cpu_inst.ctrl_inst.instr_undef; +assign current_opcode = gb_inst.cpu_inst.instr; + +assign we = gb_inst.cpu_we; + +assign vram_sel = gb_inst.vram_sel; +assign hiram_sel = gb_inst.hiram_sel; + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) + current_pc <= '0; + else if (instr_valid) + current_pc <= gb_inst.cpu_inst.pc_r; +end + +always_ff @(posedge clk or negedge nreset) begin + if (!nreset) begin + last_write_address <= '0; + last_write_value <= '0; + end else if (we) begin + last_write_address <= gb_inst.cpu_addr; + last_write_value <= gb_inst.cpu_wdata; + end +end + + +// SVA code here +`include "sva_common.svh" +`SVA_DEF_CLK(clk); +`SVA_DEF_NRESET(nreset); + +`SVA_ASSERT_PROP_FATAL(undefined_opcode_pushed, + halted |-> !instr_undef, + $sformatf("PC: 0x%X | Undefined opcode pushed: 0x%X (0x%X, 0x%X)", current_pc, current_opcode[0], current_opcode[1], current_opcode[2]) +); + +logic selected_memory_implemented; +assign selected_memory_implemented = hiram_sel | vram_sel; + +`SVA_ASSERT_PROP(write_to_unimplemented_memory, + we |-> selected_memory_implemented, + $sformatf("PC: 0x%X | Write to unimplemented memory: 0x%X <= 0x%X", + current_pc, last_write_address, last_write_value) +); + +endmodule : tb_top diff --git a/sim/tbench/tb_top.sv b/sim/tbench/tb_top.sv deleted file mode 100644 index fc82f24..0000000 --- a/sim/tbench/tb_top.sv +++ /dev/null @@ -1,50 +0,0 @@ -module tb_top (); - - logic clk; - logic nreset; - - clkgen clkgen_inst ( - .clk_o (clk), - .nreset_o(nreset) - ); - - gb gb_inst ( - .clk_i (clk), - .nreset_i(nreset) - ); - - // Testbench code - logic instr_undef; - logic halted; - logic [15:0] last_pc; - logic [ 7:0] last_opcode; - logic [ 7:0] last_op1; - logic [ 7:0] last_op2; - - 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 last_op1 = gb_inst.cpu_inst.control_inst.operand0_r; - assign last_op2 = gb_inst.cpu_inst.control_inst.operand1_r; - - assign we = gb_inst.we; - assign address = gb_inst.address; - assign wdata = gb_inst.wdata; - - always @(posedge clk) begin - if (nreset && instr_undef & ~halted) begin - $display($sformatf("[%0t] %X: Undefined opcode %X | [%X | %X]", $time(), last_pc, last_opcode, last_op1, last_op2)); - $fatal(0); - $finish(); - end - if (nreset && we) begin - $display($sformatf("[%0t] Write: [%X] <= %X", $time(), address, wdata)); - end - end - -endmodule : tb_top diff --git a/synthflow b/synthflow index 3f8450a..1486728 160000 --- a/synthflow +++ b/synthflow @@ -1 +1 @@ -Subproject commit 3f8450ac6a619226060b09f22ac5418537b40d70 +Subproject commit 1486728ced51acd63f20caf41cc47b44f2efa436