Merge branch 'debug'

This commit is contained in:
Florian Zaruba 2017-07-19 16:47:07 +02:00
commit 0e0dfce0ff
11 changed files with 552 additions and 75 deletions

View file

@ -302,4 +302,21 @@ package ariane_pkg;
csr_addr_t csr_decode;
} csr_t;
// ----------------------
// Debug Unit
// ----------------------
typedef enum logic [14:0] {
DBG_CTRL = 15'h0,
DBG_HIT = 15'h4,
DBG_IE = 15'h8,
DBG_CAUSE = 15'hC,
DBG_BPCTRL = 15'b????000,
DBG_BPDATA = 15'b?????00,
DBG_GPR = 15'h4??,
DBG_CSR = 15'h5??,
DBG_NPC = 15'h2000,
DBG_PPC = 15'h2004
} debug_reg_t;
endpackage

View file

@ -237,6 +237,23 @@ module ariane
logic halt_ctrl_commit;
logic halt_debug_ctrl;
logic halt_csr_ctrl;
// --------------
// Debug <-> *
// --------------
logic [63:0] pc_debug_pcgen;
logic set_pc_debug;
logic gpr_req_debug_issue;
logic [4:0] gpr_addr_debug_issue;
logic gpr_we_debug_issue;
logic [63:0] gpr_wdata_debug_issue;
logic [63:0] gpr_rdata_debug_issue;
logic csr_req_debug_csr;
logic [11:0] csr_addr_debug_csr;
logic csr_we_debug_csr;
logic [63:0] csr_wdata_debug_csr;
logic [63:0] csr_rdata_debug_csr;
assign sec_lvl_o = priv_lvl;
// --------------
@ -257,6 +274,8 @@ module ariane
.eret_i ( eret ),
.trap_vector_base_i ( trap_vector_base_commit_pcgen ),
.ex_valid_i ( ex_commit.valid ),
.debug_pc_i ( pc_debug_pcgen ),
.debug_set_pc_i ( set_pc_debug ),
.*
);
// ---------
@ -312,58 +331,62 @@ module ariane
// ---------
// Issue
// ---------
issue_stage
#(
issue_stage #(
.NR_ENTRIES ( NR_SB_ENTRIES ),
.NR_WB_PORTS ( NR_WB_PORTS )
)
issue_stage_i (
.flush_unissued_instr_i ( flush_unissued_instr_ctrl_id ),
.flush_i ( flush_ctrl_id ),
) issue_stage_i (
.flush_unissued_instr_i ( flush_unissued_instr_ctrl_id ),
.flush_i ( flush_ctrl_id ),
// Debug
.debug_gpr_req_i ( gpr_req_debug_issue ),
.debug_gpr_addr_i ( gpr_addr_debug_issue ),
.debug_gpr_we_i ( gpr_we_debug_issue ),
.debug_gpr_wdata_i ( gpr_wdata_debug_issue ),
.debug_gpr_rdata_o ( gpr_rdata_debug_issue ),
.decoded_instr_i ( issue_entry_id_issue ),
.decoded_instr_valid_i ( issue_entry_valid_id_issue ),
.is_ctrl_flow_i ( is_ctrl_fow_id_issue ),
.decoded_instr_ack_o ( issue_instr_issue_id ),
.decoded_instr_i ( issue_entry_id_issue ),
.decoded_instr_valid_i ( issue_entry_valid_id_issue ),
.is_ctrl_flow_i ( is_ctrl_fow_id_issue ),
.decoded_instr_ack_o ( issue_instr_issue_id ),
// Functional Units
.fu_o ( fu_id_ex ),
.operator_o ( operator_id_ex ),
.operand_a_o ( operand_a_id_ex ),
.operand_b_o ( operand_b_id_ex ),
.imm_o ( imm_id_ex ),
.trans_id_o ( trans_id_id_ex ),
.pc_o ( pc_id_ex ),
.is_compressed_instr_o ( is_compressed_instr_id_ex ),
.fu_o ( fu_id_ex ),
.operator_o ( operator_id_ex ),
.operand_a_o ( operand_a_id_ex ),
.operand_b_o ( operand_b_id_ex ),
.imm_o ( imm_id_ex ),
.trans_id_o ( trans_id_id_ex ),
.pc_o ( pc_id_ex ),
.is_compressed_instr_o ( is_compressed_instr_id_ex ),
// ALU
.alu_ready_i ( alu_ready_ex_id ),
.alu_valid_o ( alu_valid_id_ex ),
.alu_ready_i ( alu_ready_ex_id ),
.alu_valid_o ( alu_valid_id_ex ),
// Branches and Jumps
.branch_ready_i ( branch_ready_ex_id ),
.branch_valid_o ( branch_valid_id_ex ), // branch is valid
.branch_predict_o ( branch_predict_id_ex ), // branch predict to ex
.resolve_branch_i ( resolve_branch_ex_id ), // in order to resolve the branch
.branch_ready_i ( branch_ready_ex_id ),
.branch_valid_o ( branch_valid_id_ex ), // branch is valid
.branch_predict_o ( branch_predict_id_ex ), // branch predict to ex
.resolve_branch_i ( resolve_branch_ex_id ), // in order to resolve the branch
// LSU
.lsu_ready_i ( lsu_ready_ex_id ),
.lsu_valid_o ( lsu_valid_id_ex ),
.lsu_ready_i ( lsu_ready_ex_id ),
.lsu_valid_o ( lsu_valid_id_ex ),
// Multiplier
.mult_ready_i ( mult_ready_ex_id ),
.mult_valid_o ( mult_valid_id_ex ),
.mult_ready_i ( mult_ready_ex_id ),
.mult_valid_o ( mult_valid_id_ex ),
// CSR
.csr_ready_i ( csr_ready_ex_id ),
.csr_valid_o ( csr_valid_id_ex ),
.csr_ready_i ( csr_ready_ex_id ),
.csr_valid_o ( csr_valid_id_ex ),
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, branch_trans_id_ex_id, csr_trans_id_ex_id }),
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, branch_result_ex_id, csr_result_ex_id }),
.ex_ex_i ( {{$bits(exception){1'b0}}, lsu_exception_ex_id, branch_exception_ex_id, {$bits(exception){1'b0}} }),
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, branch_valid_ex_id, csr_valid_ex_id }),
.waddr_a_i ( waddr_a_commit_id ),
.wdata_a_i ( wdata_a_commit_id ),
.we_a_i ( we_a_commit_id ),
.waddr_a_i ( waddr_a_commit_id ),
.wdata_a_i ( wdata_a_commit_id ),
.we_a_i ( we_a_commit_id ),
.commit_instr_o ( commit_instr_id_commit ),
.commit_ack_i ( commit_ack ),
.commit_instr_o ( commit_instr_id_commit ),
.commit_ack_i ( commit_ack ),
.*
);
@ -470,6 +493,11 @@ module ariane
csr_regfile_i (
.flush_o ( flush_csr_ctrl ),
.halt_csr_o ( halt_csr_ctrl ),
.debug_csr_req_i ( csr_req_debug_csr ),
.debug_csr_addr_i ( csr_addr_debug_csr ),
.debug_csr_we_i ( csr_we_debug_csr ),
.debug_csr_wdata_i ( csr_wdata_debug_csr ),
.debug_csr_rdata_o ( csr_rdata_debug_csr ),
.commit_ack_i ( commit_ack ),
.ex_i ( ex_commit ),
.csr_op_i ( csr_op_commit_csr ),
@ -509,7 +537,8 @@ module ariane
.flush_tlb_o ( flush_tlb_ctrl_ex ),
.halt_csr_i ( halt_csr_ctrl ),
.halt_debug_i ( 1'b0 ),
.halt_debug_i ( halt_debug_ctrl ),
.debug_set_pc_i ( set_pc_debug ),
.halt_o ( halt_ctrl_commit ),
// control ports
.eret_i ( eret ),
@ -522,6 +551,33 @@ module ariane
.*
);
// ------------
// Debug
// ------------
debug_unit debug_unit_i (
.commit_instr_i ( commit_instr_id_commit ),
.commit_ack_i ( commit_ack ),
.ex_i ( ex_commit ),
.halt_o ( halt_debug_ctrl ),
.debug_pc_o ( pc_debug_pcgen ),
.debug_set_pc_o ( set_pc_debug ),
.debug_gpr_req_o ( gpr_req_debug_issue ),
.debug_gpr_addr_o ( gpr_addr_debug_issue ),
.debug_gpr_we_o ( gpr_we_debug_issue ),
.debug_gpr_wdata_o ( gpr_wdata_debug_issue ),
.debug_gpr_rdata_i ( gpr_rdata_debug_issue ),
.debug_csr_req_o ( csr_req_debug_csr ),
.debug_csr_addr_o ( csr_addr_debug_csr ),
.debug_csr_we_o ( csr_we_debug_csr ),
.debug_csr_wdata_o ( csr_wdata_debug_csr ),
.debug_csr_rdata_i ( csr_rdata_debug_csr ),
.*
);
// -------------------
// Instruction Tracer
// -------------------

View file

@ -151,5 +151,9 @@ module commit_stage (
exception_o = csr_exception_i;
exception_o.tval = commit_instr_i.ex.tval;
end
// If we halted the processor don't take any exceptions
if (halt_i) begin
exception_o.valid = 1'b0;
end
end
endmodule

View file

@ -31,6 +31,7 @@ module controller (
input logic halt_csr_i, // Halt request from CSR (WFI instruction)
input logic halt_debug_i, // Halt request from debug
input logic debug_set_pc_i, // Debug wants to set the PC
output logic halt_o, // Halt signal to commit stage
input logic eret_i, // Return from exception
input logic ex_valid_i, // We got an exception, flush the pipeline
@ -64,13 +65,13 @@ module controller (
flush_if_o = 1'b1;
end
// ----------------------
// ---------------------------------
// FENCE
// ----------------------
// ---------------------------------
// ----------------------
// ---------------------------------
// FENCE.I
// ----------------------
// ---------------------------------
if (fence_i_i) begin
flush_pcgen_o = 1'b1;
flush_if_o = 1'b1;
@ -79,9 +80,9 @@ module controller (
flush_ex_o = 1'b1;
flush_icache_o = 1'b1;
end
// ----------------------
// ---------------------------------
// SFENCE.VMA
// ----------------------
// ---------------------------------
if (sfence_vma_i) begin
flush_pcgen_o = 1'b1;
flush_if_o = 1'b1;
@ -102,10 +103,12 @@ module controller (
flush_ex_o = 1'b1;
end
// ------------
// Exception
// ------------
if (ex_valid_i) begin
// ---------------------------------
// 1. Exception
// 2. Return from exception
// 3. Debug
// ---------------------------------
if (ex_valid_i || eret_i || debug_set_pc_i) begin
// don't flush pcgen as we want to take the exception, flush pcgen is not a flush signal
// for the PC GEN stage but instead tells it to take the PC we gave it
flush_pcgen_o = 1'b0;
@ -114,19 +117,6 @@ module controller (
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
// ----------------------
// Return from exception
// ----------------------
if (eret_i) begin
// don't flush pcgen as we want to take the exception
flush_pcgen_o = 1'b0;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
end
// ----------------------

View file

@ -21,7 +21,7 @@ import ariane_pkg::*;
module csr_regfile #(
parameter int ASID_WIDTH = 1
)(
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic [63:0] time_i, // Platform Timer
@ -30,6 +30,12 @@ module csr_regfile #(
// send a flush request out if a CSR with a side effect has changed (e.g. written)
output logic flush_o,
output logic halt_csr_o, // halt requested
// Debug CSR Port
input logic debug_csr_req_i, // Request from debug to read the CSR regfile
input logic [11:0] debug_csr_addr_i, // Address of CSR
input logic debug_csr_we_i, // Is it a read or write?
input logic [63:0] debug_csr_wdata_i, // Data to write
output logic [63:0] debug_csr_rdata_o, // Read data
// commit acknowledge
input logic commit_ack_i, // Commit acknowledged a instruction -> increase instret CSR
// Core and Cluster ID
@ -68,13 +74,6 @@ module csr_regfile #(
output logic tsr_o // trap sret
// Performance Counter
);
logic mret; // return from M-mode exception
logic sret; // return from S-mode exception
csr_t csr_addr;
assign csr_addr = csr_t'(csr_addr_i);
// internal signal to keep track of access exceptions
logic read_access_exception, update_access_exception;
logic csr_we, csr_read;
@ -83,6 +82,18 @@ module csr_regfile #(
// register for enabling load store address translation, this is critical, hence the register
logic en_ld_st_translation_n, en_ld_st_translation_q;
logic mret; // return from M-mode exception
logic sret; // return from S-mode exception
csr_t csr_addr;
// ----------------
// Assignments
// ----------------
// Debug MUX
assign csr_addr = csr_t'(((debug_csr_req_i) ? debug_csr_addr_i : csr_addr_i));
// Output the read data directly
assign debug_csr_rdata_o = csr_rdata;
// ----------------
// CSR Registers
// ----------------
@ -431,7 +442,6 @@ module csr_regfile #(
// CSR OP Select Logic
// ---------------------------
always_comb begin : csr_op_logic
csr_wdata = csr_wdata_i;
csr_we = 1'b1;
csr_read = 1'b1;
@ -460,6 +470,16 @@ module csr_regfile #(
csr_read = 1'b0;
end
endcase
// ------------------------------
// Debug Multiplexer (Priority)
// ------------------------------
if (debug_csr_req_i) begin
// Use the data supplied by the debug unit
csr_wdata = debug_csr_wdata_i;
csr_we = debug_csr_we_i;
csr_read = ~debug_csr_we_i;
end
end
logic interrupt_global_enable;

348
src/debug_unit.sv Executable file
View file

@ -0,0 +1,348 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.06.2017
// Description: Memory Mapped Debug Unit
//
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
//
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
//
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
//
import ariane_pkg::*;
module debug_unit (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input scoreboard_entry commit_instr_i,
input logic commit_ack_i,
input exception ex_i, // instruction caused an exception
output logic halt_o, // halt the hart
// GPR interface
output logic debug_gpr_req_o,
output logic [4:0] debug_gpr_addr_o,
output logic debug_gpr_we_o,
output logic [63:0] debug_gpr_wdata_o,
input logic [63:0] debug_gpr_rdata_i,
// CSR interface
output logic debug_csr_req_o,
output logic [11:0] debug_csr_addr_o,
output logic debug_csr_we_o,
output logic [63:0] debug_csr_wdata_o,
input logic [63:0] debug_csr_rdata_i,
// CPU Control
output logic [63:0] debug_pc_o,
output logic debug_set_pc_o,
// HWPB
// External 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 [63:0] debug_wdata_i,
output logic [63:0] debug_rdata_o,
output logic debug_halted_o,
input logic debug_halt_i,
input logic debug_resume_i
);
// Debugger State
enum logic [1:0] {RUNNING, HALT_REQ, SINGLE_STEP, HALTED} CS, NS;
// debug interface registers, we need to give the read data back one cycle later along with the rvalid flag
logic rvalid_n, rvalid_q;
logic rdata_n, rdata_q;
// save previous PC
logic dbg_ppc_n, dbg_ppc_q;
// ---------------
// Debug Register
// ---------------
// enable exceptions which will cause a transfer to the debug mode
logic [63:0] dbg_ie_n, dbg_ie_q;
// cause register which caused transfer to debug mode
logic [63:0] dbg_cause_n, dbg_cause_q;
// single step mode
logic dbg_ss_n, dbg_ss_q;
logic [63:0] dbg_hit_n, dbg_hit_q;
// hardware breakpoints
logic [7:0][3:0] dbg_hwbp_ctrl_n, dbg_hwbp_ctrl_q;
logic [7:0][63:0] dbg_hwbp_data_n, dbg_hwbp_data_q;
// ----------------------
// Debug Control Signals
// ----------------------
// change debug mode
logic halt_req, resume_req;
logic stepped_single;
// assigns, we can output a couple of signals directly
assign debug_rvalid_o = rvalid_q;
assign debug_rdata_o = rdata_q;
assign debug_halted_o = (CS == HALTED);
// | Address | Name | Description |
// |---------------|-----------------|---------------------------------------------------------------------|
// | 0x0000-0x007F | Debug Registers | Always accessible, even when the core is running |
// | 0x0400-0x047F | GPR (x0-x31) | General Purpose Registers. Only accessible if the core is halted. |
// | 0x0500-0x05FF | FPR (f0-f31) | Reserved. Not used in the Ariane. |
// | 0x2000-0x20FF | Debug Registers | Only accessible if the core is halted |
// | 0x4000-0x7FFF | CSR | Control and Status Registers. Only accessible if the core is halted |
always_comb begin : debug_ctrl
debug_gnt_o = 1'b0;
rdata_n = 'b0;
rvalid_n = 1'b0;
halt_req = 1'b0;
resume_req = 1'b0;
// update the previous PC if got a valid commit
dbg_ppc_n = (commit_ack_i) ? commit_instr_i.pc : dbg_ppc_q;
// debug registers
dbg_ie_n = dbg_ie_q;
dbg_cause_n = dbg_cause_q;
dbg_ss_n = dbg_ss_q;
dbg_hit_n = dbg_hit_q;
dbg_hwbp_ctrl_n = dbg_hwbp_ctrl_q;
dbg_hwbp_data_n = dbg_hwbp_data_q;
// GPR defaults
debug_gpr_req_o = 1'b0;
debug_gpr_addr_o = debug_addr_i[6:2];
debug_gpr_we_o = 1'b0;
debug_gpr_wdata_o = 64'b0;
// CSR defaults
debug_csr_req_o = 1'b0;
debug_csr_addr_o = debug_addr_i[13:2];
debug_csr_we_o = 1'b0;
debug_csr_wdata_o = 64'b0;
// change ctrl flow
debug_pc_o = 64'b0;
debug_set_pc_o = 1'b0;
// we did one single step, set the sticky bit
if (stepped_single)
dbg_hit_n = 1'b1;
// ----------
// Read
// ----------
// we've got a new read request
if (debug_req_i && !debug_we_i) begin
// we can immediately grant the request
debug_gnt_o = 1'b1;
// decode debug address
casez (debug_addr_i)
DBG_CTRL: rdata_n = {32'b0, 15'b0, debug_halted_o, 15'b0, dbg_ss_q};
DBG_HIT: rdata_n = {63'b0, dbg_hit_q};
DBG_IE: rdata_n = dbg_ie_q;
DBG_CAUSE: rdata_n = dbg_cause_q;
DBG_NPC: begin
if (debug_halted_o)
rdata_n = commit_instr_i.pc;
end
DBG_PPC: begin
if (debug_halted_o)
rdata_n = dbg_ppc_q;
end
// all breakpoints are implemented
DBG_BPCTRL: rdata_n = {57'b0, dbg_hwbp_ctrl_q[debug_addr_i[5:3]], 2'b0, 1'b1};
DBG_BPDATA: rdata_n = dbg_hwbp_data_q[debug_addr_i[5:3]];
DBG_GPR: begin
if (debug_halted_o) begin
debug_gpr_req_o = 1'b1;
rdata_n = debug_gpr_rdata_i;
end
end
DBG_CSR: begin
if (debug_halted_o) begin
debug_csr_req_o = 1'b1;
rdata_n = debug_csr_rdata_i;
end
end
endcase
// ----------
// Write
// ----------
end else if (debug_req_i) begin
// we can also immediately grant
debug_gnt_o = 1'b1;
// decode debug address
casez (debug_addr_i)
DBG_CTRL: begin
// check if requested a halt
halt_req = debug_wdata_i[16];
resume_req = ~debug_wdata_i[16];
// enable/disable single step
dbg_ss_n = debug_wdata_i[0];
end
DBG_HIT: dbg_hit_n = {debug_wdata_i[15:8], debug_wdata_i[0]};
DBG_IE: dbg_ie_n = debug_wdata_i;
DBG_CAUSE: dbg_cause_n = debug_wdata_i;
DBG_NPC: begin
if (debug_halted_o) begin
// Change CTRL Flow to debug PC
debug_pc_o = debug_wdata_i;
debug_set_pc_o = 1'b1;
end
end
// PPC is read-only
DBG_PPC:;
// Only triggering on instruction fetch is allowed at the moment
DBG_BPCTRL: dbg_hwbp_ctrl_n[debug_addr_i[5:3]] = {3'b0, debug_wdata_i[1]};
DBG_BPDATA: dbg_hwbp_data_n[debug_addr_i[5:3]] = debug_wdata_i;
DBG_GPR: begin
if (debug_halted_o) begin
debug_gpr_req_o = 1'b1;
debug_gpr_we_o = 1'b1;
debug_gpr_wdata_o = debug_wdata_i;
end
end
DBG_CSR: begin
if (debug_halted_o) begin
debug_csr_req_o = 1'b1;
debug_csr_we_o = 1'b1;
debug_csr_wdata_o = debug_wdata_i;
end
end
endcase
end
// if an exception occurred and it is enabled to trigger debug mode, halt the processor and enter debug mode
if (ex_i.valid && (|(ex_i.cause & dbg_ie_q)) == 1'b1) begin
halt_req = 1'b1;
// save the cause why we entered the exception
dbg_cause_n = ex_i.cause;
end
// --------------------
// HW Breakpoints
// --------------------
// check all possible breakpoints
for (logic [7:0] i = 0; i < 8; i++) begin
// check if a breakpoint is triggering, therefore check if it is enabled
if (dbg_hwbp_ctrl_q[i][0]) begin
// check if the PC is matching and the processor is currently retiring the instruction
if (commit_instr_i.pc == dbg_hwbp_data_q[i] && commit_ack_i) begin
halt_req = 1'b1;
dbg_hit_n[15:8] = i;
end
end
end
end
// --------------------
// Stall Control
// --------------------
always_comb begin
NS = CS;
// do not halt by default
halt_o = 1'b0;
stepped_single = 1'b0;
case (CS)
// CPU is running normally
RUNNING: begin
// 1. external debugger requested to halt the CPU
// 2. cross-trigger requested a halt
// 3. a break-point hit
if (halt_req || debug_halt_i) begin
NS = HALT_REQ;
end
end
// a halt was requested, we wait here until we get the next valid instruction
// in order to properly populate the NPC and PPC registers
HALT_REQ: begin
halt_o = 1'b1;
// we've got a valid instruction in the commit stage so we can proceed to the halted state
if (commit_instr_i.valid) begin
NS = HALTED;
end
end
// we are in single step mode
SINGLE_STEP: begin
// wait until the processor has acknowledge the instruction in the commit stage
if (commit_ack_i) begin
// then halt again
NS = HALT_REQ;
// we did one single step assert the flag so that we can set the sticky bit
stepped_single = 1'b1;
end
end
// CPU is halted, we are in debug mode
HALTED: begin
halt_o = 1'b1;
if (resume_req || debug_resume_i)
NS = RUNNING;
// resume from single step, check if single stepping is enabled and if the sticky bit is cleared
if (dbg_ss_q && !dbg_hit_q) begin
NS = SINGLE_STEP;
end
end
endcase
end
// --------------------
// Registers
// --------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
CS <= RUNNING;
rdata_q <= '0;
rvalid_q <= 1'b0;
dbg_ppc_q <= 64'b0;
dbg_ie_q <= 64'b0;
dbg_cause_q <= 64'b0;
dbg_hwbp_ctrl_q <= '0;
dbg_hwbp_data_q <= '0;
dbg_ss_q <= 1'b0;
dbg_hit_q <= 1'b0;
end else begin
CS <= NS;
rdata_q <= rdata_n;
rvalid_q <= rvalid_n;
dbg_ppc_q <= dbg_ppc_n;
dbg_ie_q <= dbg_ie_n;
dbg_cause_q <= dbg_cause_n;
dbg_ss_q <= dbg_ss_n;
dbg_hit_q <= dbg_hit_n;
dbg_hwbp_ctrl_q <= dbg_hwbp_ctrl_n;
dbg_hwbp_data_q <= dbg_hwbp_data_n;
end
end
//--------------
// Assertions
//--------------
`ifndef SYNTHESIS
`ifndef VERILATOR
// check that no registers are accessed when we are not in debug mode
assert property (
@(posedge clk_i) (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)) ) )
else $warning("Trying to access internal debug registers while core is not stalled");
// check that all accesses are word-aligned
assert property (
@(posedge clk_i) (debug_req_i) |-> (debug_addr_i[1:0] == 2'b00) );
`endif
`endif
endmodule

View file

@ -247,4 +247,4 @@ module if_stage (
else $warning("There was a grant without a request");
`endif
`endif
endmodule
endmodule

View file

@ -25,6 +25,12 @@ module issue_read_operands (
input logic test_en_i,
// flush
input logic flush_i,
// coming from Debug
input logic debug_gpr_req_i,
input logic [4:0] debug_gpr_addr_i,
input logic debug_gpr_we_i,
input logic [63:0] debug_gpr_wdata_i,
output logic [63:0] debug_gpr_rdata_o,
// coming from scoreboard
input scoreboard_entry issue_instr_i,
input logic issue_instr_valid_i,
@ -274,6 +280,31 @@ module issue_read_operands (
end
end
// --------------------
// Debug Multiplexers
// --------------------
logic [4:0] raddr_a, waddr;
logic [63:0] wdata;
logic we;
always_comb begin
// get the address from the issue stage by default
// read port
debug_gpr_rdata_o = operand_a_regfile;
raddr_a = issue_instr_i.rs1;
// write port
waddr = waddr_a_i;
wdata = wdata_a_i;
we = we_a_i;
// we've got a debug request in
if (debug_gpr_req_i) begin
raddr_a = debug_gpr_addr_i;
waddr = debug_gpr_addr_i;
wdata = debug_gpr_wdata_i;
we = debug_gpr_we_i;
end
end
// ----------------------
// Integer Register File
// ----------------------
@ -286,15 +317,15 @@ module issue_read_operands (
.rst_n ( rst_ni ),
.test_en_i ( test_en_i ),
.raddr_a_i ( issue_instr_i.rs1 ),
.raddr_a_i ( raddr_a ),
.rdata_a_o ( operand_a_regfile ),
.raddr_b_i ( issue_instr_i.rs2 ),
.rdata_b_o ( operand_b_regfile ),
.waddr_a_i ( waddr_a_i ),
.wdata_a_i ( wdata_a_i ),
.we_a_i ( we_a_i )
.waddr_a_i ( waddr ),
.wdata_a_i ( wdata ),
.we_a_i ( we )
);
// ----------------------

View file

@ -31,6 +31,12 @@ module issue_stage #(
input logic flush_unissued_instr_i,
input logic flush_i,
// from Debug
input logic debug_gpr_req_i,
input logic [4:0] debug_gpr_addr_i,
input logic debug_gpr_we_i,
input logic [63:0] debug_gpr_wdata_i,
output logic [63:0] debug_gpr_rdata_o,
// from ISSUE
input scoreboard_entry decoded_instr_i,
input logic decoded_instr_valid_i,

View file

@ -40,7 +40,10 @@ module pcgen_stage (
input logic [63:0] epc_i, // exception PC which we need to return to
input logic eret_i, // return from exception
input logic [63:0] trap_vector_base_i, // base of trap vector
input exception ex_valid_i // exception is valid - from commit
input logic ex_valid_i, // exception is valid - from commit
// Debug
input logic [63:0] debug_pc_i, // PC from debug stage
input logic debug_set_pc_i // Set PC request from debug
);
logic [63:0] npc_n, npc_q;
@ -118,6 +121,8 @@ module pcgen_stage (
// -------------------------------
// 2. Debug
// -------------------------------
if (debug_set_pc_i)
npc_n = debug_pc_i;
// -------------------------------
// 4. Exception

2
tb

@ -1 +1 @@
Subproject commit 5ad1d07f7642d3efe0a22c70870e7ca6fa517c6b
Subproject commit 51c3e044f6302b048a11c96867d492894f4b44f9