|This error occurs when mkNullCrossingWire is used and the compiler can not schedule it such that is was the first rule to fire in the schedule for the required cycle.|
code generation for mkSnoopXtor starts
Error: "Clocks.bsv", line 1538, column 9: (G0005)
The assertion `can_schedule_first' failed for rule
because before it can be executed:
RL_xferSnoop must be executed
The data input of mkNullCrossingWire must effectively be driven directly from a registered output and not have a implicit condition. In the error message above, RL_xferSnoop is a rule that drives a wire that drives the data input to the mkNullCrossingWire. This means that RL_xferSnoop is ordered in the schedule before the firing of the "clock_domain_crossing" rule inside mkNullCrossingWire.
This is fixed most easily by driving data directly from a register to the enable, or at least through a rule that always fires and have combinational logic driving the data in. i.e.
Reg#(int) din <- mkRegU;
ReadOnly data <- mkNullCrossingWire( dstClk, din, clocked_by srcClk, reset_by srcReset );
This is necessary to ensure atomicity in Bluespec designs. However, it is also good hardware practice to be cautious of clock domain crossing (not discussed here).
Another option is to use the deprecated mkNullCrossing, which doesn't necessarily ensure atomicity across the clock boundaries (and also does not work with Bluesim for exactly this reason). But if you understand the logic you are generating, and a wire if functionally okay there, you can use mkNullCrossing to generate verilog. But be warned that the compiler cannot guarantee atomicity across the clock boundary... So be sure you understand what the logic is doing.