diff --git a/controller.sv b/controller.sv index 970fe39d..cca0fe4c 100644 --- a/controller.sv +++ b/controller.sv @@ -72,15 +72,15 @@ module riscv_controller input logic exc_req_i, output logic exc_ack_o, - input logic trap_hit_i, // a trap was hit, so we have to flush EX and WB - output logic exc_save_id_o, output logic exc_restore_id_o, - // Debug Unit Signals + // Debug Signals + input logic dbg_req_i, // a trap was hit, so we have to flush EX and WB + output logic dbg_ack_o, // we stopped and give control to debug now + input logic dbg_stall_i, // Pipeline stall is requested - input logic dbg_set_npc_i, // Change PC to value from debug unit - output logic dbg_trap_o, // trap hit, inform debug unit + input logic dbg_jump_req_i, // Change PC to value from debug unit // Forwarding signals from regfile input logic [4:0] regfile_waddr_ex_i, // FW: write address from EX stage @@ -179,7 +179,7 @@ module riscv_controller halt_if_o = 1'b0; halt_id_o = 1'b0; - dbg_trap_o = 1'b0; + dbg_ack_o = 1'b0; unique case (ctrl_fsm_cs) // We were just reset, wait for fetch_enable @@ -303,7 +303,7 @@ module riscv_controller // take care of debug // branch conditional will be handled in next state - if (trap_hit_i) + if (dbg_req_i) begin // halt pipeline immediately halt_if_o = 1'b1; @@ -332,7 +332,7 @@ module riscv_controller // if we want to debug, flush the pipeline // the current_pc_if will take the value of the next instruction to // be executed (NPC) - if (trap_hit_i) + if (dbg_req_i) begin ctrl_fsm_ns = DBG_SIGNAL; end @@ -357,7 +357,7 @@ module riscv_controller // can examine our current state DBG_SIGNAL: begin - dbg_trap_o = 1'b1; + dbg_ack_o = 1'b1; halt_if_o = 1'b1; ctrl_fsm_ns = DBG_WAIT; @@ -369,13 +369,13 @@ module riscv_controller begin halt_if_o = 1'b1; - if(dbg_set_npc_i == 1'b1) begin + if (dbg_jump_req_i) begin pc_mux_o = `PC_DBG_NPC; pc_set_o = 1'b1; ctrl_fsm_ns = DBG_WAIT; end - if(dbg_stall_i == 1'b0) begin + if (dbg_stall_i == 1'b0) begin ctrl_fsm_ns = DECODE; end end @@ -385,7 +385,7 @@ module riscv_controller begin halt_if_o = 1'b1; - if(ex_valid_i) + if (ex_valid_i) ctrl_fsm_ns = FLUSH_WB; end diff --git a/debug_unit.sv b/debug_unit.sv index 96343bbb..3875a839 100644 --- a/debug_unit.sv +++ b/debug_unit.sv @@ -1,7 +1,7 @@ -// Copyright 2015 ETH Zurich and University of Bologna. +// Copyright 2016 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the “License”); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at +// compliance with the License. You may obtain a copy of the License at // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law // or agreed to in writing, software, hardware and materials distributed under // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR @@ -9,11 +9,7 @@ // specific language governing permissions and limitations under the License. //////////////////////////////////////////////////////////////////////////////// -// Engineer: Florian Glaser - glaserf@ethz.ch // -// // -// Additional contributions by: // -// Andreas Traber - atraber@student.ethz.ch // -// Sven Stucki - svstucki@student.ethz.ch // +// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch // // // // Design Name: Debug Unit // // Project Name: RI5CY // @@ -31,31 +27,42 @@ module riscv_debug_unit input logic clk, input logic rst_n, - // signals to Debug Interface - input logic dbginf_stall_i, - output logic dbginf_bp_o, - input logic dbginf_strobe_i, - output logic dbginf_ack_o, - input logic dbginf_we_i, - input logic [15:0] dbginf_addr_i, - input logic [31:0] dbginf_data_i, - output logic [31:0] dbginf_data_o, + // Debug Interface + input logic debug_req_i, + output logic debug_gnt_o, + output logic debug_rvalid_o, + input logic [14:0] debug_addr_i, + input logic debug_we_i, + input logic [31:0] debug_wdata_i, + output logic [31:0] debug_rdata_o, + output logic debug_halted_o, + input logic debug_halt_i, // signals to core - output logic dbg_step_en_o, // Single-step trace mode enabled - output logic [1:0] dbg_dsr_o, // debug stop register + output logic [`DBG_SETS_W-1:0] settings_o, - output logic stall_core_o, - output logic stop_req_o, - input logic trap_i, + input logic trap_i, // trap found, need to stop the core now + output logic stall_o, // after we got control, we control the stall signal + output logic dbg_req_o, + input logic dbg_ack_i, - output logic sp_mux_o, - output logic regfile_mux_o, - output logic regfile_we_o, - output logic [11:0] regfile_addr_o, - output logic [31:0] regfile_wdata_o, + // register file read port + output logic regfile_rreq_o, + output logic [ 4:0] regfile_raddr_o, input logic [31:0] regfile_rdata_i, + // register file write port + output logic regfile_wreq_o, + output logic [ 4:0] regfile_waddr_o, + output logic [31:0] regfile_wdata_o, + + // CSR read/write port + output logic csr_req_o, + output logic [11:0] csr_addr_o, + output logic csr_we_o, + output logic [31:0] csr_wdata_o, + input logic [31:0] csr_rdata_i, + // Signals for PPC & NPC register input logic [31:0] curr_pc_if_i, input logic [31:0] curr_pc_id_i, @@ -64,158 +71,328 @@ module riscv_debug_unit input logic branch_in_ex_i, input logic branch_taken_i, - output logic [31:0] npc_o, - output logic set_npc_o + output logic jump_req_o, + output logic [31:0] jump_addr_o ); + enum logic [2:0] {RD_NONE, RD_CSR, RD_GPR, RD_DBGA, RD_DBGS} rdata_sel_q, rdata_sel_n; - // registers for debug control - logic [1:0] dsr_q, dsr_n; // Debug Stop Register: IIE, INTE - logic [1:0] dmr1_q, dmr1_n; // only single step trace and branch trace bits + enum logic [0:0] {FIRST, SECOND} state_q, state_n; + + logic [`DBG_SETS_W-1:0] settings_q, settings_n; + + // for timing critical register file access we need to keep those in FFs + logic [14:0] addr_q; + logic [31:0] wdata_q; // mainly for jumps + logic regfile_rreq_q, regfile_rreq_n; + logic jump_req_q, jump_req_n; + + // not timing critical + logic csr_req_q, csr_req_n; + logic regfile_wreq; + + + enum logic [1:0] {RUNNING, HALT_REQ, HALT} stall_cs, stall_ns; + logic [31:0] dbg_rdata; + logic dbg_resume; + logic dbg_halt; - // BP control FSM - enum logic [1:0] {Idle, Trap, DebugStall, StallCore} bp_fsm_cs, bp_fsm_ns; // ppc/npc tracking enum logic [1:0] {IFID, IFEX, IDEX} pc_tracking_fsm_cs, pc_tracking_fsm_ns; logic [31:0] ppc_int, npc_int; - // ack to debug interface - assign dbginf_ack_o = dbginf_strobe_i && ((bp_fsm_cs == StallCore) || (dbginf_addr_i[15:11] == 5'b00110)); - - - always_comb - begin - bp_fsm_ns = bp_fsm_cs; - stall_core_o = 1'b0; - dbginf_bp_o = 1'b0; - stop_req_o = 1'b0; - - case (bp_fsm_cs) - Idle: - begin - if(trap_i == 1'b1) - begin - dbginf_bp_o = 1'b1; - stall_core_o = 1'b1; - bp_fsm_ns = StallCore; - end - else if(dbginf_stall_i) - begin - stop_req_o = 1'b1; - bp_fsm_ns = DebugStall; - end - end - - // A stall from adv dbg unit was seen, flush the pipeline and wait for unstalling - DebugStall: - begin - stop_req_o = 1'b1; - - if(trap_i == 1'b1) - begin - stall_core_o = 1'b1; - bp_fsm_ns = StallCore; - end - end - - StallCore: - begin - stall_core_o = 1'b1; - - if(~dbginf_stall_i) - bp_fsm_ns = Idle; - end - - default: bp_fsm_ns = Idle; - endcase // case (bp_fsm_cs) - end - - - // data to GPRs and SPRs - assign regfile_wdata_o = dbginf_data_i; - - assign dbg_step_en_o = dmr1_q[0]; - assign dbg_dsr_o = dsr_q; - - assign npc_o = dbginf_data_i; - // address decoding, write and read controller always_comb begin - dmr1_n = dmr1_q; - dsr_n = dsr_q; - dbginf_data_o = 32'b0; - regfile_we_o = 1'b0; - regfile_addr_o = '0; - regfile_mux_o = 1'b0; - sp_mux_o = 1'b0; - set_npc_o = 1'b0; + rdata_sel_n = RD_NONE; + state_n = FIRST; - if(dbginf_strobe_i == 1'b1) begin - // address decoding, first stage: evaluate higher 5 Bits to detect if debug regs are accessed - if(dbginf_addr_i[15:11] == 5'b00110) begin - // second stage: evaluate Bits 10:0 to detect which part of debug registers is accessed - case (dbginf_addr_i[10:0]) - 11'd0: begin // NPC - set_npc_o = dbginf_we_i; + debug_gnt_o = 1'b0; - dbginf_data_o = npc_int; + regfile_rreq_n = 1'b0; + regfile_wreq = 1'b0; + csr_req_n = 1'b0; + csr_we_o = 1'b0; + jump_req_n = 1'b0; + + dbg_resume = 1'b0; + dbg_halt = 1'b0; + settings_n = settings_q; + + if (debug_req_i) begin + if (debug_we_i) begin + //---------------------------------------------------------------------------- + // write access + //---------------------------------------------------------------------------- + if (debug_addr_i[14]) begin + // CSR access + if (state_q == FIRST) begin + // only grant in second cycle, address and data have been latched by then + debug_gnt_o = 1'b1; // grant it even when invalid access to not block + state_n = SECOND; + + if (debug_halted_o) begin + // access to internal registers are only allowed when the core is halted + csr_req_n = 1'b1; + end + end else begin + state_n = FIRST; + csr_we_o = 1'b1; end + end else begin + // non-CSR access + unique case (debug_addr_i[13:8]) + 6'b00_0000: begin // Debug Registers, always accessible + debug_gnt_o = 1'b1; - 11'd1: begin // PPC - dbginf_data_o = ppc_int; - end + unique case (debug_addr_i[6:2]) + 5'b0_0000: begin // DBG_CTRL + // RESUME takes precedence over HALT + if (debug_wdata_i[31]) begin + // RESUME set + if (debug_halted_o) begin + dbg_resume = 1'b1; + end + end else if (debug_wdata_i[16]) begin + // HALT set + if (~debug_halted_o) begin + // not halt, so STOP + dbg_halt = 1'b1; + end + end + settings_n[`DBG_SETS_SSTE] = debug_wdata_i[0]; + end + 5'b0_0001: begin // DBG_HIT + if (debug_wdata_i[0]) begin + // TODO: clear SSTH sticky bit + end + end + 5'b0_0010: begin // DBG_IE + settings_n[`DBG_SETS_ECALL] = debug_wdata_i[11]; + settings_n[`DBG_SETS_ELSU] = debug_wdata_i[7] | debug_wdata_i[5]; + settings_n[`DBG_SETS_EBRK] = debug_wdata_i[3]; + settings_n[`DBG_SETS_EILL] = debug_wdata_i[2]; + end + default:; + endcase + end - 11'd16: begin // SP_DMR1 - if(dbginf_we_i == 1'b1) - dmr1_n = dbginf_data_i[`DMR1_ST+1:`DMR1_ST]; - else - dbginf_data_o[`DMR1_ST+1:`DMR1_ST] = dmr1_q; - end + 6'b01_0010: begin // Debug Registers, only accessible when in debug + debug_gnt_o = 1'b1; // grant it even when invalid access to not block - 11'd20: begin // SP_DSR - // currently we only handle IIE and INTE - if(dbginf_we_i == 1'b1) - dsr_n = dbginf_data_i[7:6]; - else - dbginf_data_o[7:6] = dsr_q[1:0]; - end + if (debug_halted_o) begin + unique case (debug_addr_i[6:2]) + 5'b0_0001: jump_req_n = 1'b1; // DNPC + default:; + endcase + end + end - default: ; - endcase - end - // check if internal registers (GPR or SPR) are accessed - else if(bp_fsm_cs == StallCore) - begin - // check if GPRs are accessed - if(dbginf_addr_i[15:10] == 6'b000001) - begin - regfile_mux_o = 1'b1; - regfile_addr_o[4:0] = dbginf_addr_i[4:0]; + 6'b01_0000: begin // General-Purpose Registers + debug_gnt_o = 1'b1; // grant it even when invalid access to not block - if(dbginf_we_i == 1'b1) - regfile_we_o = 1'b1; - else - dbginf_data_o = regfile_rdata_i; + if (debug_halted_o) begin + regfile_wreq = 1'b1; + end + end + + default:; + endcase end - // some other SPR is accessed - else - begin - sp_mux_o = 1'b1; - regfile_addr_o = dbginf_addr_i[11:0]; + end else begin + //---------------------------------------------------------------------------- + // read access + //---------------------------------------------------------------------------- + if (debug_addr_i[14]) begin + debug_gnt_o = 1'b1; // grant it even when invalid access to not block - if(dbginf_we_i == 1'b1) - regfile_we_o = 1'b1; - else - dbginf_data_o = regfile_rdata_i; + // CSR access + if (debug_halted_o) begin + // access to internal registers are only allowed when the core is halted + csr_req_n = 1'b1; + rdata_sel_n = RD_CSR; + end + end else begin + // non-CSR access + unique case (debug_addr_i[13:8]) + 6'b00_0000: begin // Debug Registers, always accessible + debug_gnt_o = 1'b1; + + rdata_sel_n = RD_DBGA; + end + + 6'b01_0010: begin // Debug Registers, only accessible when in debug + debug_gnt_o = 1'b1; // grant it even when invalid access to not block + + if (debug_halted_o) begin + rdata_sel_n = RD_DBGS; + end + end + + 6'b01_0000: begin // General-Purpose Registers + debug_gnt_o = 1'b1; // grant it even when invalid access to not block + + if (debug_halted_o) begin + regfile_rreq_n = 1'b1; + rdata_sel_n = RD_GPR; + end + end + + default:; + endcase end end end end + //---------------------------------------------------------------------------- + // debug register read access + // + // Since those are combinational, we can do it in the cycle where we set + // rvalid. The address has been latched into addr_q + //---------------------------------------------------------------------------- + always_comb + begin + dbg_rdata = '0; + case (rdata_sel_q) + RD_DBGA: begin + unique case (addr_q[6:2]) + 5'h00: dbg_rdata[31:0] = {31'b0, settings_q[`DBG_SETS_SSTE]}; // DBG_CTRL + 5'h01: dbg_rdata[31:0] = {15'b0, debug_halted_o, 16'b0}; // DBG_HIT, TODO: SSTH is missing + 5'h02: begin // DBG_IE + dbg_rdata[31:16] = '0; + dbg_rdata[15:12] = '0; + dbg_rdata[11] = settings_q[`DBG_SETS_ECALL]; + dbg_rdata[10: 8] = '0; + dbg_rdata[ 7] = settings_q[`DBG_SETS_ELSU]; + dbg_rdata[ 6] = 1'b0; + dbg_rdata[ 5] = settings_q[`DBG_SETS_ELSU]; + dbg_rdata[ 4] = 1'b0; + dbg_rdata[ 3] = settings_q[`DBG_SETS_EBRK]; + dbg_rdata[ 2] = settings_q[`DBG_SETS_EILL]; + dbg_rdata[ 1: 0] = '0; + end + 5'h03: dbg_rdata = '1; // DBG_CAUSE. TODO: maybe take from exc controller directly? + 5'h10: dbg_rdata = '0; // DBG_BPCTRL0 + 5'h12: dbg_rdata = '0; // DBG_BPCTRL1 + 5'h14: dbg_rdata = '0; // DBG_BPCTRL2 + 5'h16: dbg_rdata = '0; // DBG_BPCTRL3 + 5'h18: dbg_rdata = '0; // DBG_BPCTRL4 + 5'h1A: dbg_rdata = '0; // DBG_BPCTRL5 + 5'h1C: dbg_rdata = '0; // DBG_BPCTRL6 + 5'h1E: dbg_rdata = '0; // DBG_BPCTRL7 + default:; + endcase + end + + RD_DBGS: begin + unique case (debug_addr_i[2:2]) + 1'b0: dbg_rdata = npc_int; // DBG_NPC + 1'b1: dbg_rdata = ppc_int; // DBG_PPC + default:; + endcase + end + + default:; + endcase + end + + //---------------------------------------------------------------------------- + // read data mux + //---------------------------------------------------------------------------- + always_comb + begin + debug_rdata_o = '0; + + case (rdata_sel_q) + RD_CSR: debug_rdata_o = csr_rdata_i; + RD_GPR: debug_rdata_o = regfile_rdata_i; + RD_DBGA: debug_rdata_o = dbg_rdata; + RD_DBGS: debug_rdata_o = dbg_rdata; + endcase + end + + //---------------------------------------------------------------------------- + // rvalid generation + //---------------------------------------------------------------------------- + always_ff @(posedge clk, negedge rst_n) + begin + if (~rst_n) begin + debug_rvalid_o <= 1'b0; + end else begin + debug_rvalid_o <= debug_gnt_o; // always give the rvalid one cycle after gnt + end + end + + //---------------------------------------------------------------------------- + // stall control + //---------------------------------------------------------------------------- + always_comb + begin + stall_ns = stall_cs; + dbg_req_o = 1'b0; + stall_o = 1'b0; + debug_halted_o = 1'b0; + + case (stall_cs) + RUNNING: begin + if (dbg_halt) + stall_ns = HALT_REQ; + end + + HALT_REQ: begin + dbg_req_o = 1'b1; + + if (dbg_ack_i) // TODO: check if we need to set stall already + stall_ns = HALT; + + if (dbg_resume) + stall_ns = RUNNING; + end + + HALT: begin + stall_o = 1'b1; + debug_halted_o = 1'b1; + + if (dbg_resume) + stall_ns = RUNNING; + end + endcase + + // if a trap is found, halt immediately + if (trap_i) begin + dbg_req_o = 1'b1; + stall_ns = HALT; + end + end + + always_ff @(posedge clk, negedge rst_n) + begin + if (~rst_n) begin + stall_cs <= RUNNING; + end else begin + stall_cs <= stall_ns; + end + end + + //---------------------------------------------------------------------------- + // rvalid generation + //---------------------------------------------------------------------------- + always_ff @(posedge clk, negedge rst_n) + begin + if (~rst_n) begin + debug_rvalid_o <= 1'b0; + end else begin + debug_rvalid_o <= debug_gnt_o; // always give the rvalid one cycle after gnt + end + end + + //---------------------------------------------------------------------------- + // NPC/PPC selection + //---------------------------------------------------------------------------- always_comb begin pc_tracking_fsm_ns = pc_tracking_fsm_cs; @@ -239,7 +416,7 @@ module riscv_debug_unit ppc_int = branch_pc_i; npc_int = curr_pc_id_i; - if (set_npc_o) + if (jump_req_o) pc_tracking_fsm_ns = IFEX; end @@ -249,7 +426,7 @@ module riscv_debug_unit endcase // set state if trap is encountered - if (stall_core_o && (bp_fsm_cs != StallCore)) begin + if (dbg_ack_i) begin pc_tracking_fsm_ns = IFID; if (branch_in_ex_i) begin @@ -262,20 +439,74 @@ module riscv_debug_unit end - always_ff@(posedge clk, negedge rst_n) + always_ff @(posedge clk, negedge rst_n) begin - if (rst_n == 1'b0) begin - dmr1_q <= '0; - dsr_q <= '0; - bp_fsm_cs <= Idle; + if (~rst_n) begin pc_tracking_fsm_cs <= IFID; - end - else begin - dmr1_q <= dmr1_n; - dsr_q <= dsr_n; - bp_fsm_cs <= bp_fsm_ns; + + addr_q <= '0; + wdata_q <= '0; + state_q <= FIRST; + rdata_sel_q <= RD_NONE; + regfile_rreq_q <= 1'b0; + csr_req_q <= 1'b0; + jump_req_q <= 1'b0; + + settings_q <= 1'b0; + end else begin pc_tracking_fsm_cs <= pc_tracking_fsm_ns; + + // settings + settings_q <= settings_n; + + // for the actual interface + if (debug_req_i) begin + addr_q <= debug_addr_i; + wdata_q <= debug_wdata_i; + state_q <= FIRST; + end + + if (debug_req_i | debug_rvalid_o) begin + // wait for either req or rvalid to set those FFs + // This makes sure that they are only triggered once when there is + // only one request, and the FFs can be properly clock gated otherwise + regfile_rreq_q <= regfile_rreq_n; + csr_req_q <= csr_req_n; + jump_req_q <= jump_req_n; + rdata_sel_q <= rdata_sel_n; + end end end + assign regfile_rreq_o = regfile_rreq_q; + assign regfile_raddr_o = addr_q[6:2]; + + assign regfile_wreq_o = regfile_wreq; + assign regfile_waddr_o = debug_addr_i[6:2]; + assign regfile_wdata_o = debug_wdata_i; + + assign csr_req_o = csr_req_q; + assign csr_addr_o = addr_q[13:2]; + assign csr_wdata_o = wdata_q; + + assign jump_req_o = jump_req_q; + assign jump_addr_o = wdata_q; + + assign settings_o = settings_q; + + //---------------------------------------------------------------------------- + // Assertions + //---------------------------------------------------------------------------- + + // check that no registers are accessed when we are not in debug mode + assert property ( + @(posedge clk) (debug_req_i) |-> ((debug_halted_o == 1'b1) || + ((debug_addr_i[14] != 1'b1) && + (debug_addr_i[13:7] != 5'b0_1001) && + (debug_addr_i[13:7] != 5'b0_1000)) ) ); + + // check that all accesses are word-aligned + assert property ( + @(posedge clk) (debug_req_i) |-> (debug_addr_i[1:0] == 2'b00) ); + endmodule // debug_unit diff --git a/decoder.sv b/decoder.sv index 39fe71cc..040f8b8b 100644 --- a/decoder.sv +++ b/decoder.sv @@ -34,7 +34,7 @@ module riscv_decoder input logic mult_multicycle_i, // multiplier taking multiple cycles, using op c as storage output logic illegal_insn_o, // illegal instruction encountered - output logic trap_insn_o, // trap instruction encountered + output logic ebrk_insn_o, // trap instruction encountered output logic eret_insn_o, // return from exception instruction encountered output logic ecall_insn_o, // environment call (syscall) instruction encountered output logic pipe_flush_o, // pipeline flush is requested @@ -107,7 +107,7 @@ module riscv_decoder logic data_req; logic [2:0] hwloop_we; - logic trap_insn; + logic ebrk_insn; logic eret_insn; logic pipe_flush; @@ -170,7 +170,7 @@ module riscv_decoder data_load_event_o = 1'b0; illegal_insn_o = 1'b0; - trap_insn = 1'b0; + ebrk_insn = 1'b0; eret_insn = 1'b0; ecall_insn_o = 1'b0; pipe_flush = 1'b0; @@ -831,7 +831,7 @@ module riscv_decoder 32'h00_10_00_73: // ebreak begin // debugger trap - trap_insn = 1'b1; + ebrk_insn = 1'b1; end 32'h10_00_00_73: // eret @@ -980,7 +980,7 @@ module riscv_decoder assign hwloop_we_o = (deassert_we_i) ? 3'b0 : hwloop_we; assign csr_op_o = (deassert_we_i) ? `CSR_OP_NONE : csr_op; assign jump_in_id_o = (deassert_we_i) ? `BRANCH_NONE : jump_in_id; - assign trap_insn_o = (deassert_we_i) ? 1'b0 : trap_insn; + assign ebrk_insn_o = (deassert_we_i) ? 1'b0 : ebrk_insn; assign eret_insn_o = (deassert_we_i) ? 1'b0 : eret_insn; // TODO: do not deassert? assign pipe_flush_o = (deassert_we_i) ? 1'b0 : pipe_flush; // TODO: do not deassert? diff --git a/exc_controller.sv b/exc_controller.sv index e2f3518b..6f794489 100644 --- a/exc_controller.sv +++ b/exc_controller.sv @@ -34,7 +34,7 @@ module riscv_exc_controller output logic req_o, input logic ack_i, - output logic trap_hit_o, + output logic trap_o, // to IF stage output logic [1:0] pc_mux_o, // selects target PC for exception @@ -45,7 +45,7 @@ module riscv_exc_controller input logic irq_enable_i, // interrupt enable bit from CSR // from decoder - input logic trap_insn_i, // trap instruction encountered (EBREAK) + input logic ebrk_insn_i, // ebrk instruction encountered (EBREAK) input logic illegal_insn_i, // illegal instruction encountered input logic ecall_insn_i, // ecall instruction encountered input logic eret_insn_i, // eret instruction encountered @@ -58,9 +58,7 @@ module riscv_exc_controller output logic save_cause_o, // from debug unit - input logic dbg_stop_req_i, - input logic dbg_step_en_i, - input logic [1:0] dbg_dsr_i + input logic [`DBG_SETS_W-1:0] dbg_settings_i ); @@ -80,18 +78,20 @@ module riscv_exc_controller // - illegal instruction exception and IIE bit is set // - IRQ and INTE bit is set and no exception is currently running // - Debuger requests halt - assign trap_hit_o = trap_insn_i - | dbg_stop_req_i - | dbg_step_en_i - | (illegal_insn_i & dbg_dsr_i[`DSR_IIE]) - | (irq_enable_i & (|irq_i) & dbg_dsr_i[`DSR_INTE]); + assign trap_o = (dbg_settings_i[`DBG_SETS_SSTE]) + | (ecall_insn_i & dbg_settings_i[`DBG_SETS_ECALL]) + | (lsu_load_err_i & dbg_settings_i[`DBG_SETS_ELSU]) + | (lsu_store_err_i & dbg_settings_i[`DBG_SETS_ELSU]) + | (ebrk_insn_i & dbg_settings_i[`DBG_SETS_EBRK]) + | (illegal_insn_i & dbg_settings_i[`DBG_SETS_EILL]) + | (irq_enable_i & (|irq_i) & dbg_settings_i[`DBG_SETS_IRQ]); // request for exception/interrupt - assign req_int = ecall_insn_i - | lsu_load_err_i - | lsu_store_err_i - | (illegal_insn_i & (~dbg_dsr_i[`DSR_IIE])) - | (irq_enable_i & (|irq_i) & (~dbg_dsr_i[`DSR_INTE])); + assign req_int = (ecall_insn_i & (~dbg_settings_i[`DBG_SETS_ECALL])) + | (lsu_load_err_i & (~dbg_settings_i[`DBG_SETS_ELSU])) + | (lsu_store_err_i & (~dbg_settings_i[`DBG_SETS_ELSU])) + | (illegal_insn_i & (~dbg_settings_i[`DBG_SETS_EILL])) + | (irq_enable_i & (|irq_i) & (~dbg_settings_i[`DBG_SETS_IRQ])); // Exception cause and ISR address selection @@ -100,10 +100,10 @@ module riscv_exc_controller cause_int = 6'b0; pc_mux_int = 'x; - if (irq_enable_i & (~dbg_dsr_i[`DSR_INTE])) begin + if (irq_enable_i & (~dbg_settings_i[`DBG_SETS_IRQ])) begin // pc_mux_int is a critical signal, so try to get it as soon as possible if (|irq_i) - pc_mux_int = `EXC_PC_IRQ; + pc_mux_int = `EXC_PC_IRQ; for (i = 31; i >= 0; i--) begin @@ -119,17 +119,17 @@ module riscv_exc_controller pc_mux_int = `EXC_PC_ECALL; end - if (illegal_insn_i & (~dbg_dsr_i[`DSR_IIE])) begin + if (illegal_insn_i & (~dbg_settings_i[`DBG_SETS_EILL])) begin cause_int = 6'b0_00010; pc_mux_int = `EXC_PC_ILLINSN; end - if (lsu_load_err_i) begin + if (lsu_load_err_i & (~dbg_settings_i[`DBG_SETS_ELSU])) begin cause_int = 6'b0_00101; pc_mux_int = `EXC_PC_LOAD; end - if (lsu_store_err_i) begin + if (lsu_store_err_i & (~dbg_settings_i[`DBG_SETS_ELSU])) begin cause_int = 6'b0_00111; pc_mux_int = `EXC_PC_STORE; end diff --git a/id_stage.sv b/id_stage.sv index 0fb8562b..2d48e458 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -159,17 +159,21 @@ module riscv_id_stage input logic lsu_store_err_i, // Debug Unit Signals - input logic dbg_stop_req_i, - input logic dbg_step_en_i, - input logic [1:0] dbg_dsr_i, + input logic [`DBG_SETS_W-1:0] dbg_settings_i, + input logic dbg_req_i, + output logic dbg_ack_o, input logic dbg_stall_i, output logic dbg_trap_o, - input logic dbg_reg_mux_i, - input logic dbg_reg_we_i, - input logic [4:0] dbg_reg_addr_i, - input logic [31:0] dbg_reg_wdata_i, + + input logic dbg_reg_rreq_i, + input logic [ 4:0] dbg_reg_raddr_i, output logic [31:0] dbg_reg_rdata_o, - input logic dbg_set_npc_i, + + input logic dbg_reg_wreq_i, + input logic [ 4:0] dbg_reg_waddr_i, + input logic [31:0] dbg_reg_wdata_i, + + input logic dbg_jump_req_i, // Forward Signals input logic [4:0] regfile_waddr_wb_i, @@ -195,7 +199,7 @@ module riscv_id_stage logic deassert_we; logic illegal_insn_dec; - logic trap_insn; + logic ebrk_insn; logic eret_insn_dec; logic ecall_insn_dec; logic pipe_flush_dec; @@ -241,8 +245,6 @@ module riscv_id_stage // Signals running between controller and exception controller logic exc_req, exc_ack; // handshake - logic trap_hit; - // Register file interface logic [4:0] regfile_addr_ra_id; logic [4:0] regfile_addr_rb_id; @@ -693,7 +695,7 @@ module riscv_id_stage .rdata_b_o ( regfile_data_rb_id ), // Read port c - .raddr_c_i ( (dbg_reg_mux_i == 1'b0) ? regfile_addr_rc_id : dbg_reg_addr_i ), + .raddr_c_i ( (dbg_reg_rreq_i == 1'b0) ? regfile_addr_rc_id : dbg_reg_raddr_i ), .rdata_c_o ( regfile_data_rc_id ), // Write port a @@ -702,9 +704,9 @@ module riscv_id_stage .we_a_i ( regfile_we_wb_i ), // Write port b - .waddr_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_waddr_fw_i : dbg_reg_addr_i ), - .wdata_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_wdata_fw_i : dbg_reg_wdata_i ), - .we_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_we_fw_i : dbg_reg_we_i ) + .waddr_b_i ( (dbg_reg_wreq_i == 1'b0) ? regfile_alu_waddr_fw_i : dbg_reg_waddr_i ), + .wdata_b_i ( (dbg_reg_wreq_i == 1'b0) ? regfile_alu_wdata_fw_i : dbg_reg_wdata_i ), + .we_b_i ( (dbg_reg_wreq_i == 1'b0) ? regfile_alu_we_fw_i : 1'b1 ) ); assign dbg_reg_rdata_o = regfile_data_rc_id; @@ -727,7 +729,7 @@ module riscv_id_stage .mult_multicycle_i ( mult_multicycle_i ), .illegal_insn_o ( illegal_insn_dec ), - .trap_insn_o ( trap_insn ), + .ebrk_insn_o ( ebrk_insn ), .eret_insn_o ( eret_insn_dec ), .ecall_insn_o ( ecall_insn_dec ), .pipe_flush_o ( pipe_flush_dec ), @@ -849,15 +851,15 @@ module riscv_id_stage // Exception Controller Signals .exc_req_i ( exc_req ), .exc_ack_o ( exc_ack ), - .trap_hit_i ( trap_hit ), .exc_save_id_o ( exc_save_id_o ), .exc_restore_id_o ( exc_restore_id_o ), // Debug Unit Signals + .dbg_req_i ( dbg_req_i ), + .dbg_ack_o ( dbg_ack_o ), .dbg_stall_i ( dbg_stall_i ), - .dbg_set_npc_i ( dbg_set_npc_i ), - .dbg_trap_o ( dbg_trap_o ), + .dbg_jump_req_i ( dbg_jump_req_i ), // Forwarding signals from regfile .regfile_waddr_ex_i ( regfile_waddr_ex_o ), // Write address for register file from ex-wb- pipeline registers @@ -922,7 +924,7 @@ module riscv_id_stage .req_o ( exc_req ), .ack_i ( exc_ack ), - .trap_hit_o ( trap_hit ), + .trap_o ( dbg_trap_o ), // to IF stage .pc_mux_o ( exc_pc_mux_o ), @@ -932,7 +934,7 @@ module riscv_id_stage .irq_i ( irq_i ), .irq_enable_i ( irq_enable_i ), - .trap_insn_i ( is_decoding_o & trap_insn ), + .ebrk_insn_i ( is_decoding_o & ebrk_insn ), .illegal_insn_i ( is_decoding_o & illegal_insn_dec ), .ecall_insn_i ( is_decoding_o & ecall_insn_dec ), .eret_insn_i ( is_decoding_o & eret_insn_dec ), @@ -943,10 +945,7 @@ module riscv_id_stage .cause_o ( exc_cause_o ), .save_cause_o ( save_exc_cause_o ), - // Debug Signals - .dbg_stop_req_i ( dbg_stop_req_i ), - .dbg_step_en_i ( dbg_step_en_i ), - .dbg_dsr_i ( dbg_dsr_i ) + .dbg_settings_i ( dbg_settings_i ) ); diff --git a/if_stage.sv b/if_stage.sv index 11159090..fd85ad98 100644 --- a/if_stage.sv +++ b/if_stage.sv @@ -78,8 +78,8 @@ module riscv_if_stage input logic [N_HWLP-1:0] [31:0] hwlp_cnt_i, // hardware loop counters // from debug unit - input logic [31:0] dbg_npc_i, - input logic dbg_set_npc_i, + input logic [31:0] dbg_jump_addr_i, + input logic dbg_jump_req_i, // pipeline stall input logic halt_if_i, @@ -143,7 +143,7 @@ module riscv_if_stage `PC_BRANCH: fetch_addr_n = jump_target_ex_i; `PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler `PC_ERET: fetch_addr_n = exception_pc_reg_i; // PC is restored when returning from IRQ/exception - `PC_DBG_NPC: fetch_addr_n = dbg_npc_i; // PC is taken from debug unit + `PC_DBG_NPC: fetch_addr_n = dbg_jump_addr_i; // PC is taken from debug unit default:; endcase diff --git a/include/riscv_defines.sv b/include/riscv_defines.sv index 727ccbb0..68cae473 100644 --- a/include/riscv_defines.sv +++ b/include/riscv_defines.sv @@ -318,10 +318,14 @@ // Debug module -`define DMR1_ST 22 +`define DBG_SETS_W 6 -`define DSR_IIE 0 -`define DSR_INTE 1 +`define DBG_SETS_IRQ 5 +`define DBG_SETS_ECALL 4 +`define DBG_SETS_EILL 3 +`define DBG_SETS_ELSU 2 +`define DBG_SETS_EBRK 1 +`define DBG_SETS_SSTE 0 `endif diff --git a/riscv_core.sv b/riscv_core.sv index f8a48165..6db93f6e 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -34,9 +34,10 @@ module riscv_core ) ( // Clock and Reset - input logic clk, - input logic rst_n, + input logic clk_i, + input logic rst_ni, + input logic clock_en_i, // enable clock, otherwise it is gated input logic test_en_i, // enable all clock gates for testing // Core ID, Cluster ID and boot address are considered more or less static @@ -66,14 +67,15 @@ module riscv_core input logic [31:0] irq_i, // level sensitive IR lines // Debug Interface - input logic dbginf_stall_i, - output logic dbginf_bp_o, - input logic dbginf_strobe_i, - output logic dbginf_ack_o, - input logic dbginf_we_i, - input logic [15:0] dbginf_addr_i, - input logic [31:0] dbginf_data_i, - output logic [31:0] dbginf_data_o, + input logic debug_req_i, + output logic debug_gnt_o, + output logic debug_rvalid_o, + input logic [14:0] debug_addr_i, + input logic debug_we_i, + input logic [31:0] debug_wdata_i, + output logic [31:0] debug_rdata_o, + output logic debug_halted_o, + input logic debug_halt_i, // CPU Control Signals input logic fetch_enable_i, @@ -85,7 +87,6 @@ module riscv_core localparam N_HWLP = 2; localparam N_HWLP_BITS = $clog2(N_HWLP); - // IF/ID signals logic is_hwlp_id; logic [N_HWLP-1:0] hwlp_dec_cnt_id; @@ -223,22 +224,30 @@ module riscv_core // Debug Unit + logic [`DBG_SETS_W-1:0] dbg_settings; + logic dbg_req; + logic dbg_ack; logic dbg_stall; - logic dbg_stop_req; logic dbg_trap; - logic dbg_step_en; // single-step trace mode enabled - logic [1:0] dbg_dsr; // Debug Stop Register - logic dbg_reg_mux; - logic dbg_sp_mux; - logic dbg_reg_we; - logic [11:0] dbg_reg_addr; - logic [31:0] dbg_reg_wdata; + // Debug GPR Read Access + logic dbg_reg_rreq; + logic [ 4:0] dbg_reg_raddr; logic [31:0] dbg_reg_rdata; - logic [31:0] dbg_rdata; - logic [31:0] dbg_npc; - logic dbg_set_npc; + // Debug GPR Write Access + logic dbg_reg_wreq; + logic [ 4:0] dbg_reg_waddr; + logic [31:0] dbg_reg_wdata; + + // Debug CSR Access + logic dbg_csr_req; + logic [11:0] dbg_csr_addr; + logic dbg_csr_we; + logic [31:0] dbg_csr_wdata; + + logic [31:0] dbg_jump_addr; + logic dbg_jump_req; // Performance Counters logic perf_imiss; @@ -246,12 +255,25 @@ module riscv_core logic perf_jr_stall; logic perf_ld_stall; + logic clk; + // if we are sleeping on a barrier let's just wait on the instruction // interface to finish loading instructions assign core_busy_o = (data_load_event_ex && data_req_o) ? if_busy : (if_busy || core_busy || lsu_busy); + // main clock gate of the core + // generates all clocks except the one for the debug unit which is + // independent + cluster_clock_gating core_clock_gate_i + ( + .clk_i ( clk_i ), + .en_i ( clock_en_i ), + .test_en_i ( test_en_i ), + .clk_o ( clk ) + ); + ////////////////////////////////////////////////// // ___ _____ ____ _____ _ ____ _____ // // |_ _| ___| / ___|_ _|/ \ / ___| ____| // @@ -268,7 +290,7 @@ module riscv_core if_stage_i ( .clk ( clk ), - .rst_n ( rst_n ), + .rst_n ( rst_ni ), // boot address (trap vector location) .boot_addr_i ( boot_addr_i ), @@ -307,8 +329,8 @@ module riscv_core .hwlp_cnt_i ( hwlp_cnt ), // from debug unit - .dbg_npc_i ( dbg_npc ), - .dbg_set_npc_i ( dbg_set_npc ), + .dbg_jump_addr_i ( dbg_jump_addr ), + .dbg_jump_req_i ( dbg_jump_req ), // Jump targets .jump_target_id_i ( jump_target_id ), @@ -340,7 +362,7 @@ module riscv_core id_stage_i ( .clk ( clk ), - .rst_n ( rst_n ), + .rst_n ( rst_ni ), .test_en_i ( test_en_i ), @@ -458,17 +480,21 @@ module riscv_core .lsu_store_err_i ( lsu_store_err ), // Debug Unit Signals - .dbg_stop_req_i ( dbg_stop_req ), - .dbg_step_en_i ( dbg_step_en ), - .dbg_dsr_i ( dbg_dsr ), + .dbg_settings_i ( dbg_settings ), + .dbg_req_i ( dbg_req ), + .dbg_ack_o ( dbg_ack ), .dbg_stall_i ( dbg_stall ), .dbg_trap_o ( dbg_trap ), - .dbg_reg_mux_i ( dbg_reg_mux ), - .dbg_reg_we_i ( dbg_reg_we ), - .dbg_reg_addr_i ( dbg_reg_addr[4:0] ), - .dbg_reg_wdata_i ( dbg_reg_wdata ), + + .dbg_reg_rreq_i ( dbg_reg_rreq ), + .dbg_reg_raddr_i ( dbg_reg_raddr ), .dbg_reg_rdata_o ( dbg_reg_rdata ), - .dbg_set_npc_i ( dbg_set_npc ), + + .dbg_reg_wreq_i ( dbg_reg_wreq ), + .dbg_reg_waddr_i ( dbg_reg_waddr ), + .dbg_reg_wdata_i ( dbg_reg_wdata ), + + .dbg_jump_req_i ( dbg_jump_req ), // Forward Signals .regfile_waddr_wb_i ( regfile_waddr_fw_wb_o), // Write address ex-wb pipeline @@ -501,7 +527,7 @@ module riscv_core ( // Global signals: Clock and active low asynchronous reset .clk ( clk ), - .rst_n ( rst_n ), + .rst_n ( rst_ni ), // Alu signals from ID stage .alu_operator_i ( alu_operator_ex ), // from ID/EX pipe registers @@ -575,7 +601,7 @@ module riscv_core riscv_load_store_unit load_store_unit_i ( .clk ( clk ), - .rst_n ( rst_n ), + .rst_n ( rst_ni ), //output to data memory .data_req_o ( data_req_o ), @@ -637,14 +663,14 @@ module riscv_core cs_registers_i ( .clk ( clk ), - .rst_n ( rst_n ), + .rst_n ( rst_ni ), // Core and Cluster ID from outside .core_id_i ( core_id_i ), .cluster_id_i ( cluster_id_i ), // Interface to CSRs (SRAM like) - .csr_access_i ( csr_access_ex ), + .csr_access_i ( csr_access ), .csr_addr_i ( csr_addr ), .csr_wdata_i ( csr_wdata ), .csr_op_i ( csr_op ), @@ -692,14 +718,12 @@ module riscv_core ); // Mux for CSR access through Debug Unit - assign csr_access = (dbg_sp_mux == 1'b0) ? csr_access_ex : 1'b1; - assign csr_addr = (dbg_sp_mux == 1'b0) ? csr_addr_int : dbg_reg_addr; - assign csr_wdata = (dbg_sp_mux == 1'b0) ? alu_operand_a_ex : dbg_reg_wdata; - assign csr_op = (dbg_sp_mux == 1'b0) ? csr_op_ex - : (dbg_reg_we == 1'b1 ? `CSR_OP_WRITE - : `CSR_OP_NONE ); - assign dbg_rdata = (dbg_sp_mux == 1'b0) ? dbg_reg_rdata : csr_rdata; - + assign csr_access = (dbg_csr_req == 1'b0) ? csr_access_ex : 1'b1; + assign csr_addr = (dbg_csr_req == 1'b0) ? csr_addr_int : dbg_csr_addr; + assign csr_wdata = (dbg_csr_req == 1'b0) ? alu_operand_a_ex : dbg_csr_wdata; + assign csr_op = (dbg_csr_req == 1'b0) ? csr_op_ex + : (dbg_csr_we == 1'b1 ? `CSR_OP_WRITE + : `CSR_OP_NONE ); assign csr_addr_int = csr_access_ex ? alu_operand_b_ex[11:0] : '0; @@ -714,34 +738,43 @@ module riscv_core riscv_debug_unit debug_unit_i ( - .clk ( clk ), - .rst_n ( rst_n ), + .clk ( clk_i ), // always-running clock for debug + .rst_n ( rst_ni ), // Debug Interface - .dbginf_stall_i ( dbginf_stall_i ), - .dbginf_bp_o ( dbginf_bp_o ), - .dbginf_strobe_i ( dbginf_strobe_i ), - .dbginf_ack_o ( dbginf_ack_o ), - .dbginf_we_i ( dbginf_we_i ), - .dbginf_addr_i ( dbginf_addr_i ), - .dbginf_data_i ( dbginf_data_i ), - .dbginf_data_o ( dbginf_data_o ), + .debug_req_i ( debug_req_i ), + .debug_gnt_o ( debug_gnt_o ), + .debug_rvalid_o ( debug_rvalid_o ), + .debug_addr_i ( debug_addr_i ), + .debug_we_i ( debug_we_i ), + .debug_wdata_i ( debug_wdata_i ), + .debug_rdata_o ( debug_rdata_o ), + .debug_halt_i ( debug_halt_i ), + .debug_halted_o ( debug_halted_o ), // To/From Core - .dbg_step_en_o ( dbg_step_en ), - .dbg_dsr_o ( dbg_dsr ), - - .stall_core_o ( dbg_stall ), - .stop_req_o ( dbg_stop_req ), + .settings_o ( dbg_settings ), + .stall_o ( dbg_stall ), + .dbg_req_o ( dbg_req ), + .dbg_ack_i ( dbg_ack ), .trap_i ( dbg_trap ), - // register file access - .sp_mux_o ( dbg_sp_mux ), - .regfile_mux_o ( dbg_reg_mux ), - .regfile_we_o ( dbg_reg_we ), - .regfile_addr_o ( dbg_reg_addr ), + // register file read port + .regfile_rreq_o ( dbg_reg_rreq ), + .regfile_raddr_o ( dbg_reg_raddr ), + .regfile_rdata_i ( dbg_reg_rdata ), + + // register file write port + .regfile_wreq_o ( dbg_reg_wreq ), + .regfile_waddr_o ( dbg_reg_waddr ), .regfile_wdata_o ( dbg_reg_wdata ), - .regfile_rdata_i ( dbg_rdata ), + + // CSR read/write port + .csr_req_o ( dbg_csr_req ), + .csr_addr_o ( dbg_csr_addr ), + .csr_we_o ( dbg_csr_we ), + .csr_wdata_o ( dbg_csr_wdata ), + .csr_rdata_i ( csr_rdata ), // signals for PPC and NPC .curr_pc_if_i ( pc_if ), // from IF stage @@ -751,16 +784,16 @@ module riscv_core .branch_in_ex_i ( branch_in_ex ), .branch_taken_i ( branch_decision ), - .npc_o ( dbg_npc ), // PC from debug unit - .set_npc_o ( dbg_set_npc ) // set PC to new value + .jump_addr_o ( dbg_jump_addr ), // PC from debug unit + .jump_req_o ( dbg_jump_req ) // set PC to new value ); `ifdef TRACE_EXECUTION riscv_tracer riscv_tracer_i ( - .clk ( clk ), - .rst_n ( rst_n ), + .clk ( clk_i ), // always-running clock for tracing + .rst_n ( rst_ni ), .fetch_enable ( fetch_enable_i ), .core_id ( core_id_i ), @@ -817,8 +850,8 @@ module riscv_core riscv_simchecker riscv_simchecker_i ( - .clk ( clk ), - .rst_n ( rst_n ), + .clk ( clk_i ), // always-running clock for tracing + .rst_n ( rst_ni ), .fetch_enable ( fetch_enable_i ), .boot_addr ( boot_addr_i ),