mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 13:17:41 -04:00
Merge branch 'debug'
This commit is contained in:
commit
0e0dfce0ff
11 changed files with 552 additions and 75 deletions
|
@ -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
|
||||
|
|
128
src/ariane.sv
128
src/ariane.sv
|
@ -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
|
||||
// -------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
// ----------------------
|
||||
|
|
|
@ -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
348
src/debug_unit.sv
Executable 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
|
|
@ -247,4 +247,4 @@ module if_stage (
|
|||
else $warning("There was a grant without a request");
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
||||
endmodule
|
||||
|
|
|
@ -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 )
|
||||
);
|
||||
|
||||
// ----------------------
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
2
tb
|
@ -1 +1 @@
|
|||
Subproject commit 5ad1d07f7642d3efe0a22c70870e7ca6fa517c6b
|
||||
Subproject commit 51c3e044f6302b048a11c96867d492894f4b44f9
|
Loading…
Add table
Add a link
Reference in a new issue