Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for DBG_NUM_TRIGGERS parameter #700

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions bhv/cv32e40x_rvfi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,18 @@ module cv32e40x_rvfi
input logic [31:0] csr_tdata2_n_i,
input logic [31:0] csr_tdata2_q_i,
input logic csr_tdata2_we_i,
input logic [31:0] csr_tdata3_n_i,
input logic [31:0] csr_tdata3_q_i,
input logic csr_tdata3_we_i,
input logic [31:0] csr_tinfo_n_i,
input logic [31:0] csr_tinfo_q_i,
input logic csr_tinfo_we_i,
input logic [31:0] csr_tcontrol_n_i,
input logic [31:0] csr_tcontrol_q_i,
input logic csr_tcontrol_we_i,
input logic [31:0] csr_tselect_n_i,
input logic [31:0] csr_tselect_q_i,
input logic csr_tselect_we_i,
input dcsr_t csr_dcsr_n_i,
input dcsr_t csr_dcsr_q_i,
input logic csr_dcsr_we_i,
Expand Down Expand Up @@ -1307,9 +1313,9 @@ module cv32e40x_rvfi
assign rvfi_csr_wmask_d.mclicbase = csr_mclicbase_we_i ? '1 : '0;

// Trigger
assign rvfi_csr_rdata_d.tselect = '0;
assign rvfi_csr_wdata_d.tselect = '0; // Not implemented, read 0
assign rvfi_csr_wmask_d.tselect = '0;
assign rvfi_csr_rdata_d.tselect = csr_tselect_q_i;
assign rvfi_csr_wdata_d.tselect = csr_tselect_n_i;
assign rvfi_csr_wmask_d.tselect = csr_tselect_we_i;

assign rvfi_csr_rdata_d.tdata[0] = 'Z;
assign rvfi_csr_wdata_d.tdata[0] = 'Z; // Does not exist
Expand All @@ -1323,9 +1329,9 @@ module cv32e40x_rvfi
assign rvfi_csr_wdata_d.tdata[2] = csr_tdata2_n_i;
assign rvfi_csr_wmask_d.tdata[2] = csr_tdata2_we_i ? '1 : '0;

assign rvfi_csr_rdata_d.tdata[3] = '0;
assign rvfi_csr_wdata_d.tdata[3] = '0; // Not implemented, read 0
assign rvfi_csr_wmask_d.tdata[3] = '0;
assign rvfi_csr_rdata_d.tdata[3] = csr_tdata3_q_i;
assign rvfi_csr_wdata_d.tdata[3] = csr_tdata3_n_i;
assign rvfi_csr_wmask_d.tdata[3] = csr_tdata3_we_i;

assign rvfi_csr_rdata_d.tinfo = csr_tinfo_q_i;
assign rvfi_csr_wdata_d.tinfo = csr_tinfo_n_i;
Expand Down
7 changes: 6 additions & 1 deletion bhv/cv32e40x_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,9 @@ endgenerate
.csr_tdata2_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata2_n ),
.csr_tdata2_q_i ( core_i.cs_registers_i.tdata2_rdata ),
.csr_tdata2_we_i ( core_i.cs_registers_i.tdata2_we ),
.csr_tdata3_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata3_n ),
.csr_tdata3_q_i ( core_i.cs_registers_i.tdata3_rdata ),
.csr_tdata3_we_i ( core_i.cs_registers_i.tdata3_we ),
.csr_tinfo_n_i ( core_i.cs_registers_i.debug_triggers_i.tinfo_n ),
.csr_tinfo_q_i ( core_i.cs_registers_i.tinfo_rdata ),
.csr_tinfo_we_i ( core_i.cs_registers_i.tinfo_we ),
Expand Down Expand Up @@ -595,7 +598,9 @@ endgenerate
.csr_tcontrol_n_i ( core_i.cs_registers_i.debug_triggers_i.tcontrol_n ),
.csr_tcontrol_q_i ( core_i.cs_registers_i.tcontrol_rdata ),
.csr_tcontrol_we_i ( core_i.cs_registers_i.tcontrol_we ),
//todo: add tselect, tdata3
.csr_tselect_n_i ( core_i.cs_registers_i.debug_triggers_i.tselect_n ),
.csr_tselect_q_i ( core_i.cs_registers_i.tselect_rdata ),
.csr_tselect_we_i ( core_i.cs_registers_i.tselect_we ),

.csr_mcounteren_n_i ( '0 /* Not supported in cv32e40x*/ ),
.csr_mcounteren_q_i ( '0 /* Not supported in cv32e40x*/ ),
Expand Down
57 changes: 49 additions & 8 deletions rtl/cv32e40x_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -470,17 +470,59 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
end
end

CSR_TSELECT: csr_rdata_int = tselect_rdata;
CSR_TSELECT: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tselect_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_TDATA1: csr_rdata_int = tdata1_rdata;
CSR_TDATA1: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tdata1_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_TDATA2: csr_rdata_int = tdata2_rdata;
CSR_TDATA2: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tdata2_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_TDATA3: csr_rdata_int = tdata3_rdata;
CSR_TDATA3: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tdata3_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_TINFO: csr_rdata_int = tinfo_rdata;
CSR_TINFO: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tinfo_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_TCONTROL: csr_rdata_int = tcontrol_rdata;
CSR_TCONTROL: begin
if (DBG_NUM_TRIGGERS > 0) begin
csr_rdata_int = tcontrol_rdata;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
end
end

CSR_DCSR: begin
csr_rdata_int = dcsr_rdata;
Expand Down Expand Up @@ -1480,11 +1522,10 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;

// Trigger match output
.trigger_match_o ( trigger_match_o )


);



/////////////////////////////////////////////////////////////////
// ____ __ ____ _ //
// | _ \ ___ _ __ / _| / ___|___ _ _ _ __ | |_ ___ _ __ //
Expand Down
238 changes: 155 additions & 83 deletions rtl/cv32e40x_debug_triggers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -74,89 +74,161 @@ import cv32e40x_pkg::*;
logic [31:0] tinfo_n;
logic [31:0] tcontrol_n;

// CSR instance outputs
logic [31:0] tdata1_q;
logic [31:0] tdata2_q;

// Signal for or'ing unused signals for easier lint
logic unused_signals;

// Write data
always_comb begin
tselect_n = tselect_rdata_o; // todo

tdata1_n = {
TTYPE_MCONTROL, // type : address/data match
1'b1, // dmode : access from D mode only
6'h00, // maskmax : exact match only
1'b0, // hit : not supported
1'b0, // select : address match only
1'b0, // timing : match before execution
2'b00, // sizelo : match any access
4'h1, // action : enter debug mode
1'b0, // chain : not supported
4'h0, // match : simple match
1'b1, // m : match in m-mode
1'b0, // 0 : zero
1'b0, // s : not supported
1'b0, // u : match in u-mode
csr_wdata_i[2], // execute : match instruction address
1'b0, // store : not supported
1'b0 // load : not supported
};

tdata2_n = csr_wdata_i;
tdata3_n = tdata3_rdata_o; // Read only
tinfo_n = tinfo_rdata_o; // Read only
tcontrol_n = tcontrol_rdata_o; // Read only
end

// Breakpoint matching
// We match against the next address, as the breakpoint must be taken before execution
// Matching is disabled when ctrl_fsm_i.debug_mode == 1'b1
// Trigger CSRs can only be written from debug mode, writes from any other privilege level are ignored.
// Thus we do not have an issue where a write to the tdata2 CSR immediately before the matched instruction
// could be missed since we must write in debug mode, then dret to machine mode (kills pipeline) before
// returning to dpc.
// Todo: There is no CLIC spec for trigger matches for pointers.
assign trigger_match_o = tdata1_rdata_o[2] && !ctrl_fsm_i.debug_mode && !ptr_in_if_i &&
(pc_if_i[31:0] == tdata2_rdata_o[31:0]);


cv32e40x_csr
#(
.WIDTH (32),
.RESETVALUE (TDATA1_RST_VAL)
)
tdata1_csr_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.wr_data_i ( tdata1_n ),
.wr_en_i ( tdata1_we_i ),
.rd_data_o ( tdata1_q )
);

cv32e40x_csr
#(
.WIDTH (32),
.RESETVALUE (32'd0)
)
tdata2_csr_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.wr_data_i ( tdata2_n ),
.wr_en_i ( tdata2_we_i ),
.rd_data_o ( tdata2_q )
);

// Assign CSR read data outputs
assign tdata1_rdata_o = tdata1_q;
assign tdata2_rdata_o = tdata2_q;
assign tdata3_rdata_o = 32'h00000000;
assign tselect_rdata_o = 32'h00000000;
assign tinfo_rdata_o = 32'h4;
assign tcontrol_rdata_o = 32'h00000000;

assign unused_signals = tselect_we_i | tinfo_we_i | tcontrol_we_i | tdata3_we_i;
generate
if (DBG_NUM_TRIGGERS > 0) begin : gen_triggers
// Internal CSR write enables
logic [DBG_NUM_TRIGGERS-1 : 0] tdata1_we_int;
logic [DBG_NUM_TRIGGERS-1 : 0] tdata2_we_int;

// CSR instance outputs
logic [31:0] tdata1_q[DBG_NUM_TRIGGERS];
logic [31:0] tdata2_q[DBG_NUM_TRIGGERS];
logic [31:0] tselect_q;

// Fetch stage trigger match
logic [DBG_NUM_TRIGGERS-1 : 0] trigger_match_if;


// Write data
always_comb begin
// Tselect is WARL (0 -> DBG_NUM_TRIGGERS-1)
tselect_n = (csr_wdata_i < DBG_NUM_TRIGGERS) ? csr_wdata_i : tselect_rdata_o;

// todo: handle WARL based on trigger type
tdata1_n = {
TTYPE_MCONTROL6, // type : address/data match
1'b1, // dmode : access from D mode only
2'b00, // zero 26:25
3'b000, // zero, vs, vu, hit 24:22
1'b0, // zero, select 21
1'b0, // zero, timing 20
4'b0000, // zero, size (match any size) 19:16
4'b0001, // action, WARL(1), enter debug 15:12
1'b0, // zero, chain 11
4'b0000, // match, WARL(0,2,3) 10:7 todo: resolve WARL
csr_wdata_i[6], // M 6
1'b0, // zero 5
1'b0, // zero, S 4
1'b0, // zero, U 3
csr_wdata_i[2], // EXECUTE 2
csr_wdata_i[1], // STORE 1
csr_wdata_i[0]}; // LOAD 0

tdata2_n = csr_wdata_i;
tdata3_n = tdata3_rdata_o; // Read only
tinfo_n = tinfo_rdata_o; // Read only
tcontrol_n = tcontrol_rdata_o; // Read only
end

// Generate DBG_NUM_TRIGGERS instances of tdata1, tdata2 and match checks
for (genvar idx=0; idx<DBG_NUM_TRIGGERS; idx++) begin : tmatch_csr
// Breakpoint matching
// We match against the next address, as the breakpoint must be taken before execution
// Matching is disabled when ctrl_fsm_i.debug_mode == 1'b1
// Trigger CSRs can only be written from debug mode, writes from any other privilege level are ignored.
// Thus we do not have an issue where a write to the tdata2 CSR immediately before the matched instruction
// could be missed since we must write in debug mode, then dret to machine mode (kills pipeline) before
// returning to dpc.
// Todo: There is no CLIC spec for trigger matches for pointers.
// todo: use struct or parameters for indexing to make code more readable.
// todo: Check tdata1[6] vs actual priv_lvl and add check for tdata1[3] (PRIV_LVL_U)
assign trigger_match_if[idx] = tdata1_q[idx][2] && tdata1_q[idx][6] && !ctrl_fsm_i.debug_mode && !ptr_in_if_i &&
(pc_if_i[31:0] == tdata2_q[idx][31:0]);


cv32e40x_csr
#(
.WIDTH (32),
.RESETVALUE (TDATA1_RST_VAL)
)
tdata1_csr_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.wr_data_i ( tdata1_n ),
.wr_en_i ( tdata1_we_int[idx] ),
.rd_data_o ( tdata1_q[idx] )
);

cv32e40x_csr
#(
.WIDTH (32),
.RESETVALUE (32'd0)
)
tdata2_csr_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.wr_data_i ( tdata2_n ),
.wr_en_i ( tdata2_we_int[idx] ),
.rd_data_o ( tdata2_q[idx] )
);

// Set write enables
assign tdata1_we_int[idx] = tdata1_we_i && (tselect_q == idx);
assign tdata2_we_int[idx] = tdata2_we_i && (tselect_q == idx);
end // for

// CSR instance for tselect
cv32e40x_csr
#(
.WIDTH (32),
.RESETVALUE (32'd0)
)
tselect_csr_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.wr_data_i ( tselect_n ),
.wr_en_i ( tselect_we_i ),
.rd_data_o ( tselect_q )
);

// Assign CSR read data outputs
always_comb begin
tdata1_rdata_o = tdata1_q[0];
tdata2_rdata_o = tdata2_q[0];

// Iterate through triggers and set tdata1/tdata2 rdata for the currently selected trigger
for (int i=0; i<DBG_NUM_TRIGGERS; i++) begin
if(tselect_q == i) begin
tdata1_rdata_o = tdata1_q[i];
tdata2_rdata_o = tdata2_q[i];
end
end
end

assign tdata3_rdata_o = 32'h00000000;
assign tselect_rdata_o = tselect_q;
assign tinfo_rdata_o = 32'h4; // todo: update
assign tcontrol_rdata_o = 32'h00000000;

// Set trigger match for IF
assign trigger_match_o = |trigger_match_if;

assign unused_signals = tinfo_we_i | tcontrol_we_i | tdata3_we_i | (|tinfo_n) | (|tdata3_n) | (|tcontrol_n);

end else begin : gen_no_triggers
// Tie off outputs
assign tdata1_rdata_o = '0;
assign tdata2_rdata_o = '0;
assign tdata3_rdata_o = '0;
assign tselect_rdata_o = '0;
assign tinfo_rdata_o = '0;
assign tcontrol_rdata_o = '0;
assign trigger_match_o = '0;
assign tdata1_n = '0;
assign tdata2_n = '0;
assign tdata3_n = '0;
assign tselect_n = '0;
assign tinfo_n = '0;
assign tcontrol_n = '0;

assign unused_signals = (|tdata1_n) | (|tdata2_n) | (|tdata3_n) | (|tselect_n) | (|tinfo_n) | (|tcontrol_n) |
(|csr_wdata_i) | tdata1_we_i | tdata2_we_i | tdata3_we_i | tselect_we_i | tinfo_we_i | tcontrol_we_i;
end
endgenerate
endmodule
Loading