mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
Working on debug support
Most features have a preliminary support now, i.e. software breakpoints work in general, NPC and PPC SPR are integrated and fully working, so it is possible to set a new PC from the debugger There are probably still some bugs in corner cases, and I'm pretty sure jumps are not working nicely in single-stepping mode
This commit is contained in:
parent
102691a06a
commit
73dd948f59
4 changed files with 62 additions and 74 deletions
|
@ -1254,7 +1254,10 @@ module controller
|
|||
case (dbg_fsm_cs)
|
||||
DBG_IDLE:
|
||||
begin
|
||||
if(trap_hit_i == 1'b1 && stall_ex_o == 1'b0 && jump_in_id_o == 2'b0)
|
||||
// branches take two cycles, jumps just one
|
||||
// everything else can be done immediately
|
||||
// TODO: there is a bug here, I'm sure of it
|
||||
if(trap_hit_i == 1'b1 && stall_ex_o == 1'b0 && jump_in_id_o == 2'b0 && jump_in_ex_i == 2'b0)
|
||||
begin
|
||||
dbg_halt = 1'b1;
|
||||
dbg_fsm_ns = DBG_EX;
|
||||
|
|
|
@ -58,11 +58,7 @@ module cs_registers
|
|||
output logic [31:0] hwlp_end_o,
|
||||
output logic [31:0] hwlp_counter_o,
|
||||
output logic [1:0] hwlp_regid_o,
|
||||
output logic [2:0] hwlp_we_o,
|
||||
|
||||
// Signals for NPC register
|
||||
output logic [31:0] npc_o, // TODO: check if needed
|
||||
output logic set_npc_o // TODO: check if needed
|
||||
output logic [2:0] hwlp_we_o
|
||||
);
|
||||
|
||||
|
||||
|
@ -106,6 +102,11 @@ module cs_registers
|
|||
12'hF01: constant_rdata_int = 32'h00_00_80_00; // mimpid: PULP3, anonymous source (no allocated ID)
|
||||
12'hF10: constant_rdata_int = {22'b0, cluster_id_i, core_id_i}; // mhartid: unique hardware thread id
|
||||
|
||||
// debug registers
|
||||
12'hFC0: constant_rdata_int = curr_pc_id_i; // Previous Program Counter for Debug
|
||||
|
||||
12'h780: constant_rdata_int = curr_pc_if_i; // Next Program Counter for Debug
|
||||
|
||||
default: is_constant = 1'b0;
|
||||
endcase
|
||||
end
|
||||
|
|
|
@ -57,25 +57,25 @@ module debug_unit
|
|||
output logic sp_mux_o,
|
||||
output logic regfile_mux_o,
|
||||
output logic regfile_we_o,
|
||||
output logic [15:0] regfile_addr_o,
|
||||
output logic [11:0] regfile_addr_o,
|
||||
output logic [31:0] regfile_wdata_o,
|
||||
input logic [31:0] regfile_rdata_i
|
||||
input logic [31:0] regfile_rdata_i,
|
||||
|
||||
// Signals for NPC register
|
||||
output logic [31:0] npc_o,
|
||||
output logic set_npc_o
|
||||
|
||||
);
|
||||
|
||||
// registers for debug control
|
||||
logic [1:0] DSR_DP, DSR_DN; // Debug Stop Register: IIE, INTE
|
||||
logic [1:0] DMR1_DP, DMR1_DN; // only single step trace and branch trace bits
|
||||
logic [2*`N_WP-1:0] DMR2_DP, DMR2_DN; // only BP enable control and BP cause status
|
||||
|
||||
// watchpoint status
|
||||
logic [`N_WP-1:0] WP_Status_D;
|
||||
|
||||
// BP control FSM
|
||||
enum logic [2:0] {Idle, Trap, DebugStall, StallCore} BP_State_SN, BP_State_SP;
|
||||
|
||||
// ack to debug interface
|
||||
assign dbginf_ack_o = (dbginf_strobe_i && (BP_State_SP == StallCore));
|
||||
assign dbginf_ack_o = dbginf_strobe_i && ((BP_State_SP == StallCore) || (dbginf_addr_i[15:11] == 5'b00110));
|
||||
|
||||
always_comb
|
||||
begin
|
||||
|
@ -83,38 +83,32 @@ module debug_unit
|
|||
stall_core_o = 1'b0;
|
||||
dbginf_bp_o = 1'b0;
|
||||
flush_pipe_o = 1'b0;
|
||||
|
||||
case (BP_State_SP)
|
||||
Idle:
|
||||
begin
|
||||
if(trap_i == 1'b1)
|
||||
BP_State_SN = Trap;
|
||||
|
||||
if(dbginf_stall_i)
|
||||
begin
|
||||
dbginf_bp_o = 1'b1;
|
||||
stall_core_o = 1'b1;
|
||||
BP_State_SN = StallCore;
|
||||
end
|
||||
else if(dbginf_stall_i)
|
||||
begin
|
||||
flush_pipe_o = 1'b1;
|
||||
BP_State_SN = DebugStall;
|
||||
BP_State_SN = DebugStall;
|
||||
end
|
||||
end
|
||||
|
||||
// A trap was encountered, wait for for the pipeline to be
|
||||
// flushed
|
||||
Trap:
|
||||
begin
|
||||
if(pipe_flushed_i == 1'b1)
|
||||
begin
|
||||
dbginf_bp_o = 1'b1;
|
||||
BP_State_SN = StallCore;
|
||||
end
|
||||
end
|
||||
|
||||
// A stall from adv dbg was seen, flush the pipeline and wait for unstalling
|
||||
// A stall from adv dbg unit was seen, flush the pipeline and wait for unstalling
|
||||
DebugStall:
|
||||
begin
|
||||
flush_pipe_o = 1'b1;
|
||||
|
||||
if(pipe_flushed_i == 1'b1)
|
||||
if(trap_i == 1'b1)
|
||||
begin
|
||||
BP_State_SN = StallCore;
|
||||
stall_core_o = 1'b1;
|
||||
BP_State_SN = StallCore;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -137,15 +131,19 @@ module debug_unit
|
|||
assign dbg_st_en_o = DMR1_DP[0];
|
||||
assign dbg_dsr_o = DSR_DP;
|
||||
|
||||
// handle set next program counter
|
||||
assign set_npc_o = (regfile_addr_o == 12'h780) && (sp_mux_o == 1'b1) && (regfile_we_o == 1'b1);
|
||||
assign npc_o = dbginf_data_i;
|
||||
|
||||
|
||||
// address decoding, write and read controller
|
||||
always_comb
|
||||
begin
|
||||
DMR1_DN = DMR1_DP;
|
||||
DMR2_DN[`N_WP-1:0] = DMR2_DP[`N_WP-1:0];
|
||||
DSR_DN = DSR_DP;
|
||||
dbginf_data_o = 32'b0;
|
||||
regfile_we_o = 1'b0;
|
||||
regfile_addr_o = 16'b0;
|
||||
regfile_addr_o = 'h0;
|
||||
regfile_mux_o = 1'b0;
|
||||
sp_mux_o = 1'b0;
|
||||
|
||||
|
@ -160,13 +158,6 @@ module debug_unit
|
|||
else
|
||||
dbginf_data_o[`DMR1_ST+1:`DMR1_ST] = DMR1_DP;
|
||||
end
|
||||
11'd17: begin // SP_DMR2
|
||||
if(dbginf_we_i == 1'b1)
|
||||
DMR2_DN[`N_WP-1:0] = dbginf_data_i[`DMR2_WGB0 + (`N_WP-1):`DMR2_WGB0];
|
||||
else
|
||||
dbginf_data_o[`DMR2_WGB0 + (`N_WP-1):`DMR2_WGB0] = DMR2_DP[`N_WP-1:0];
|
||||
dbginf_data_o[`DMR2_WBS0 + (`N_WP-1):`DMR2_WBS0] = DMR2_DP[2*`N_WP-1:`N_WP];
|
||||
end
|
||||
11'd20: begin // SP_DSR
|
||||
// currently we only handle IIE and INTE
|
||||
if(dbginf_we_i == 1'b1)
|
||||
|
@ -177,27 +168,31 @@ module debug_unit
|
|||
default: ;
|
||||
endcase // casex [10:0]
|
||||
end
|
||||
// check if GPRs are accessed
|
||||
else if(dbginf_addr_i[15:10] == 6'b000001)
|
||||
// check if internal registers (GPR or SPR) are accessed
|
||||
else if(BP_State_SP == StallCore)
|
||||
begin
|
||||
regfile_mux_o = 1'b1;
|
||||
regfile_addr_o[4:0] = dbginf_addr_i[4:0];
|
||||
// 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];
|
||||
|
||||
if(dbginf_we_i == 1'b1)
|
||||
regfile_we_o = 1'b1;
|
||||
if(dbginf_we_i == 1'b1)
|
||||
regfile_we_o = 1'b1;
|
||||
else
|
||||
dbginf_data_o = regfile_rdata_i;
|
||||
end
|
||||
// some other SPR is accessed
|
||||
else
|
||||
dbginf_data_o = regfile_rdata_i;
|
||||
end
|
||||
// some other SPR is accessed
|
||||
else
|
||||
begin
|
||||
sp_mux_o = 1'b1;
|
||||
regfile_addr_o = dbginf_addr_i;
|
||||
begin
|
||||
sp_mux_o = 1'b1;
|
||||
regfile_addr_o = dbginf_addr_i[11:0];
|
||||
|
||||
if(dbginf_we_i == 1'b1)
|
||||
regfile_we_o = 1'b1;
|
||||
else
|
||||
dbginf_data_o = regfile_rdata_i;
|
||||
if(dbginf_we_i == 1'b1)
|
||||
regfile_we_o = 1'b1;
|
||||
else
|
||||
dbginf_data_o = regfile_rdata_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -206,13 +201,11 @@ module debug_unit
|
|||
always_ff@(posedge clk or negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
DMR1_DP <= 2'b0;
|
||||
DMR2_DP <= 'b0;
|
||||
DSR_DP <= 'b0;
|
||||
BP_State_SP <= Idle;
|
||||
end
|
||||
else begin
|
||||
DMR1_DP <= DMR1_DN;
|
||||
DMR2_DP <= DMR2_DN;
|
||||
DSR_DP <= DSR_DN;
|
||||
BP_State_SP <= BP_State_SN;
|
||||
end
|
||||
|
|
|
@ -236,12 +236,6 @@ module riscv_core
|
|||
`endif
|
||||
|
||||
|
||||
// TODO: Temporary assignments while not everything from OR10N is implemented (e.g. debug unit)
|
||||
assign dbg_dsr = 2'b0;
|
||||
assign dbg_st_en = 1'b0;
|
||||
assign dbg_sp_mux = 1'b0;
|
||||
assign dbg_flush_pipe = 1'b0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// ___ _____ ____ _____ _ ____ _____ //
|
||||
|
@ -646,10 +640,7 @@ module riscv_core
|
|||
.save_pc_if_i ( save_pc_if ),
|
||||
.save_pc_id_i ( save_pc_id ),
|
||||
.epcr_o ( epcr ),
|
||||
.irq_enable_o ( irq_enable ),
|
||||
|
||||
.npc_o ( dbg_npc ), // PC from debug unit
|
||||
.set_npc_o ( dbg_set_npc ) // set PC to new value
|
||||
.irq_enable_o ( irq_enable )
|
||||
);
|
||||
|
||||
// Mux for SPR access through Debug Unit
|
||||
|
@ -747,6 +738,7 @@ module riscv_core
|
|||
assign hwlp_cnt_data = (hwlp_we_ex[2] == 1'b1) ? hwlp_cnt_data_ex : sp_hwlp_cnt;
|
||||
assign hwlp_regid = (|hwlp_we_ex) ? hwlp_regid_ex : sp_hwlp_regid;
|
||||
assign hwlp_we = hwlp_we_ex | sp_hwlp_we;
|
||||
*/
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
@ -786,13 +778,12 @@ module riscv_core
|
|||
.regfile_we_o ( dbg_reg_we ),
|
||||
.regfile_addr_o ( dbg_reg_addr ),
|
||||
.regfile_wdata_o ( dbg_reg_wdata ),
|
||||
.regfile_rdata_i ( dbg_rdata )
|
||||
.regfile_rdata_i ( dbg_rdata ),
|
||||
|
||||
.npc_o ( dbg_npc ), // PC from debug unit
|
||||
.set_npc_o ( dbg_set_npc ) // set PC to new value
|
||||
);
|
||||
|
||||
*/
|
||||
|
||||
assign dbg_reg_mux = 0;
|
||||
assign dbg_stall = 0;
|
||||
|
||||
|
||||
// Execution trace generation
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue