The following Verilog code has five major sub-modules:
As with all good synchronous modules, a global_reset signal is included so that the latches can be put into a known state at the start of testing.
The code follows:
// Universal Asynchronous Receiver
// Start detection
module start_detect (valid, clk, reset, gl_reset, dIn);
output valid;
input clk, reset, gl_reset, dIn;
reg [3:0] shift_reg;
always @ (posedge clk) begin
if (reset | gl_reset)
shift_reg = 0;
else
shift_reg = { shift_reg[2:0], dIn };
end
assign valid = (shift_reg [0] == 0) &
(shift_reg [2] == 0) &
(shift_reg [3] == 1);
endmodule
// controller
module counter (count72, count8, clk, enable);
output count72, count8;
input clk, enable;
wire each8;
reg [8:0] count_reg;
always @ (posedge clk)
if (enable == 0)
count_reg <= 0;
else begin
count_reg <= count_reg + 1;
end
assign each8 = ((count_reg % 8) == 7);
assign count72 = (count_reg == 71);
assign count8 = each8 & ~count72;
endmodule
// serial parallel converter
module ser_par_conv (dOut, clk, enable, dIn);
output [7:0] dOut;
input clk, enable, dIn;
reg [7:0] dOut;
always @ (posedge clk)
if (enable == 1)
dOut = {dIn, dOut[7:1]};
endmodule
// flags for ready and data error
module flags (dReady, dError, clk, set, reset, dIn);
output dReady, dError;
input clk, set, reset, dIn;
reg dReady, dError;
always @(posedge clk)
if (reset == 1) begin
dReady = 0;
dError = 0;
end
else if (set == 1) begin
dReady <= dIn;
dError <= ~dIn;
end
initial $monitor("dReady %b %b", dReady, dError, $time);
endmodule
// generating the run signals
module control (running, clk, reset, gl_reset, set);
output running;
input clk, reset, gl_reset, set;
reg running;
always @ (posedge clk)
if ((reset == 1) | (gl_reset == 1))
running = 0;
else if (set == 1)
running = 1;
endmodule
// overall receiver definition
module uar (dOut, dReady, dError, clk, gl_reset, dIn);
output [7:0] dOut;
output dReady, dError;
input clk, gl_reset, dIn;
wire running, finish, count8, start;
start_detect s_d (start, clk, running, gl_reset, dIn);
counter cov (finish, count8, clk, running);
ser_par_conv s_p (dOut, clk, count8, dIn);
flags fla (dReady, dError, clk, finish, start, dIn);
control con (running, clk, finish, gl_reset, start);
endmodule
// test module
module mytest;
reg clk, gl_reset, dIn;
wire [7:0] dOut;
wire dReady, dError;
reg [7:0] inWord;
uar mod1 (dOut, dReady, dError, clk, gl_reset, dIn);
always #5 clk = ~clk;
initial begin
#0
clk = 0;
gl_reset = 1;
inWord = 0;
dIn = 1;
#10
gl_reset = 0;
#80
repeat (4) begin
// start of cycle
inWord = {$random} /2 % 128;
dIn = 1;
#80
dIn = 0;
#80
$display ("inWord = %b", inWord, $time);
repeat (8) begin
dIn <= inWord[0];
inWord <= inWord >> 1;
#80;
end
$display ("outWord = %b (%b %b)", dOut, dReady, dError);
end
// error condition 1
dIn = 1;
#80
dIn = 0;
#800
$display ("outWord = %b (%b %b)", dOut, dReady, dError);
$finish;
end
endmodule