Skip to content

Commit 86d27d7

Browse files
Merge pull request #620 from Silabs-ArjanB/ArjanB_todofl
Added todos related to recent PRs
2 parents fa22670 + 83699c4 commit 86d27d7

7 files changed

+49
-40
lines changed

bhv/cv32e40x_rvfi.sv

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -915,9 +915,9 @@ module cv32e40x_rvfi
915915
// Jumps may actually use rs1 before (id_valid && ex_ready), an assertion exists to check that
916916
// the jump target is stable and it should be safe to use rs1/2_rdata at the time of the pipeline handshake.
917917
// rs1/2 should reflect state of the first operation of any instruction.
918-
rs1_addr [STAGE_EX] <= first_op_id_i ? rs1_addr_id : rs1_addr[STAGE_EX];
919-
rs2_addr [STAGE_EX] <= first_op_id_i ? rs2_addr_id : rs2_addr[STAGE_EX];
920-
rs1_rdata [STAGE_EX] <= first_op_id_i ? rs1_rdata_id : rs1_rdata[STAGE_EX];
918+
rs1_addr [STAGE_EX] <= first_op_id_i ? rs1_addr_id : rs1_addr[STAGE_EX]; // todo: why the first_op_id_i dependency? In https://github.com/openhwgroup/cv32e40x/pull/605 it was stated as not needed.
919+
rs2_addr [STAGE_EX] <= first_op_id_i ? rs2_addr_id : rs2_addr[STAGE_EX]; // todo: why the first_op_id_i dependency? In https://github.com/openhwgroup/cv32e40x/pull/605 it was stated as not needed.
920+
rs1_rdata [STAGE_EX] <= first_op_id_i ? rs1_rdata_id : rs1_rdata[STAGE_EX]; // todo: add good explanation why the select is needed here and not for example on rs1_rdata_subop
921921
rs2_rdata [STAGE_EX] <= first_op_id_i ? rs2_rdata_id : rs2_rdata[STAGE_EX];
922922

923923
mem_rmask [STAGE_EX] <= (lsu_en_id_i && !lsu_we_id_i) ? rvfi_mem_mask_int : '0;
@@ -1035,7 +1035,7 @@ module cv32e40x_rvfi
10351035
end
10361036

10371037
// Update rvfi_mem
1038-
rvfi_mem_rdata[(32*(memop_cnt+1))-1 -: 32] <= lsu_rdata_wb_i;
1038+
rvfi_mem_rdata[(32*(memop_cnt+1))-1 -: 32] <= lsu_rdata_wb_i; // todo: document rvfi_mem_* signals in user manual RVFI section as they differ from the official RVFI. At what index will the 'official' RVFI info be present (also for misaligned loads/stores)?
10391039
rvfi_mem_rmask[ (4*(memop_cnt+1))-1 -: 4] <= mem_rmask [STAGE_WB];
10401040
rvfi_mem_wmask[ (4*(memop_cnt+1))-1 -: 4] <= mem_wmask [STAGE_WB];
10411041
rvfi_mem_addr [(32*(memop_cnt+1))-1 -: 32] <= ex_mem_addr;

rtl/cv32e40x_controller_fsm.sv

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
184184

185185
// Flag indicating there is a 'live' CLIC pointer in the pipeline
186186
// Used to block debug until pointer
187-
logic pointer_in_pipeline;
187+
logic clic_ptr_in_pipeline;
188188

189189
// Internal irq_ack for use when a (clic) pointer reaches ID stage and
190190
// we have single stepping enabled.
@@ -383,10 +383,10 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
383383
if(SMCLIC) begin : gen_clic_pointer_flag
384384
// We only need to check EX and WB, as the FSM will only be in FUNCTIONAL state
385385
// one cycle after the target CLIC jump has been performed from ID
386-
assign pointer_in_pipeline = (id_ex_pipe_i.instr_valid && id_ex_pipe_i.instr_meta.clic_ptr) ||
387-
(ex_wb_pipe_i.instr_valid && ex_wb_pipe_i.instr_meta.clic_ptr);
386+
assign clic_ptr_in_pipeline = (id_ex_pipe_i.instr_valid && id_ex_pipe_i.instr_meta.clic_ptr) ||
387+
(ex_wb_pipe_i.instr_valid && ex_wb_pipe_i.instr_meta.clic_ptr);
388388
end else begin : gen_basic_pointer_flag
389-
assign pointer_in_pipeline = 1'b0;
389+
assign clic_ptr_in_pipeline = 1'b0;
390390
end
391391
endgenerate
392392
// Regular debug will kill insn in WB, do not allow if LSU is not interruptible, a fence.i handshake is taking place
@@ -395,8 +395,8 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
395395
// a trans_valid has been clocked without ex_valid && wb_ready handshake.
396396
// The cycle after fencei enters WB, the fencei handshake will be initiated. This must complete and the fencei instruction must retire before allowing debug.
397397
// Once the first part of a table jump has finished in WB, we are not allowed to take debug before the last part finishes. This can be detected when the last
398-
// part of a table jump is in either EX or WB.
399-
assign debug_allowed = lsu_interruptible_i && !fencei_ongoing && !xif_in_wb && !pointer_in_pipeline && sequence_interruptible;
398+
// part of a table jump is in either EX or WB. // todo: update comments related to table jump (explain general concept and to which instructions it applies)
399+
assign debug_allowed = lsu_interruptible_i && !fencei_ongoing && !xif_in_wb && !clic_ptr_in_pipeline && sequence_interruptible;
400400

401401
// Debug pending for any other reason than single step
402402
assign pending_debug = (trigger_match_in_wb) ||
@@ -475,7 +475,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
475475
end else if (if_id_pipe_i.instr_valid) begin
476476
sequence_interruptible = first_op_id_i;
477477
end else begin
478-
sequence_interruptible = first_op_if_i;
478+
sequence_interruptible = first_op_if_i; // todo: first/last op should always be classified with instr_vali; if not it needs proper explanation.
479479
end
480480
end
481481

@@ -490,7 +490,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
490490
end else begin
491491
// IF stage first_op defaults to 1'b1 if the stage does not hold a valid instruction or
492492
// table jump pointer. Table jump pointers will have first_op set to 0.
493-
id_stage_haltable = first_op_if_i;
493+
id_stage_haltable = first_op_if_i; // todo: first/last op should always be classified with instr_valid; if not it needs proper explanation (and I would prefer if we get rid of this special reliance on the 1'b1 default)
494494
end
495495
end
496496

rtl/cv32e40x_if_stage.sv

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,12 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
313313
// Trigger matches will have all write enables deasserted in ID, and once the first operation reaches WB the debug entry will be made.
314314
// Marking as first (and last above) since we know it will not be a true sequence. Sequencer will keep sequencing, but will get killed
315315
// upon debug entry and no side effect will occur.
316+
// todo: The treatement of trigger match causes 1 instruction to possibly have first/last op set multiple times. Can this be avoided (it messes up the semantics of first/last op)?
316317
// todo: factor in CLIC pointers?
317318
assign first_op_o = prefetch_is_tbljmp_ptr ? 1'b0 :
318319
trigger_match_i ? 1'b1 : seq_first;
319320

320-
321+
// todo: first/last op need to be treated in the same manner (assignments need to look more similar). Also seq_first/seq_last need cleaner semantics with respect ot how they relate to seq_valid.
321322

322323
// Populate instruction meta data
323324
// Fields 'compressed' and 'tbljmp' keep their old value by default.
@@ -451,7 +452,7 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
451452
assign seq_last = 1'b0;
452453
assign seq_instr = '0;
453454
assign seq_ready = 1'b1;
454-
assign seq_first = 1'b1; // Tie high to enable default first_op when ZC_EXT=0
455+
assign seq_first = 1'b1; // Tie high to enable default first_op when ZC_EXT=0 // todo: Clean up semantics of seq_first and make this one default 0.
455456
end
456457
endgenerate
457458

@@ -465,6 +466,9 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
465466
assign tbljmp = (instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK)) ? 1'b0 :
466467
trigger_match_i ? 1'b0 : tbljmp_raw;
467468

469+
// todo: The above tbljmp assignment is likely very timing critical. Why is it important to suppress table jumps here, whereas the same thing is not done for non-sequenced compressed instructions nor for sequenced instructions.
470+
// In fact sequenced instructions seems only gated by trigger match, which also seems inconsistent. Can't all further handling of bus/parity/MPU/trigger match be done in ID?
471+
468472
//---------------------------------------------------------------------------
469473
// eXtension interface
470474
//---------------------------------------------------------------------------

rtl/cv32e40x_sequencer.sv

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import cv32e40x_pkg::*;
7272
assign rlist = instr[7:4];
7373

7474
// Count number of instructions emitted and set next state for FSM.
75-
always_ff @( posedge clk, negedge rst_n) begin
75+
always_ff @(posedge clk, negedge rst_n) begin
7676
if (!rst_n) begin
7777
instr_cnt_q <= '0;
7878
seq_state_q <= S_IDLE;
@@ -89,7 +89,7 @@ import cv32e40x_pkg::*;
8989

9090
if ((!valid_o && !halt_i) || kill_i) begin
9191
// Whenever we have no valid outputs and are not halted, reset counter to 0.
92-
// In case both halt_i and kill_i are high, kill_i takes presedence.
92+
// In case both halt_i and kill_i are high, kill_i takes precedence.
9393
// Not resetting if halted, as we might have to continue the sequence after being unhalted.
9494
instr_cnt_q <= '0;
9595
seq_state_q <= seq_state_n;
@@ -165,7 +165,7 @@ import cv32e40x_pkg::*;
165165
// In principle this is the same as "seq_en && valid_i"
166166
// as the output of the above decode logic is equivalent to seq_en
167167
// todo: halting IF stage would imply !valid, can this be an issue?
168-
// todo: revisit the error conditions below
168+
// todo: revisit the error conditions below (they are bad for the critical path; why can't they be done in ID?)
169169
assign valid_o = (seq_instr != INVALID_INST) && !instr_is_ptr_i && !(instr_i.bus_resp.err || !(instr_i.mpu_status == MPU_OK)) && valid_i && !halt_i && !kill_i;
170170

171171

@@ -205,7 +205,7 @@ import cv32e40x_pkg::*;
205205
seq_state_n = seq_state_q;
206206
seq_last_o = 1'b0;
207207
// default to 1, used by IF stage regardless of seq_valid
208-
// See explanation around combinatorial loops in the if_stage.sv.
208+
// See explanation around combinatorial loops in the if_stage.sv. // todo: reconsider, this is not clean enough
209209
seq_first_o = 1'b1;
210210
ready_o = 1'b0;
211211

sva/cv32e40x_controller_fsm_sva.sv

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ module cv32e40x_controller_fsm_sva
304304

305305
// Only include following assertions if X_EXT=1
306306
generate;
307-
if(X_EXT) begin
307+
if (X_EXT) begin
308308

309309
// Assert that a CSR instruction that is accepted by both eXtension interface and pipeline is
310310
// flagged as killed on the eXtension interface
@@ -360,11 +360,11 @@ generate;
360360
commit_kill_flag <= 1'b0;
361361
end else begin
362362
// Clear flag if EX is killed or instruction goes to WB
363-
if(ctrl_fsm_o.kill_ex || (ex_valid_i && wb_ready_i)) begin
363+
if (ctrl_fsm_o.kill_ex || (ex_valid_i && wb_ready_i)) begin
364364
commit_valid_flag <= 1'b0;
365365
commit_kill_flag <= 1'b0;
366366
// Set flag when commit_valid goes high
367-
end else if(xif_commit_valid) begin
367+
end else if (xif_commit_valid) begin
368368
commit_valid_flag <= 1'b1;
369369
commit_kill_flag <= xif_commit_kill;
370370
end
@@ -441,11 +441,11 @@ endgenerate
441441
retire_at_error <= 1'b0;
442442
end else begin
443443
// Req, no rvalid
444-
if( (m_c_obi_data_if.s_req.req && m_c_obi_data_if.s_gnt.gnt) && !m_c_obi_data_if.s_rvalid.rvalid) begin
444+
if (m_c_obi_data_if.s_req.req && m_c_obi_data_if.s_gnt.gnt && !m_c_obi_data_if.s_rvalid.rvalid) begin
445445
// Increase outstanding counter
446446
outstanding_count <= outstanding_count + 2'b01;
447447

448-
if(outstanding_count == 2'b00) begin
448+
if (outstanding_count == 2'b00) begin
449449
// No outstanding, assign first entry
450450
outstanding_type[0] <= m_c_obi_data_if.req_payload.we;
451451
end else begin
@@ -472,7 +472,7 @@ endgenerate
472472
end
473473

474474

475-
if(m_c_obi_data_if.s_rvalid.rvalid && m_c_obi_data_if.resp_payload.err && !bus_error_latched) begin
475+
if (m_c_obi_data_if.s_rvalid.rvalid && m_c_obi_data_if.resp_payload.err && !bus_error_latched) begin
476476
bus_error_is_write <= outstanding_count == 2'b01 ? outstanding_type[0] : outstanding_type[1];
477477
bus_error_latched <= 1'b1;
478478
retire_at_error <= wb_valid_i;
@@ -500,8 +500,8 @@ endgenerate
500500
if (rst_n == 1'b0) begin
501501
valid_cnt <= '0;
502502
end else begin
503-
if(bus_error_latched) begin
504-
if(wb_valid_i && last_op_wb_i && !ctrl_fsm_o.debug_mode && !(dcsr_i.step && !dcsr_i.stepie)) begin
503+
if (bus_error_latched) begin
504+
if (wb_valid_i && last_op_wb_i && !ctrl_fsm_o.debug_mode && !(dcsr_i.step && !dcsr_i.stepie)) begin
505505
valid_cnt <= valid_cnt + 1'b1;
506506
end
507507
end else begin
@@ -545,32 +545,34 @@ end // SMCLIC
545545
if (rst_n == 1'b0) begin
546546
first_op_done_wb <= 1'b0;
547547
end else begin
548-
if(!first_op_done_wb) begin
549-
if(wb_valid_i && ex_wb_pipe_i.first_op && !last_op_wb_i) begin
548+
if (!first_op_done_wb) begin
549+
if (wb_valid_i && ex_wb_pipe_i.first_op && !last_op_wb_i) begin
550550
first_op_done_wb <= 1'b1;
551551
end
552552
end else begin
553553
// first_op_done_wb is set, clear when last_op retires
554-
if(wb_valid_i && last_op_wb_i) begin
554+
if (wb_valid_i && last_op_wb_i) begin
555555
first_op_done_wb <= 1'b0;
556556
end
557557
end
558558
end
559559
end
560560

561+
// todo: make above code look the same as below code (add kill_wb related logic)
562+
561563
// Helper logic to track first_op and last_op through the ID stage to detect unhaltable sequences
562564
logic first_op_done_id;
563565
always_ff @(posedge clk, negedge rst_n) begin
564566
if (rst_n == 1'b0) begin
565567
first_op_done_id <= 1'b0;
566568
end else begin
567-
if(!first_op_done_id) begin
568-
if(id_valid_i && ex_ready_i && first_op_id_i && !last_op_id_i) begin
569+
if (!first_op_done_id) begin
570+
if (id_valid_i && ex_ready_i && first_op_id_i && !last_op_id_i) begin
569571
first_op_done_id <= 1'b1;
570572
end
571573
end else begin
572574
// first_op_done_id is set, clear when last_op retires
573-
if(id_valid_i && ex_ready_i && last_op_id_i) begin
575+
if (id_valid_i && ex_ready_i && last_op_id_i) begin
574576
first_op_done_id <= 1'b0;
575577
end
576578
end
@@ -586,21 +588,23 @@ end // SMCLIC
586588
(first_op_done_wb |-> !ctrl_fsm_o.irq_ack))
587589
else `uvm_error("controller", "Sequence broken by interrupt")
588590

591+
// todo: add equivalency check related to first_op_done_wb computation and sequence_interruptible
592+
589593
a_no_sequence_nmi:
590594
assert property (@(posedge clk) disable iff (!rst_n)
591595
(first_op_done_wb |-> !(ctrl_fsm_o.pc_set && (ctrl_fsm_o.pc_mux == PC_TRAP_NMI))))
592596
else `uvm_error("controller", "Sequence broken by NMI")
593597

594598
a_no_sequence_ext_debug:
595599
assert property (@(posedge clk) disable iff (!rst_n)
596-
(first_op_done_wb |-> !(ctrl_fsm_o.dbg_ack && (debug_cause_q == DBG_CAUSE_HALTREQ))))
600+
(first_op_done_wb |-> !(ctrl_fsm_o.dbg_ack && (debug_cause_q == DBG_CAUSE_HALTREQ)))) // todo: timing of (debug_cause_q == DBG_CAUSE_HALTREQ) seems wrong (and whole calsuse should not be needed)
597601
else `uvm_error("controller", "Sequence broken by external debug")
598602

599603
// Check that we do not allow ID stage to be halted for pending interrupts/debug if a sequence is not done
600604
// in the ID stage.
601605
a_id_stage_haltable:
602606
assert property (@(posedge clk) disable iff (!rst_n)
603-
(first_op_done_id |-> !id_stage_haltable))
607+
(first_op_done_id |-> !id_stage_haltable)) // todo: proof equivalency, not just implication
604608
else `uvm_error("controller", "id_stage_haltable not correct")
605609

606610
// Assert that we have no pc_set in the same cycle as a CSR write in WB requires flushing of the pipeline

sva/cv32e40x_core_sva.sv

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ module cv32e40x_core_sva
8383
input mcause_t cs_registers_mcause_q, // From cs_registers, flopped mcause
8484
input mstatus_t cs_registers_mstatus_q);
8585

86-
if(SMCLIC) begin
86+
if (SMCLIC) begin
8787
property p_clic_mie_tieoff;
8888
@(posedge clk)
8989
|mie == 1'b0;
@@ -224,7 +224,7 @@ always_ff @(posedge clk , negedge rst_ni)
224224
end
225225
else begin
226226
// Disregard saved CSR due to interrupts when chekcing exceptions
227-
if(!cs_registers_csr_cause_i.irq) begin
227+
if (!cs_registers_csr_cause_i.irq) begin
228228
if (!first_cause_illegal_found && (cs_registers_csr_cause_i.exception_code == EXC_CAUSE_ILLEGAL_INSN) && ctrl_fsm.csr_save_cause) begin
229229
first_cause_illegal_found <= 1'b1;
230230
actual_illegal_mepc <= cs_registers_mepc_n;
@@ -296,7 +296,7 @@ always_ff @(posedge clk , negedge rst_ni)
296296
// For checking single step, ID stage is used as it contains a 'multi_cycle_id_stall' signal.
297297
// This makes it easy to count misaligned LSU ins as one instruction instead of two.
298298
logic inst_taken;
299-
assign inst_taken = id_stage_id_valid && ex_ready && if_id_pipe.last_op && !id_stage_multi_cycle_id_stall;
299+
assign inst_taken = id_stage_id_valid && ex_ready && if_id_pipe.last_op && !id_stage_multi_cycle_id_stall; // todo: the && !id_stage_multi_cycle_id_stall signal should now no longer be needed
300300

301301
// Support for single step assertion
302302
// In case of single step + taken interrupt, the first instruction
@@ -309,9 +309,9 @@ always_ff @(posedge clk , negedge rst_ni)
309309
interrupt_taken <= 1'b0;
310310
end
311311
else begin
312-
if(irq_ack == 1'b1) begin
312+
if (irq_ack == 1'b1) begin
313313
interrupt_taken <= 1'b1;
314-
end else if(ctrl_debug_mode_n) begin
314+
end else if (ctrl_debug_mode_n) begin
315315
interrupt_taken <= 1'b0;
316316
end
317317
end
@@ -327,6 +327,8 @@ always_ff @(posedge clk , negedge rst_ni)
327327
|-> (ctrl_fsm.debug_mode && dcsr.step))
328328
else `uvm_error("core", "Assertion a_single_step_no_irq failed")
329329

330+
// todo: add similar assertion as above to check that only one instruction moves from IF to ID while taking a single step (rename inst_taken to inst_taken_id and introduce similar inst_taken_if signal)
331+
330332
if (SMCLIC) begin
331333
// Non-SHV interrupt taken during single stepping.
332334
// If this happens, no instructions should retire until the core is in debug mode.

sva/cv32e40x_if_stage_sva.sv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,5 @@ module cv32e40x_if_stage_sva
8080
ctrl_fsm_i.kill_if |-> (seq_ready && !seq_valid))
8181
else `uvm_error("if_stage", "Kill should imply ready and not valid.")
8282

83-
8483
endmodule // cv32e40x_if_stage
8584

0 commit comments

Comments
 (0)