-
Notifications
You must be signed in to change notification settings - Fork 52
Mcontrol6 #702
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
Mcontrol6 #702
Changes from 5 commits
17fe54f
b793ab9
bc29151
e2bf78c
4aa496f
3949629
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,12 +58,21 @@ import cv32e40x_pkg::*; | |
// IF stage inputs | ||
input logic [31:0] pc_if_i, | ||
input logic ptr_in_if_i, | ||
input privlvl_t priv_lvl_if_i, | ||
|
||
// EX stage / LSU inputs | ||
input logic lsu_valid_ex_i, | ||
input logic [31:0] lsu_addr_ex_i, | ||
input logic lsu_we_ex_i, | ||
input logic [3:0] lsu_be_ex_i, | ||
input privlvl_t priv_lvl_ex_i, | ||
|
||
// Controller inputs | ||
input ctrl_fsm_t ctrl_fsm_i, | ||
|
||
// Trigger match output | ||
output logic trigger_match_o | ||
// Trigger match outputs | ||
output logic trigger_match_if_o, // Instruction address match | ||
output logic trigger_match_ex_o // Load/Store address match | ||
Silabs-ArjanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
|
||
// CSR write data | ||
|
@@ -77,6 +86,8 @@ import cv32e40x_pkg::*; | |
// Signal for or'ing unused signals for easier lint | ||
logic unused_signals; | ||
|
||
|
||
|
||
generate | ||
if (DBG_NUM_TRIGGERS > 0) begin : gen_triggers | ||
// Internal CSR write enables | ||
|
@@ -88,9 +99,28 @@ import cv32e40x_pkg::*; | |
logic [31:0] tdata2_q[DBG_NUM_TRIGGERS]; | ||
logic [31:0] tselect_q; | ||
|
||
// Fetch stage trigger match | ||
// CSR read data, possibly WARL resolved | ||
logic [31:0] tdata1_rdata[DBG_NUM_TRIGGERS]; | ||
logic [31:0] tdata2_rdata[DBG_NUM_TRIGGERS]; | ||
|
||
// IF and EX stages trigger match | ||
logic [DBG_NUM_TRIGGERS-1 : 0] trigger_match_if; | ||
logic [DBG_NUM_TRIGGERS-1 : 0] trigger_match_ex; | ||
Silabs-ArjanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Instruction address match | ||
logic [DBG_NUM_TRIGGERS-1 : 0] if_addr_match; | ||
|
||
// LSU address match signals | ||
logic [DBG_NUM_TRIGGERS-1 : 0] lsu_addr_match_en; | ||
logic [DBG_NUM_TRIGGERS-1 : 0] lsu_addr_match; | ||
logic [3:0] lsu_byte_addr_match[DBG_NUM_TRIGGERS]; | ||
|
||
// Enable matching based on privilege level per trigger | ||
logic [DBG_NUM_TRIGGERS-1 : 0] priv_lvl_match_en_if; | ||
logic [DBG_NUM_TRIGGERS-1 : 0] priv_lvl_match_en_ex; | ||
|
||
logic [1:0] lsu_addr_high_lsb; // Lower two bits of the highest accessed address | ||
logic [31:0] lsu_addr_high; // The highest accessed address of an LSU transaction | ||
|
||
// Write data | ||
always_comb begin | ||
|
@@ -108,7 +138,7 @@ import cv32e40x_pkg::*; | |
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 | ||
mcontrol6_match_resolve(csr_wdata_i[MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW]), // match, WARL(0,2,3) 10:7 | ||
csr_wdata_i[6], // M 6 | ||
1'b0, // zero 5 | ||
1'b0, // zero, S 4 | ||
|
@@ -123,20 +153,87 @@ import cv32e40x_pkg::*; | |
tcontrol_n = tcontrol_rdata_o; // Read only | ||
end | ||
|
||
// Calculate highest value of address[1:0] based on lsu_be_ex_i | ||
always_comb begin | ||
for (int b=0; b<4; b++) begin : gen_byte_checks | ||
if (lsu_be_ex_i[b]) begin | ||
lsu_addr_high_lsb = 2'(b); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add default assignment for lsu_addr_high_lsb (with XIF none of the lsu_be_ex_i bits might be high) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
end // if | ||
end // for | ||
end // always | ||
|
||
assign lsu_addr_high = {lsu_addr_ex_i[31:2], lsu_addr_high_lsb}; | ||
|
||
// 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 | ||
|
||
//////////////////////////////////// | ||
// Instruction address match (IF) | ||
//////////////////////////////////// | ||
|
||
// With timing=0 we enter debug before executing the instruction at the match address. We use the IF stage PC | ||
// for comparison, and any trigger match will cause the instruction to act as a NOP with no side effects until it | ||
// reaches WB where debug mode is entered. | ||
// | ||
// Trigger match is disabled while in debug mode. | ||
// | ||
// 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]); | ||
// No instruction address match on any pointer type (CLIC and Zc tablejumps). | ||
Silabs-ArjanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Check for address match using tdata2.match for checking rule | ||
assign if_addr_match[idx] = (tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h0) ? (pc_if_i == tdata2_rdata[idx]) : | ||
(tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h2) ? (pc_if_i >= tdata2_rdata[idx]) : (pc_if_i < tdata2_rdata[idx]); | ||
|
||
// Check if matching is enabled for the current privilege level from IF | ||
assign priv_lvl_match_en_if[idx] = (tdata1_rdata[idx][MCONTROL6_M] && (priv_lvl_if_i == PRIV_LVL_M)) || | ||
(tdata1_rdata[idx][MCONTROL6_U] && (priv_lvl_if_i == PRIV_LVL_U)); | ||
|
||
// Check for trigger match from IF | ||
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 && | ||
if_addr_match[idx]; | ||
|
||
/////////////////////////////////////// | ||
// Load/Store address match (EX) | ||
/////////////////////////////////////// | ||
|
||
// todo: LSU address matching must be revisited once the atomics are implemented | ||
// As for instruction address match, the load/store address match happens before the a bus transaction is visible on the OBI bus. | ||
// For split misaligned transfers, each transfer is checked separately. This means that half a store may be visible externally even if | ||
// 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 | ||
// will happen regardless of which transaction matches. | ||
// The BE of the transaction is used to determine which bytes of a word is being accessed. | ||
|
||
// Check if any accessed byte matches the lower two bits of tdata2 | ||
always_comb begin | ||
for (int b=0; b<4; b++) begin | ||
if (lsu_be_ex_i[b] && (2'(b) == tdata2_rdata[idx][1:0])) begin | ||
lsu_byte_addr_match[idx][b] = 1'b1; | ||
end else begin | ||
lsu_byte_addr_match[idx][b] = 1'b0; | ||
end | ||
end | ||
end | ||
|
||
// Check address matches for (==), (>=) and (<) | ||
// For ==, check that we match the 32-bit aligned word and that any of the accessed bytes matches tdata2[1:0] | ||
// For >=, check that the highest accessed address is greater than or equal to tdata2 | ||
// For <, check that the highest accessed address is less than tdata2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment and implementation not according to debug spec There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
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])) : | ||
(tdata1_rdata[idx][MCONTROL6_MATCH_HIGH:MCONTROL6_MATCH_LOW] == 4'h2) ? (lsu_addr_high >= tdata2_rdata[idx]) : | ||
(lsu_addr_high < tdata2_rdata[idx]) ; | ||
|
||
// Check if matching is enabled for the current privilege level from EX | ||
assign priv_lvl_match_en_ex[idx] = (tdata1_rdata[idx][MCONTROL6_M] && (priv_lvl_ex_i == PRIV_LVL_M)) || | ||
(tdata1_rdata[idx][MCONTROL6_U] && (priv_lvl_ex_i == PRIV_LVL_U)); | ||
|
||
// Enable LSU address matching | ||
assign lsu_addr_match_en[idx] = lsu_valid_ex_i && ((tdata1_q[idx][MCONTROL6_LOAD] && !lsu_we_ex_i) || (tdata1_q[idx][MCONTROL6_STORE] && lsu_we_ex_i)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add todo to revisit this code when supporting Atomics There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done
Silabs-ArjanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Signal trigger match for LSU address | ||
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; | ||
|
||
|
||
cv32e40x_csr | ||
|
@@ -170,6 +267,11 @@ import cv32e40x_pkg::*; | |
// 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); | ||
|
||
Silabs-ArjanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Assign read data | ||
// todo: WARL | ||
assign tdata1_rdata[idx] = tdata1_q[idx]; | ||
assign tdata2_rdata[idx] = tdata2_q[idx]; | ||
end // for | ||
|
||
// CSR instance for tselect | ||
|
@@ -189,14 +291,14 @@ import cv32e40x_pkg::*; | |
|
||
// Assign CSR read data outputs | ||
always_comb begin | ||
tdata1_rdata_o = tdata1_q[0]; | ||
tdata2_rdata_o = tdata2_q[0]; | ||
tdata1_rdata_o = tdata1_rdata[0]; | ||
tdata2_rdata_o = tdata2_rdata[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]; | ||
tdata1_rdata_o = tdata1_rdata[i]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tselect_q -> tselect_rdata There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
tdata2_rdata_o = tdata2_rdata[i]; | ||
end | ||
end | ||
end | ||
|
@@ -207,7 +309,10 @@ import cv32e40x_pkg::*; | |
assign tcontrol_rdata_o = 32'h00000000; | ||
|
||
// Set trigger match for IF | ||
assign trigger_match_o = |trigger_match_if; | ||
assign trigger_match_if_o = |trigger_match_if; | ||
|
||
// Set trigger match for EX | ||
assign trigger_match_ex_o = |trigger_match_ex; | ||
|
||
assign unused_signals = tinfo_we_i | tcontrol_we_i | tdata3_we_i | (|tinfo_n) | (|tdata3_n) | (|tcontrol_n); | ||
|
||
|
@@ -219,7 +324,8 @@ import cv32e40x_pkg::*; | |
assign tselect_rdata_o = '0; | ||
assign tinfo_rdata_o = '0; | ||
assign tcontrol_rdata_o = '0; | ||
assign trigger_match_o = '0; | ||
assign trigger_match_if_o = '0; | ||
assign trigger_match_ex_o = '0; | ||
assign tdata1_n = '0; | ||
assign tdata2_n = '0; | ||
assign tdata3_n = '0; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change in itself SEC clean when ZC_EXT = 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SEC is still running after four days