Skip to content

Commit 2cf44d1

Browse files
Merge pull request #702 from silabs-oysteink/silabs-oysteink_mcontrol6
Mcontrol6
2 parents 5da9bc5 + 3949629 commit 2cf44d1

7 files changed

+247
-51
lines changed

rtl/cv32e40x_controller_fsm.sv

+3-1
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,11 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
442442
// The cycle after fencei enters WB, the fencei handshake will be initiated. This must complete and the fencei instruction must retire before allowing debug.
443443
// Any multi operation instruction (table jumps, push/pop and double moves) may not be interrupted once the first operation has completed its operation in WB.
444444
// - This is guarded with using the sequence_interruptible, which tracks sequence progress through the WB stage.
445+
// - Exception if a LSU trigger match happens during push or pop, then we must abort the sequence and enter debug mode.
446+
// - If trigger_match_in_wb is caused by instruction address match, then no side effects will happen for a sequence, and debug mode is entered when the first operation is in WB.
445447
// When a CLIC pointer is in the pipeline stages EX or WB, we must block debug.
446448
// - Debug would otherwise kill the pointer and use the address of the pointer for dpc. A following dret would then return to the mtvt table, losing program progress.
447-
assign debug_allowed = lsu_interruptible_i && !fencei_ongoing && !xif_in_wb && !clic_ptr_in_pipeline && sequence_interruptible;
449+
assign debug_allowed = lsu_interruptible_i && !fencei_ongoing && !xif_in_wb && !clic_ptr_in_pipeline && (sequence_interruptible || trigger_match_in_wb);
448450

449451
// Debug pending for any other reason than single step
450452
assign pending_debug = (trigger_match_in_wb) ||

rtl/cv32e40x_core.sv

+26-3
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,11 @@ module cv32e40x_core import cv32e40x_pkg::*;
256256
logic lsu_valid_wb;
257257
logic lsu_ready_1;
258258

259+
// LSU signals to trigger module
260+
logic [31:0] lsu_addr_ex;
261+
logic lsu_we_ex;
262+
logic [3:0] lsu_be_ex;
263+
259264
logic data_stall_wb;
260265

261266
// Stage ready signals
@@ -282,8 +287,10 @@ module cv32e40x_core import cv32e40x_pkg::*;
282287
// From cs_registers
283288
dcsr_t dcsr;
284289

285-
// trigger match detected in cs_registers (using ID timing)
290+
// trigger match detected in trigger module (using IF timing)
286291
logic trigger_match_if;
292+
// trigger match detected in trigger module (using EX/LSU timing)
293+
logic trigger_match_ex;
287294

288295
// Controller <-> decoder
289296
logic alu_jmp_id;
@@ -572,6 +579,9 @@ module cv32e40x_core import cv32e40x_pkg::*;
572579
.csr_illegal_i ( csr_illegal ),
573580
.csr_mnxti_read_i ( csr_mnxti_read ),
574581

582+
// trigger input
583+
.trigger_match_i ( trigger_match_ex ),
584+
575585
// Branch decision
576586
.branch_decision_o ( branch_decision_ex ),
577587
.branch_target_o ( branch_target_ex ),
@@ -633,11 +643,19 @@ module cv32e40x_core import cv32e40x_pkg::*;
633643
.busy_o ( lsu_busy ),
634644
.interruptible_o ( lsu_interruptible ),
635645

646+
// Trigger match
647+
.trigger_match_0_i ( trigger_match_ex ),
648+
636649
// Stage 0 outputs (EX)
637650
.lsu_split_0_o ( lsu_split_ex ),
638651
.lsu_first_op_0_o ( lsu_first_op_ex ),
639652
.lsu_last_op_0_o ( lsu_last_op_ex ),
640653

654+
// Outputs to trigger module
655+
.lsu_addr_o ( lsu_addr_ex ),
656+
.lsu_we_o ( lsu_we_ex ),
657+
.lsu_be_o ( lsu_be_ex ),
658+
641659
// Stage 1 outputs (WB)
642660
.lsu_err_1_o ( lsu_err_wb ), // To controller (has WB timing, but does not pass through WB stage)
643661
.lsu_rdata_1_o ( lsu_rdata_wb ),
@@ -791,9 +809,14 @@ module cv32e40x_core import cv32e40x_pkg::*;
791809
.csr_wr_in_wb_flush_o ( csr_wr_in_wb_flush ),
792810

793811
// Debug
794-
.trigger_match_o ( trigger_match_if ),
812+
.trigger_match_if_o ( trigger_match_if ),
813+
.trigger_match_ex_o ( trigger_match_ex ),
795814
.pc_if_i ( pc_if ),
796-
.ptr_in_if_i ( ptr_in_if )
815+
.ptr_in_if_i ( ptr_in_if ),
816+
.lsu_valid_ex_i ( lsu_valid_ex ),
817+
.lsu_addr_ex_i ( lsu_addr_ex ),
818+
.lsu_we_ex_i ( lsu_we_ex ),
819+
.lsu_be_ex_i ( lsu_be_ex )
797820
);
798821

799822
////////////////////////////////////////////////////////////////////

rtl/cv32e40x_cs_registers.sv

+17-3
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,12 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
103103
// Debug
104104
input logic [31:0] pc_if_i,
105105
input logic ptr_in_if_i,
106-
output logic trigger_match_o
106+
output logic trigger_match_if_o,
107+
output logic trigger_match_ex_o,
108+
input logic lsu_valid_ex_i,
109+
input logic [31:0] lsu_addr_ex_i,
110+
input logic lsu_we_ex_i,
111+
input logic [3:0] lsu_be_ex_i
107112
);
108113

109114
localparam logic [31:0] CORE_MISA =
@@ -1516,12 +1521,21 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
15161521
// IF stage inputs
15171522
.pc_if_i ( pc_if_i ),
15181523
.ptr_in_if_i ( ptr_in_if_i ),
1524+
.priv_lvl_if_i ( PRIV_LVL_M ),
1525+
1526+
// LSU inputs
1527+
.lsu_valid_ex_i ( lsu_valid_ex_i),
1528+
.lsu_addr_ex_i ( lsu_addr_ex_i ),
1529+
.lsu_we_ex_i ( lsu_we_ex_i ),
1530+
.lsu_be_ex_i ( lsu_be_ex_i ),
1531+
.priv_lvl_ex_i ( PRIV_LVL_M ),
15191532

15201533
// Controller inputs
15211534
.ctrl_fsm_i ( ctrl_fsm_i ),
15221535

1523-
// Trigger match output
1524-
.trigger_match_o ( trigger_match_o )
1536+
// Trigger match outputs
1537+
.trigger_match_if_o ( trigger_match_if_o ),
1538+
.trigger_match_ex_o ( trigger_match_ex_o )
15251539
);
15261540

15271541

rtl/cv32e40x_debug_triggers.sv

+140-21
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,21 @@ import cv32e40x_pkg::*;
5858
// IF stage inputs
5959
input logic [31:0] pc_if_i,
6060
input logic ptr_in_if_i,
61+
input privlvl_t priv_lvl_if_i,
62+
63+
// EX stage / LSU inputs
64+
input logic lsu_valid_ex_i,
65+
input logic [31:0] lsu_addr_ex_i,
66+
input logic lsu_we_ex_i,
67+
input logic [3:0] lsu_be_ex_i,
68+
input privlvl_t priv_lvl_ex_i,
6169

6270
// Controller inputs
6371
input ctrl_fsm_t ctrl_fsm_i,
6472

65-
// Trigger match output
66-
output logic trigger_match_o
73+
// Trigger match outputs
74+
output logic trigger_match_if_o, // Instruction address match
75+
output logic trigger_match_ex_o // Load/Store address match
6776
);
6877

6978
// CSR write data
@@ -77,6 +86,8 @@ import cv32e40x_pkg::*;
7786
// Signal for or'ing unused signals for easier lint
7887
logic unused_signals;
7988

89+
90+
8091
generate
8192
if (DBG_NUM_TRIGGERS > 0) begin : gen_triggers
8293
// Internal CSR write enables
@@ -88,9 +99,30 @@ import cv32e40x_pkg::*;
8899
logic [31:0] tdata2_q[DBG_NUM_TRIGGERS];
89100
logic [31:0] tselect_q;
90101

91-
// Fetch stage trigger match
102+
// CSR read data, possibly WARL resolved
103+
logic [31:0] tdata1_rdata[DBG_NUM_TRIGGERS];
104+
logic [31:0] tdata2_rdata[DBG_NUM_TRIGGERS];
105+
106+
// IF and EX stages trigger match
92107
logic [DBG_NUM_TRIGGERS-1 : 0] trigger_match_if;
108+
logic [DBG_NUM_TRIGGERS-1 : 0] trigger_match_ex;
109+
110+
// Instruction address match
111+
logic [DBG_NUM_TRIGGERS-1 : 0] if_addr_match;
112+
113+
// LSU address match signals
114+
logic [DBG_NUM_TRIGGERS-1 : 0] lsu_addr_match_en;
115+
logic [DBG_NUM_TRIGGERS-1 : 0] lsu_addr_match;
116+
logic [3:0] lsu_byte_addr_match[DBG_NUM_TRIGGERS];
117+
118+
// Enable matching based on privilege level per trigger
119+
logic [DBG_NUM_TRIGGERS-1 : 0] priv_lvl_match_en_if;
120+
logic [DBG_NUM_TRIGGERS-1 : 0] priv_lvl_match_en_ex;
93121

122+
logic [1:0] lsu_addr_low_lsb; // Lower two bits of the lowest accessed address
123+
logic [1:0] lsu_addr_high_lsb; // Lower two bits of the highest accessed address
124+
logic [31:0] lsu_addr_low; // The lowest accessed address of an LSU transaction
125+
logic [31:0] lsu_addr_high; // The highest accessed address of an LSU transaction
94126

95127
// Write data
96128
always_comb begin
@@ -108,7 +140,7 @@ import cv32e40x_pkg::*;
108140
4'b0000, // zero, size (match any size) 19:16
109141
4'b0001, // action, WARL(1), enter debug 15:12
110142
1'b0, // zero, chain 11
111-
4'b0000, // match, WARL(0,2,3) 10:7 todo: resolve WARL
143+
mcontrol6_match_resolve(csr_wdata_i[MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW]), // match, WARL(0,2,3) 10:7
112144
csr_wdata_i[6], // M 6
113145
1'b0, // zero 5
114146
1'b0, // zero, S 4
@@ -123,20 +155,98 @@ import cv32e40x_pkg::*;
123155
tcontrol_n = tcontrol_rdata_o; // Read only
124156
end
125157

158+
// Calculate highest and lowest value of address[1:0] based on lsu_be_ex_i
159+
always_comb begin
160+
lsu_addr_high_lsb = 2'b00;
161+
lsu_addr_low_lsb = 2'b00;
162+
// Find highest accessed byte
163+
for (int b=0; b<4; b++) begin : gen_high_byte_checks
164+
if (lsu_be_ex_i[b]) begin
165+
lsu_addr_high_lsb = 2'(b);
166+
end // if
167+
end // for
168+
169+
// Find lowest accessed byte
170+
for (int b=3; b>=0; b--) begin : gen_low_byte_checks
171+
if (lsu_be_ex_i[b]) begin
172+
lsu_addr_low_lsb = 2'(b);
173+
end // if
174+
end // for
175+
end // always
176+
177+
assign lsu_addr_high = {lsu_addr_ex_i[31:2], lsu_addr_high_lsb};
178+
assign lsu_addr_low = {lsu_addr_ex_i[31:2], lsu_addr_low_lsb};
179+
126180
// Generate DBG_NUM_TRIGGERS instances of tdata1, tdata2 and match checks
127181
for (genvar idx=0; idx<DBG_NUM_TRIGGERS; idx++) begin : tmatch_csr
128-
// Breakpoint matching
129-
// We match against the next address, as the breakpoint must be taken before execution
130-
// Matching is disabled when ctrl_fsm_i.debug_mode == 1'b1
182+
183+
////////////////////////////////////
184+
// Instruction address match (IF)
185+
////////////////////////////////////
186+
187+
// With timing=0 we enter debug before executing the instruction at the match address. We use the IF stage PC
188+
// for comparison, and any trigger match will cause the instruction to act as a NOP with no side effects until it
189+
// reaches WB where debug mode is entered.
190+
//
191+
// Trigger match is disabled while in debug mode.
192+
//
131193
// Trigger CSRs can only be written from debug mode, writes from any other privilege level are ignored.
132194
// Thus we do not have an issue where a write to the tdata2 CSR immediately before the matched instruction
133195
// could be missed since we must write in debug mode, then dret to machine mode (kills pipeline) before
134196
// returning to dpc.
135-
// Todo: There is no CLIC spec for trigger matches for pointers.
136-
// todo: use struct or parameters for indexing to make code more readable.
137-
// todo: Check tdata1[6] vs actual priv_lvl and add check for tdata1[3] (PRIV_LVL_U)
138-
assign trigger_match_if[idx] = tdata1_q[idx][2] && tdata1_q[idx][6] && !ctrl_fsm_i.debug_mode && !ptr_in_if_i &&
139-
(pc_if_i[31:0] == tdata2_q[idx][31:0]);
197+
// No instruction address match on any pointer type (CLIC and Zc tablejumps).
198+
199+
// Check for address match using tdata2.match for checking rule
200+
assign if_addr_match[idx] = (tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h0) ? (pc_if_i == tdata2_rdata[idx]) :
201+
(tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h2) ? (pc_if_i >= tdata2_rdata[idx]) : (pc_if_i < tdata2_rdata[idx]);
202+
203+
// Check if matching is enabled for the current privilege level from IF
204+
assign priv_lvl_match_en_if[idx] = (tdata1_rdata[idx][MCONTROL6_M] && (priv_lvl_if_i == PRIV_LVL_M)) ||
205+
(tdata1_rdata[idx][MCONTROL6_U] && (priv_lvl_if_i == PRIV_LVL_U));
206+
207+
// Check for trigger match from IF
208+
assign trigger_match_if[idx] = tdata1_rdata[idx][MCONTROL6_EXECUTE] && priv_lvl_match_en_if[idx] && !ctrl_fsm_i.debug_mode && !ptr_in_if_i &&
209+
if_addr_match[idx];
210+
211+
///////////////////////////////////////
212+
// Load/Store address match (EX)
213+
///////////////////////////////////////
214+
215+
// todo: LSU address matching must be revisited once the atomics are implemented
216+
// As for instruction address match, the load/store address match happens before the a bus transaction is visible on the OBI bus.
217+
// For split misaligned transfers, each transfer is checked separately. This means that half a store may be visible externally even if
218+
// the second part matches tdata2 and debug is entered. For loads the RF write will not happen until the last part finished anyway, so no state update
219+
// will happen regardless of which transaction matches.
220+
// The BE of the transaction is used to determine which bytes of a word is being accessed.
221+
222+
// Check if any accessed byte matches the lower two bits of tdata2
223+
always_comb begin
224+
for (int b=0; b<4; b++) begin
225+
if (lsu_be_ex_i[b] && (2'(b) == tdata2_rdata[idx][1:0])) begin
226+
lsu_byte_addr_match[idx][b] = 1'b1;
227+
end else begin
228+
lsu_byte_addr_match[idx][b] = 1'b0;
229+
end
230+
end
231+
end
232+
233+
// Check address matches for (==), (>=) and (<)
234+
// For ==, check that we match the 32-bit aligned word and that any of the accessed bytes matches tdata2[1:0]
235+
// For >=, check that the highest accessed address is greater than or equal to tdata2. If this fails, no bytes within the access are >= tdata2
236+
// For <, check that the lowest accessed address is less than tdata2. If this fails, no bytes within the access are < tdata2.
237+
assign lsu_addr_match[idx] = (tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h0) ? ((lsu_addr_ex_i[31:2] == tdata2_rdata[idx][31:2]) && (|lsu_byte_addr_match[idx])) :
238+
(tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h2) ? (lsu_addr_high >= tdata2_rdata[idx]) :
239+
(lsu_addr_low < tdata2_rdata[idx]) ;
240+
241+
// Check if matching is enabled for the current privilege level from EX
242+
assign priv_lvl_match_en_ex[idx] = (tdata1_rdata[idx][MCONTROL6_M] && (priv_lvl_ex_i == PRIV_LVL_M)) ||
243+
(tdata1_rdata[idx][MCONTROL6_U] && (priv_lvl_ex_i == PRIV_LVL_U));
244+
245+
// Enable LSU address matching
246+
assign lsu_addr_match_en[idx] = lsu_valid_ex_i && ((tdata1_rdata[idx][MCONTROL6_LOAD] && !lsu_we_ex_i) || (tdata1_rdata[idx][MCONTROL6_STORE] && lsu_we_ex_i));
247+
248+
// Signal trigger match for LSU address
249+
assign trigger_match_ex[idx] = priv_lvl_match_en_ex[idx] && lsu_addr_match_en[idx] && lsu_addr_match[idx] && !ctrl_fsm_i.debug_mode;
140250

141251

142252
cv32e40x_csr
@@ -168,8 +278,13 @@ import cv32e40x_pkg::*;
168278
);
169279

170280
// Set write enables
171-
assign tdata1_we_int[idx] = tdata1_we_i && (tselect_q == idx);
172-
assign tdata2_we_int[idx] = tdata2_we_i && (tselect_q == idx);
281+
assign tdata1_we_int[idx] = tdata1_we_i && (tselect_rdata_o == idx);
282+
assign tdata2_we_int[idx] = tdata2_we_i && (tselect_rdata_o == idx);
283+
284+
// Assign read data
285+
// todo: WARL
286+
assign tdata1_rdata[idx] = tdata1_q[idx];
287+
assign tdata2_rdata[idx] = tdata2_q[idx];
173288
end // for
174289

175290
// CSR instance for tselect
@@ -189,14 +304,14 @@ import cv32e40x_pkg::*;
189304

190305
// Assign CSR read data outputs
191306
always_comb begin
192-
tdata1_rdata_o = tdata1_q[0];
193-
tdata2_rdata_o = tdata2_q[0];
307+
tdata1_rdata_o = tdata1_rdata[0];
308+
tdata2_rdata_o = tdata2_rdata[0];
194309

195310
// Iterate through triggers and set tdata1/tdata2 rdata for the currently selected trigger
196311
for (int i=0; i<DBG_NUM_TRIGGERS; i++) begin
197-
if(tselect_q == i) begin
198-
tdata1_rdata_o = tdata1_q[i];
199-
tdata2_rdata_o = tdata2_q[i];
312+
if(tselect_rdata_o == i) begin
313+
tdata1_rdata_o = tdata1_rdata[i];
314+
tdata2_rdata_o = tdata2_rdata[i];
200315
end
201316
end
202317
end
@@ -207,7 +322,10 @@ import cv32e40x_pkg::*;
207322
assign tcontrol_rdata_o = 32'h00000000;
208323

209324
// Set trigger match for IF
210-
assign trigger_match_o = |trigger_match_if;
325+
assign trigger_match_if_o = |trigger_match_if;
326+
327+
// Set trigger match for EX
328+
assign trigger_match_ex_o = |trigger_match_ex;
211329

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

@@ -219,7 +337,8 @@ import cv32e40x_pkg::*;
219337
assign tselect_rdata_o = '0;
220338
assign tinfo_rdata_o = '0;
221339
assign tcontrol_rdata_o = '0;
222-
assign trigger_match_o = '0;
340+
assign trigger_match_if_o = '0;
341+
assign trigger_match_ex_o = '0;
223342
assign tdata1_n = '0;
224343
assign tdata2_n = '0;
225344
assign tdata3_n = '0;

0 commit comments

Comments
 (0)