Purely synchronous design is based upon the principle that all state elements (dtypes) can only be changed on a single event trigger (for instance, a positive clock edge).
One of the key benefits of this is that glitches on a control line do not lead to unexpected changes since when they take effect (on the trigger event) the glitch will have gone away.
In some styles of Verilog, an output is continuously updated by enclosing it in an always block and putting all of its inputs on the event list. Thus a s-1 multiplexor could be:
module contAss_A(out, cnt, a, b); output out; input cnt, a, b; reg out; always @(cnt or a or b) out = cnt ? a: b; endmodule // contAss
In some cases this permits clarity as in:
module contAss_B(out, cnt, a, b); output out; input cnt, a, b; reg out; always @(cnt or a or b) if (cnt == 1) out = a; else if (cnt == 0) out = b; else $display("unexpected value for cnt (%b)", cnt); endmodule
module contAss_C(out, cnt, a, b); output out; input cnt, a, b; assign out = cnt ? a: b; endmodule
In the first two examples, the reg declaration was simply made to allow the assignment within an always block: there was NO intended correspondence with a "register" which would hold the value of out (since the code states that this changes whenever the input changes). However, when we DO want a software equivalent of a state element there should be ONLY ONE ENTRY ON THE EVENT list.
Thus the basic, bog-standard Dtype is:
module dtype(out, clk, d); output out; input clk, d; reg out; always @(posedge clk) out = d; endmodule
It is simple to enhance this module with additional functionality. Thus, for instance, we can add a synchronous reset:
module dtype_r(out, clk, reset, d); output out; input clk, reset, d; reg out; always @(posedge clk) if (reset == 1) out = 0; else out = d; endmodule
module Etype_s(out, clk, enable, set, d); output out; input clk, enable, set, d; reg out; always @(posedge clk) if (set == 1) out = 1; else if (enable == 1) out = d; endmodule
To repeat: in synchronous design, there should only be one (edge-triggered) event guarding the always statements which implement state elements.
Thus the following is NOT recommended:
module dtype_A_r(out, clk, reset, d); output out; input clk, reset, d; reg out; always @(posedge clk or posedge reset) if (reset == 1) out = 0; else out = d; endmodule
Of course, the state elements do not need to be as simple as these examples. For instance. they could be:
Synchronous design assumes that all signals settled down when the next active clock edge arrives. Thus any inputs which we provide as test vectors should also be "settled down" on the active clock edge.
In general, we provide a clock signal: clk with code such as:
reg clk; initial begin clk = 0; forever #50 clk = ~clk; end
initial begin a = 0; #100 a = 1; #800 a = 0; #100 a = 1; #200 $finish; end
time | incr | a = |
0 | #0 | 0 |
100 | #100 | 1 |
900 | #800 | 0 |
1000 | #100 | 1 |
1200 | #200 | STOP |
By the same token, we can set up a $display command to catch the outputs of our circuit at some time after the active clock edge (giving enough time for the signals to all settle down. Thus:
initial #40 forever #100 $display("output = %d", out);
always @(posedge clk) out = d; always @(posedge clk) $display("output = %d", out);
always @(posedge clk) #1 $display("output = %d", out);
Putting these ideas together gives us a test module such as:
module testsync; reg [3:0] a,b; reg clk; initial begin clk = 0; forever #50 clk = ~clk; end initial begin a = 0; #100 a = 1; #800 a = 2; #100 a = 3; #200 $finish; end initial #40 forever #100 $display($time, " input = %d output = %d", a, b); always @(posedge clk) b = a; endmodule // testsync