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:
Andreas Traber 2015-08-10 17:00:02 +02:00
parent 102691a06a
commit 73dd948f59
4 changed files with 62 additions and 74 deletions

View file

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

View file

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

View file

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

View file

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