The term “asynchronous” can refer to several different scenarios. Here is a brief description of some more common scenarios that we will study:
Asynchronous handshaking is an important technique for coordinating processes that have variable timing. To illustrate this concept, consider a competitive foot race with three states:
To coordinate this race, the officials use three flags for signaling: ready
, start
, and done
. Before the competitors can line up, all three flags must be LOW. Once the runners are in position, the ready
flag can go HIGH.
When the race official sees the ready
flag, the start
flag may go HIGH to start the race. Meanwhile, down at the finish line, once the start
flag goes HIGH a race observer watches the runners to verify when they have all completed the race. At the end, the done
flag goes HIGH.
At any time after raising the start
flag, the ready
flag can by lowered since the runners are no longer in the ready position. Once the done
flag goes HIGH, the start
flag may be lowered since the race is over. After the start
flag is lowered, the done
flag can go LOW again. Once all three flags are LOW, another set of runners can queue up at the starting line to begin another race.
The timing of this handshaking dance is shown in the figure below. Two race events are shown. The run time is indicated for each race, as well as the delay between races. Both the run time and delay can vary from one race to the next. Since the schedule is not absolute and repeatable, we need to use handshaking with the flags.
A state transition diagram for the handshaking protocol is shown below. This state diagram responds to two inputs: ready
and done
. It controls one output: start
. Elsewhere in the design, there must be other state machines that control the ready
and done
signals.
In digital systems, the “runners” represent data. The “race” represents some process that uses the data, where the process may take an unknown number of clock cycles to complete. We model this system using two modules: the race_official
and the race_observer
. The race_official
is implemented as follows:
module race_official
(input clk,
input rst_l,
input ready,
input done,
output reg start
);
reg [1:0] state;
always @(posedge clk, negedge rst) begin
// ACTIVE-LOW RESET:
if (!rst_l) begin
0;
state <= 0;
start <= end
// NORMAL (NON-RESET) BEHAVIOR:
else begin
case (state)
0: begin
if (ready) begin
1;
start <= 1;
state <= end
else
0;
start <= end
1: begin
if (done) begin
0;
start <= 2;
state <= end
end
2: begin
if (!done && !ready)
0;
state <= end
default:
begin
0;
start <= 0;
state <= end
endcase
end
end
endmodule
Some important features of this model:
state
signal is two bits wide, since there are three states. In Verilog, it’s crucial to declare an adequate number of bits for state variables. One of the most common design errors is to declare too few bits; if our state
variable had only one bit, it would never reach state 2.case
statement has a default
condition. This is necessary since a hardware state machine could find itself in an erroneous state (e.g. state 3) due to some electrical error. If that happens, it needs a way to recover from the fault.race_observer
moduleDesign a state machine and Verilog module for the race_observer
, according to these specifications:
clk
, rst_l
, start
done
!rst_l
, done
goes LOW!start
, done
goes LOWstart
, done
goes HIGH after a random delay.random_timer
submoduleTo simulate a random delay, use this non-synthesizeable random_timer
submodule:
module random_timer
(input clk,
output reg t
);
reg [1:0] r; // random number
always @(posedge clk) begin
$random();
r <= if (r == 0)
1;
t <= else
0;
t <= end
endmodule
In your race_observer
module, place an instance of random_timer
and connect it to a wire
named t
:
wire t;
random_timer rt1 (.clk(clk), .t(t));
Create a state transition diagram for race_observer
. The diagram’s conditions should involve start
, rst_l
and t
. The diagram’s assignments should act on done
. Use the t
signal as a condition for all transitions, e.g. done
can only go high when t==1
. Scan or save the diagram in a graphical format in this assignment directory, with filename diagram.png
or diagram.jpg
or whatever graphics type you prefer to use. Implement the diagram’s state-transition logic in a file named src/race_observer.v
.
Once your race_observer
is complete, type make simulate
to simulate the official/observer handshaking. One handshaking event should look something like the example shown below, progressing from all-zeros to ready, then start, then done, then back to zeros.
clk: 5 ready: 0 start: 0 done: 0 start_state: 0 done_state: 0
clk: 6 ready: 0 start: 0 done: 0 start_state: 0 done_state: 0
clk: 7 ready: 0 start: 0 done: 0 start_state: 0 done_state: 0
clk: 8 ready: 0 start: 0 done: 0 start_state: 0 done_state: 0
clk: 9 ready: 1 start: 0 done: 0 start_state: 0 done_state: 0
clk: 10 ready: 1 start: 1 done: 0 start_state: 1 done_state: 0
clk: 11 ready: 0 start: 1 done: 0 start_state: 1 done_state: 1
clk: 12 ready: 0 start: 1 done: 0 start_state: 1 done_state: 1
clk: 13 ready: 0 start: 1 done: 0 start_state: 1 done_state: 1
clk: 14 ready: 0 start: 1 done: 0 start_state: 1 done_state: 1
clk: 15 ready: 0 start: 1 done: 1 start_state: 1 done_state: 2
clk: 16 ready: 0 start: 0 done: 1 start_state: 2 done_state: 2
clk: 17 ready: 0 start: 0 done: 0 start_state: 2 done_state: 0
clk: 18 ready: 0 start: 0 done: 0 start_state: 0 done_state: 0
clk: 19 ready: 1 start: 0 done: 0 start_state: 0 done_state: 0
Study the output to verify that the handshaking process is correct, you should note several races are completed, with each race taking different times to complete. Examine the ready
signal and note the minimum and maximum delays between races. Similarly, examine the done
signal and measure the minimum and maximum running time.
Turn in your work using git
:
git add diagram* src/*.v *.txt
git commit . -m "Complete"
git push origin master
Indicate on Canvas that your assignment is done.