Started work on MMIO debug

This commit is contained in:
Andreas Traber 2016-04-20 10:49:48 +02:00
parent 74fed0d5ea
commit 5e30493243
8 changed files with 569 additions and 302 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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