Using guarded atomic actions is an old and well-loved design paradigm.
Every operation has a guard predicate: says when it CAN be run.
Operations are grouped into rules for atomic execution where the rule takes on the conjunction of its atomic operation guards and the rule may have its own additional guard predicate.
Operations have the expectation they WILL be run (fairness).
A compiler can direct scheduling decisions to span various power/performance implementations for a given program.
Recently BlueSpec System Verilog has successfully raised the level of abstraction in RTL design using this paradigm.
The term `wiring' above is used in the sense of TLM models: binding initiators to target methods.
»LINK: Small Examples»Toy BSV Compiler (DJG) First basic example: two rules: one increments, the other exits the simulation. This example looks very much like RTL: provides an easy entry for hardware engineers.
module mkTb (Empty); Reg#(int) x <- mkReg (23); rule countup (x < 30); int y = x + 1; // This is short for int y = x.read() + 1; x <= x + 1; // This is short for x.write(x.read() + 1); $display ("x = %0d, y = %0d", x, y); endrule rule done (x >= 30); $finish (0); endrule endmodule: mkTb
Second example uses a pipeline object that could have aribtrary delay. Sending process is blocked by implied handshaking wires (hence less typing than Verilog) and in the future would allow the programmer or the compiler to retime the implementation of the pipe component.
module mkTb (Empty); Reg#(int) x <- mkReg ('h10); Pipe_ifc pipe <- mkPipe; rule fill; pipe.send (x); x <= x + 'h10; // This is short for x.write(x.read() + 'h10); endrule rule drain; let y = pipe.receive(); $display (" y = %0h", y); if (y > 'h80) $finish(0); endrule endmodule
But, behavioural expression using a conceptual thread is also useful to have, so BlueSpec has a behavioural sub-language compiler built in.