Describe the bug
When simulating the Muntjac core using an event-driven simulator like Vivado XSIM, the simulation fails immediately at $t=0$ with a fatal iteration limit error: Fatal Error: Iteration limit reached. Possible zero delay oscillation detected where simulation time can not advance.
This is caused by a circular combinatorial dependency violating standard valid/ready handshake rules: the backend's req_valid signal combinationally depends on the cache's req_ready signal, but the cache's req_ready signal combinationally depends on req_valid through its internal arbiter.
While cycle-based simulators like Verilator may mask this zero-delay loop, event-driven simulators (like XSIM) get stuck in an infinite evaluation loop within a single delta cycle.
Steps to Reproduce
- Instantiate
muntjac_core in a testbench.
- Simulate using Vivado XSIM.
- The simulator immediately aborts at time 0 ps with an iteration limit error.
Root Cause / Trace
The combinatorial loop can be traced as follows:
1. muntjac_backend.sv (Cache Ready blocks Request Valid):
- Line 1074:
assign mem_ready = dcache_d2h_i.req_ready;
- Line 335: In the
OP_MEM case of always_comb, if !mem_ready, struct_hazard is asserted: if (!mem_ready) struct_hazard = 1'b1;
- Line 407:
ex_issue depends on !struct_hazard.
- Line 1058:
dcache_h2d_o.req_valid is gated by ex_issue: assign dcache_h2d_o.req_valid = ex_issue && de_ex_decoded.op_type == OP_MEM;
(Result: The backend waits for the cache to be ready before asserting valid).
2. muntjac_dcache.sv / muntjac_icache.sv (Request Valid drives Cache Ready):
- Line 330:
wire req_valid = cache_h2d_i.req_valid;
- Line 2024: (and others)
req_valid feeds into mem_a_valid_mult.
- Line 389-393:
mem_a_valid_mult feeds into openip_round_robin_arbiter's request and enable ports.
- Line 407: The arbiter's
grant output (mem_a_arb_grant) drives mem_a_selected (and ultimately mem_a_select).
- Line 419:
mem_a_ready_mult[i] = mem_a_select[i] && mem_a_ready;
- Line 1248/1802+:
mem_a_ready_mult combinationally drives cache_d2h_o.req_ready.
(Result: The cache waits for a valid request to arbitrate before asserting ready).
Describe the bug
When simulating the Muntjac core using an event-driven simulator like Vivado XSIM, the simulation fails immediately at$t=0$ with a fatal iteration limit error:
Fatal Error: Iteration limit reached. Possible zero delay oscillation detected where simulation time can not advance.This is caused by a circular combinatorial dependency violating standard valid/ready handshake rules: the backend's
req_validsignal combinationally depends on the cache'sreq_readysignal, but the cache'sreq_readysignal combinationally depends onreq_validthrough its internal arbiter.While cycle-based simulators like Verilator may mask this zero-delay loop, event-driven simulators (like XSIM) get stuck in an infinite evaluation loop within a single delta cycle.
Steps to Reproduce
muntjac_corein a testbench.Root Cause / Trace
The combinatorial loop can be traced as follows:
1.
muntjac_backend.sv(Cache Ready blocks Request Valid):assign mem_ready = dcache_d2h_i.req_ready;OP_MEMcase ofalways_comb, if!mem_ready,struct_hazardis asserted:if (!mem_ready) struct_hazard = 1'b1;ex_issuedepends on!struct_hazard.dcache_h2d_o.req_validis gated byex_issue:assign dcache_h2d_o.req_valid = ex_issue && de_ex_decoded.op_type == OP_MEM;(Result: The backend waits for the cache to be ready before asserting valid).
2.
muntjac_dcache.sv/muntjac_icache.sv(Request Valid drives Cache Ready):wire req_valid = cache_h2d_i.req_valid;req_validfeeds intomem_a_valid_mult.mem_a_valid_multfeeds intoopenip_round_robin_arbiter'srequestandenableports.grantoutput (mem_a_arb_grant) drivesmem_a_selected(and ultimatelymem_a_select).mem_a_ready_mult[i] = mem_a_select[i] && mem_a_ready;mem_a_ready_multcombinationally drivescache_d2h_o.req_ready.(Result: The cache waits for a valid request to arbitrate before asserting ready).