开云体育

ctrl + shift + ? for shortcuts
© 2025 开云体育

Can Fire and Will Fire enabled even though rule doesn't fire in Sim


 

The following rule doesn't trigger in simulation which is the expected behavior. I know it doesn't trigger because un-commenting `$display "clientRequest" (fshow clientRequest)` never prints anything. Oddly enough however, it seems `WILL_FIRE` and `CAN_FIRE` are always high in the generated VCD... Why is this? The reason this rule ?shouldn't trigger is because `first` method of a FIFO is guarded which becomes an implicit condition for the containing rule. When it comes to this code, I call `selectedClientRequestQueue.first` which becomes an implicit guard condition for the rule.
?
Here's the relevant code snippet below for easy access:

```
? ? ? ? ? ? ? ? rules
? ? ? ? ? ? ? ? ? ? (sprintf "request server from client %d" clientIdx): when True ==> do
? ? ? ? ? ? ? ? ? ? ? ? let
? ? ? ? ? ? ? ? ? ? ? ? ? ? clientRequest :: TaggedBusRequest inFlightTransactions
? ? ? ? ? ? ? ? ? ? ? ? ? ? clientRequest = selectedClientRequestQueue.first
? ? ? ? ? ? ? ? ? ? ? ? ? ? targetAddr :: Addr = busRequestToAddr |> clientRequest.busRequest
? ? ? ? ? ? ? ? ? ? ? ? ? ? targetServerIdx :: (Maybe ServerIdx) = serverMap targetAddr
? ? ? ? ? ? ? ? ? ? ? ? -- $display "clientRequest" (fshow clientRequest)
? ? ? ? ? ? ? ? ? ? ? ? case targetServerIdx of
? ? ? ? ? ? ? ? ? ? ? ? ? ? Just serverIdx -> do
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? let
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? targetServerArbiter :: Arbiter.Arbiter_IFC numClients
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? targetServerArbiter = (select requestArbiterByServer serverIdx)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? arbiterClientSlot :: Arbiter.ArbiterClient_IFC
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? arbiterClientSlot = (select targetServerArbiter.clients clientIdx)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? arbiterClientSlot.request
? ? ? ? ? ? ? ? ? ? ? ? ? ? Nothing -> do action {}
```
?
Full reference code here:


 

It gets even more interesting! So if I do something simple in the rule "request server from client 0" such as
?
`$display "hello"`
?
, it fires in sim and prints "hello"... But if I do
?
`$display "Bus.bs:81" (fshow clientRequest)`
?
, it doesn't fire in sim... This is also reflected in the emitted VCD which shows `CAN_FIRE` and `WILL_FIRE` as 0...
?
So even though we assigned `clientRequest = selectedClientRequestQueue.first` earlier(we know that `selectedClientRequestQueue.first` is guarded, the compiler seems to ignore this assignment until we actually do something with the assignment such as read it in a display...
?
It seems then that as far as the compiler is concerned, even if you assign a value, if you don't observe it, then that assignment is not an implicit condition for the rule?


 

It seems then that as far as the compiler is concerned, even if you assign a value, if you don't observe it, then that assignment is not an implicit condition for the rule?
?
Given that observation, it looks like the compiler is removing the implicit condition along with the unused expression--changing the externally observable behavior of the code in question and not preserving semantics.? I decided to experiment a bit and I got some interesting results.? Given:
?
(* synthesize *)
module mkDeadCode(Empty);
? ?FIFOF#(Bit#(4)) fifo <- mkFIFOF;
? ?rule rule1;
? ? ? $display("rule1");
? ?endrule
? ?rule rule2;
? ? ? $display("rule2 ", fifo.first);
? ?endrule
? ?rule rule3;
? ? ? Bit#(4) temp = fifo.first;
? ? ? $display("rule3");
? ?endrule
? ?rule rule4 if (fifo.first >= 0);
? ? ? $display("rule4");
? ?endrule
? ?rule rule5 if (fifo.first >= 0 || True);
? ? ? $display("rule5");
? ?endrule
? ?rule rule6 if (True || fifo.first >= 0);
? ? ? $display("rule6");
? ?endrule
endmodule
?
I got this for the schedule:
?
Rule: rule1
Predicate: True
Blocking rules: (none)
?
Rule: rule2
Predicate: fifo.i_notEmpty
Blocking rules: (none)
?
Rule: rule3
Predicate: True
Blocking rules: (none)
?
Rule: rule4
Predicate: fifo.i_notEmpty
Blocking rules: (none)
?
Rule: rule5
Predicate: fifo.i_notEmpty
Blocking rules: (none)
?
Rule: rule6
Predicate: True
Blocking rules: (none)
?
and the following verilog:
?
? always@(negedge CLK)
? begin
? ? #0;
? ? $display("rule1");
? ? if (RST_N != `BSV_RESET_VALUE)
? ? ? if (fifo$EMPTY_N) $display("rule2 ", fifo$D_OUT);
? ? $display("rule3");
? ? if (RST_N != `BSV_RESET_VALUE) if (fifo$EMPTY_N) $display("rule4");
? ? if (RST_N != `BSV_RESET_VALUE) if (fifo$EMPTY_N) $display("rule5");
? ? $display("rule6");
? end
?
rule1 and rule2 are there to establish a baseline.
?
rule3 replicates your observation.
?
rule4 was my attempt to trigger a similar change of semantics with an explicit condition that could be optimize away.? The comparison was removed from the verilog, but the not-empty condition stuck around.
?
rule5 was a further attempt to to make it easier for the compiler to detect that the condition was degenerate.? No change from rule4.
?
But just switching the order of operands to the logical-or in rule6 did cause the condition to disappear from both the schedule and the verilog!? I don't recall seeing anything saying that the logical-and/or operators are short-circuiting like in C/C++.? (Does such a notion even make sense in an HDL?)
?
-William
?
?