@@ -1166,6 +1166,83 @@ module ibex_top import ibex_pkg::*; #(
1166
1166
1167
1167
// data_err_i relevant to both reads and writes. Check it isn't X on any response.
1168
1168
`ASSERT_KNOWN_IF (IbexDataRErrPayloadX, data_err_i, data_rvalid_i)
1169
+
1170
+ // Tracking logic and predictor for double_fault_seen_o output
1171
+
1172
+ // Returns 1'b1 if the provided instruction decodes to one that would write the sync_exc_bit of
1173
+ // the CPUCTRLSTS CSR
1174
+ function automatic logic insn_write_sync_exc_seen (logic [31 : 0 ] insn_bits);
1175
+ return (insn_bits[6 : 0 ] == OPCODE_SYSTEM ) &&
1176
+ (insn_bits[14 : 12 ] inside { 3'b001 , 3'b010 , 3'b011 , 3'b101 } ) &&
1177
+ (insn_bits[31 : 20 ] == CSR_CPUCTRLSTS );
1178
+ endfunction
1179
+
1180
+ // Given an instruction that writes the sync_exc_bit of the CPUCTRLSTS CSR along with the value
1181
+ // of the rs1 register read for that instruction and the current predicted sync_exc_bit bit
1182
+ // return the new value of the sync_exc_bit after the instruction is executed.
1183
+ function automatic logic new_sync_exc_bit (logic [31 : 0 ] insn_bits, logic [31 : 0 ] rs1,
1184
+ logic cur_bit);
1185
+ logic sync_exc_update_bit;
1186
+
1187
+ sync_exc_update_bit = insn_bits[14 ] ? 1'b0 : rs1[6 ];
1188
+
1189
+ case (insn_bits[13 : 12 ])
1190
+ 2'b01 : return sync_exc_update_bit;
1191
+ 2'b10 : return cur_bit | sync_exc_update_bit;
1192
+ 2'b11 : return cur_bit & ~ sync_exc_update_bit;
1193
+ default : return 1'bx ;
1194
+ endcase
1195
+ endfunction
1196
+
1197
+ localparam int DoubleFaultSeenLatency = 3 ;
1198
+ logic [DoubleFaultSeenLatency- 1 : 0 ] double_fault_seen_delay_buffer;
1199
+ logic [DoubleFaultSeenLatency- 2 : 0 ] double_fault_seen_delay_buffer_q;
1200
+ logic sync_exc_seen;
1201
+ logic new_sync_exc;
1202
+ logic double_fault_seen_predicted;
1203
+
1204
+ assign new_sync_exc = rvfi_valid & rvfi_trap & ~ rvfi_ext_debug_mode;
1205
+ assign double_fault_seen_predicted = sync_exc_seen & new_sync_exc;
1206
+
1207
+ // Depending on whether the exception comes from the WB or ID/EX stage the precise timing of the
1208
+ // double_fault_seen_o output vs the double fault instruction being visible on RVFI differs. At
1209
+ // the earliest extreme it can be asserted the same cycle the instruction is visible on the
1210
+ // RVFI. Buffer the last few cycles of double_fault_seen_o output for checking. We can
1211
+ // guarantee the minimum spacing between double_fault_seen_o assertions (occurring when the
1212
+ // first instruction of an exception handler continuously double faults with a single cycle
1213
+ // memory access time) is sufficient that we'll only see a single bit set in the delay buffer.
1214
+ assign double_fault_seen_delay_buffer = { double_fault_seen_delay_buffer_q, double_fault_seen_o} ;
1215
+
1216
+ always @ (posedge clk_i or negedge rst_ni) begin
1217
+ if (! rst_ni) begin
1218
+ double_fault_seen_delay_buffer_q <= '0 ;
1219
+ sync_exc_seen <= 1'b0 ;
1220
+ end else begin
1221
+ double_fault_seen_delay_buffer_q <=
1222
+ double_fault_seen_delay_buffer[DoubleFaultSeenLatency- 2 : 0 ];
1223
+
1224
+ if (new_sync_exc) begin
1225
+ // Set flag when we see a new synchronous exception
1226
+ sync_exc_seen <= 1'b1 ;
1227
+ end else if (rvfi_valid && rvfi_insn == 32'h30200073 ) begin
1228
+ // Clear flag when we see an MRET
1229
+ sync_exc_seen <= 1'b0 ;
1230
+ end else if (rvfi_valid && insn_write_sync_exc_seen (rvfi_insn)) begin
1231
+ // Update predicted sync_exc_seen when the instruction modifies the relevant CPUCTRLSTS CSR
1232
+ // bit.
1233
+ sync_exc_seen <= new_sync_exc_bit (rvfi_insn, rvfi_rs1_rdata, sync_exc_seen);
1234
+ end
1235
+ end
1236
+ end
1237
+
1238
+ // We should only have a single assertion of double_fault_seen in the delay buffer
1239
+ `ASSERT (DoubleFaultSinglePulse, $onehot0 (double_fault_seen_delay_buffer))
1240
+ // If we predict a double_fault_seen_o we should see one in the delay buffer
1241
+ `ASSERT (DoubleFaultPulseSeenOnDoubleFault,
1242
+ double_fault_seen_predicted | - > | double_fault_seen_delay_buffer)
1243
+ // If double_fault_seen_o is asserted we should see predict one occurring within a bounded time
1244
+ `ASSERT (DoubleFaultPulseOnlyOnDoubleFault,
1245
+ double_fault_seen_o | - > ## [0 : DoubleFaultSeenLatency] double_fault_seen_predicted)
1169
1246
`endif
1170
1247
1171
1248
`ASSERT_KNOWN (IbexIrqX, { irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i} )
0 commit comments