package PinSync; // mkPinSync builds a synchronizer for use with asynchronous inputs. // // You should only use this to capture asynchronous inputs coming from // outside your design. For clock domain crossing within your design, // use the dual-clocked synchronizers found in Bluespec's standard // library. // // As the name suggests, mkPinSync is intended to be used to // synchronize data coming into your design from an external pin, such // as the RX line of a UART. Such signals do not run according to a // known clock, so the regular stdlib synchronizers cannot be used as // there's no "source" clock we can provide them. // // You can think of mkPinSync as the output end of a standard // synchronizer, without the initial register that's clocked by the // source domain. Conceptually, we assume that register exists outside // our design and is driving the input of mkPinSync, so we just need // the metastability mitigation within our own domain. module mkPinSync(val init_value, Reg#(val) ifc) provisos(Bits#(val, _)); Reg#(val) r1 <- mkReg(init_value); Reg#(val) r2 <- mkReg(init_value); // To break write+read conflicts. Without this, a rule that // atomically reads the sync while also writing it fails to // schedule vs. the 'every' rule below. This shouldn't really // happen in real designs, but it's a convenient idiom in // testing. The wire is free in terms of logic, so might as well // make atomic read+write work. Wire#(val) out <- mkBypassWire(); (* no_implicit_conditions, fire_when_enabled *) rule every; out <= r2; r2 <= r1; endrule method _read = out._read; method _write = r1._write; endmodule endpackage