Valid-Ready handshake in Verilog - verilog

I am trying to learn valid/ready handshake in verilog. In particular, I am interested to use ready as a flag that indicates the successful transaction of data (i.e., ready_in becomes high after valid_out goes high). I would like to explain my problem using a very simple Verilog example. I have written a convolutional encoder (code below)
module Conv_Encoder_Core(
input wire clk,
input wire reset,
input wire in_bit,
output reg out_A,
output reg out_B,
input wire sleep,
input wire valid_in,
input wire ready_in,
output reg valid_out,
output reg ready_out);
reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;
always #(posedge clkON)begin
if (reset) begin
S <=0;
valid_out <=0;
ready_out <=0;
end else if (valid_in) begin
out_A <= in_bit ^ S_A;
out_B <= in_bit ^ S_B;
valid_out <=1;
if (ready_in)begin
S<= S<<1;
S[0] <=in_bit;
ready_out <=1;
end else begin
ready_out <=0;
end
end else begin
valid_out <=0;
ready_out <=0;
end
end
endmodule
I am interested to use ready_in flag as an indicator that data out_A and out_B are received by the next block, so my block can accept the new data by setting ready_out flag high. I have written a testbench for this block, however, I am not getting the results I am expecting
`timescale 1 ns/1 ns
module TB_Conv();
reg clk;
//---------------clock generator-----------------------
initial begin
clk = 1'b0;
#5;
clk = 1'b1;
forever begin
#5 clk = ~clk;
end
end
//------------------ dump -----------------------
initial begin
$dumpfile("dumpVCD.vcd");
$dumpvars(10);
end
localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
in_bits_vec[0] = 1'b1;
in_bits_vec[1] = 1'b0;
in_bits_vec[2] = 1'b0;
in_bits_vec[3] = 1'b0;
in_bits_vec[4] = 1'b0;
in_bits_vec[5] = 1'b0;
in_bits_vec[6] = 1'b0;
in_bits_vec[7] = 1'b0;
in_bits_vec[8] = 1'b0;
in_bits_vec[9] = 1'b1;
end
reg in_bit, ready_in,reset, valid_in;
Conv_Encoder_Core UUT(.clk(clk),
.reset(reset),
.in_bit(in_bit),
.out_A(out_A),
.out_B(out_B),
.sleep(1'b0),
.valid_in(valid_in),
.ready_in(ready_in),
.valid_out(valid_out),
.ready_out(ready_out));
//---------------- code starts here -------------------//
reg [3:0] addr;
always #(posedge clk) begin
if (reset)begin
addr<=0;
valid_in <=0;
in_bit <=0;
end else if (addr < 10) begin
in_bit <= in_bits_vec[addr];
valid_in <=1'b1;
if (ready_out) begin
addr <= addr+1'b1;
end
end else begin
in_bit <=0;
valid_in <=0;
end
if (valid_out==1) ready_in <= 1;
else ready_in <= 0;
end
// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always #(negedge clk)begin
if (cnt<5) begin
reset = 1;
cnt=cnt+1;
end else reset =0;
end
initial begin
#1000;
$finish;
end
endmodule
if you look at the input data (in the testbech), you can see it is 1000000000. I am expecting to see 1 being passed through S register as follows:
S = 000000 //at beginning
S = 000001 // after ready_out=1
S = 000010
S = 000100
however, the results I get is entirely different(please see snapshot).
Another problem I have is that inbit=1 continues two clock cycles more than what I expect. in fact when ready_out=1, I expect to see that in_bit becomes zero but this happens two clock cycles later(yellow cursor in the snapshot ).
I would be most grateful if someone could explain what I do wrong in this example.

Conv_Encoder_Core
module Conv_Encoder_Core
(
input wire clk,
input wire reset,
input wire in_bit,
output reg out_A,
output reg out_B,
input wire sleep,
// input channel
input wire inp_valid_i,
output wire inp_ready_o,
// output channel
output reg out_valid_o,
input reg out_ready_i
);
reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;
// -- Changes start here -- //
wire wr_en;
reg full_r;
assign wr_en = ~full_r | out_ready_i;
always #(posedge clkON)begin
if (reset) begin
S <=0;
full_r <=0;
end else begin
if (wr_en) begin
if (inp_valid_i) begin
full_r <= 1;
out_A <= in_bit ^ S_A;
out_B <= in_bit ^ S_B;
S <= S<<1;
S[0] <=in_bit;
end else begin
full_r <= 0;
end
end
end
end
assign inp_ready_o = wr_en;
assign out_valid_o = full_r;
endmodule
tb
`timescale 1 ns/1 ns
module tb();
reg clk;
//---------------clock generator-----------------------
initial begin
clk = 1'b0;
#5;
clk = 1'b1;
forever begin
#5 clk = ~clk;
end
end
//------------------ dump -----------------------
initial begin
$dumpfile("dumpVCD.vcd");
$dumpvars(10);
end
localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
in_bits_vec[0] = 1'b1;
in_bits_vec[1] = 1'b0;
in_bits_vec[2] = 1'b0;
in_bits_vec[3] = 1'b0;
in_bits_vec[4] = 1'b0;
in_bits_vec[5] = 1'b0;
in_bits_vec[6] = 1'b0;
in_bits_vec[7] = 1'b0;
in_bits_vec[8] = 1'b0;
in_bits_vec[9] = 1'b1;
end
reg in_bit, reset, inp_valid, inp_ready, out_valid, out_ready;
Conv_Encoder_Core UUT(.clk(clk),
.reset(reset),
.in_bit(in_bit),
.out_A(out_A),
.out_B(out_B),
.sleep(1'b0),
// input channel
.inp_valid_i(inp_valid),
.inp_ready_o(inp_ready),
// output channel
.out_valid_o(out_valid),
.out_ready_i(out_ready));
//---------------- code starts here -------------------//
reg [3:0] addr;
// -- Transmitter Side -- //
always #(posedge clk) begin: ff_addr
if (reset)begin
addr <= 0;
end else begin
if (addr < 10) begin
if (inp_valid && inp_ready) begin
addr <= addr + 1;
end
end else begin
addr <= 0;
end
end
end
assign inp_valid = (addr < 10) ? 1'b1 : 1'b0;
assign in_bit = in_bits_vec[addr];
// -- Receiver Side -- //
always #(posedge clk) begin: ff_ready_in
if (reset) begin
out_ready <= 0;
end else begin
out_ready <= $urandom_range(0, 1); // some randomness on the receiver, otherwise, we won't see if our DUT behaves correctly in case of ready=0
end
end
// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always #(negedge clk)begin
if (cnt<5) begin
reset = 1;
cnt=cnt+1;
end else reset =0;
end
initial begin
#1000;
$finish;
end
endmodule
Issues with your implementation
Bad protocol definition & implementation
You are defining a protocol that looks more like "request/acknowledge" than "ready/valid" one, because data transmissions in your protocol are acknowledged after a one-cycle delay. What you need is concurrent transmission acknowledge in the same cycle, something like the following:
A valid data transmission is indicated by the Transmitter through valid=1 and are acknowledged by the Receiver through ready=1. So, a data transmission is valid only when valid && ready in the same cycle. Note that input data is equivalent to in_bit in your case, while output data is out_A and out_B.
Input/Output ready/valid channel confusion
If you add a processing/buffering unit between the Transmitter and the Receiver of the above channel, then what you got is something like this:
In that case, your buffer is the Conv_Encoder_Core module and, apart from its internal core logic, it must expose an input ready/valid channel, from which it receives input data, and an output one, from which it outputs its data. Also note that the Transmitter and the Receiver, are implemented by the testbench code (tb module). See
"Transmitter Side" and "Receiver Side" comments in code.

Related

Monostable multivibrator simulation

The monostable module implements a monostable multivibrator. It takes in three inputs (clk, reset, trigger) and outputs a single (pulse).
The trigger input triggers the module. When triggered, the output signal (pulse) will switch to a high position for a period of clock ticks, and then return to a low position. The pulse width of the output signal can be set via the PULSE_WIDTH parameter, which represents the period in clock ticks that the signal should stay high.
Now, what is happening is when it gets triggered, immediately output signal (pulse) is getting high.
When triggered, the output signal (pulse) should be high on the next active edge of clk. What changes can be done ?
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
pulse <= 1'b0;
end else begin
pulse <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
end
endmodule
module monostable_tb();
reg clk;
reg reset;
reg trigger;
wire pulse;
parameter PULSE_WIDTH = 20;
monostable imonostable(.*);
initial begin
clk=0;
forever #50 clk=~clk;
end
initial begin
$monitor("trigger=%b pulse=%b, count = %0d",trigger,pulse,imonostable.count);
$dumpfile("monostable_tb.vcd");
$dumpvars(0,monostable_tb);
trigger=1'b0;
reset = 1'b0;
#(posedge clk) reset = 1'b1;
#(posedge clk) reset = 1'b0;
#(posedge clk) trigger=1'b1;
#(posedge clk) trigger=1'b0;
repeat(25) #(posedge clk);
$finish;
end
endmodule
Here is a simplified design which sets the output one cycle after the input trigger pulse, and keeps the output high for 20 cycles:
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count;
always #(posedge clk, posedge reset) begin
if (reset) begin
pulse <= 1'b0;
end else if (trigger) begin
pulse <= 1'b1;
end else if (count == PULSE_WIDTH-1) begin
pulse <= 1'b0;
end
end
always #(posedge clk, posedge reset) begin
if(reset) begin
count <= 0;
end else if (pulse) begin
count <= count + 1'b1;
end
end
endmodule
It now uses a single clock signal, instead of 2. It also uses a simple reset signal, which can avoid potential glitches causing unwanted asynchronous resets.
You should also use nonblocking assignments in the testbench:
#(posedge clk) reset <= 1'b1;
#(posedge clk) reset <= 1'b0;
#(posedge clk) trigger<= 1'b1;
#(posedge clk) trigger<= 1'b0;
If a 1-clock synchronous delay is needed, then run the output thru a flip flop.
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
reg reg_pulse_temp;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
reg_pulse_temp <= 1'b0;
end else begin
reg_pulse_temp <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
// reset the flop
pulse <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
// flip flop
pulse <= reg_pulse_temp;
end
endmodule

Clock Divider for 50MHz to 1MHz - Verilog

I have written the code for SPI Master and I want the output SPI frequency to be 1MHz.
But, when I run the behaviroal simulation, I don't get a 1MHz spi_sclk. Any suggestions what is wrong with my code? Thanks!
module spi_master(
input wire clk,
input wire reset,
input wire [15:0] datain,
output wire spi_cs_l,
output wire spi_sclk,
output wire spi_data,
output wire [4:0] counter
);
reg [15:0] MOSI;
reg [4:0] count;
reg cs_l;
reg sclk = 1'b0;
reg [2:0] state;
reg [4:0] clk_counter = 0;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1'd1;
end
end
always #(posedge clk or posedge reset) begin
if(reset) begin
MOSI <= 16'b0;
count <= 5'd16;
cs_l <= 1'b1;
end
else begin
case (state)
0:begin
cs_l <= 1'b1;
state <= 1;
end
1:begin
cs_l <= 1'b0;
MOSI <= datain[count-1];
count <= count-1;
state <= 2;
end
2:begin
if(count > 0) begin
state <= 1;
end
else begin
count <= 16;
state <= 0;
end
end
default:state<=0;
endcase
end
end
assign spi_cs_l = cs_l;
assign spi_sclk = sclk;
assign spi_data = MOSI;
assign counter = count;
endmodule
Testbench
module spi_master_tb;
// Inputs
reg clk;
reg reset;
reg [15:0] datain;
// Outputs
wire spi_cs_l;
wire spi_sclk;
wire spi_data;
wire [4:0] counter;
spi_master dut(
.clk(clk),
.reset(reset),
.counter(counter),
.datain(datain),
.spi_cs_l(spi_cs_l),
.spi_sclk(spi_sclk),
.spi_data(spi_data)
);
initial begin
clk = 0;
reset = 1;
datain = 0;
end
always #5 clk=~clk;
initial begin
#10 reset = 1'b0;
#10 datain = 16'hA569;
#335 datain = 16'h2563;
#335 datain = 16'h9B63;
#335 datain = 16'h6A61;
end
endmodule
Waveform
It helps if you create Minimal reproducible example. Also your waveform don't include an important signal clk_counter.
Try this in your testbench, if it doesn't work you at least have the minimum reproducible example.
I changed the initialization of clk_counter and in the increment I simply added 1 instead of 1'b1, if you wanted to be strict you could add a 5-bit wide 1 (5'b1).
module spi_master(
input wire clk,
input wire reset,
output wire spi_sclk,
);
reg [4:0] clk_counter;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if(reset) begin
sclk <= 1'b0;
clk_counter <= 1;
end
else begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1;
end
end
end
assign spi_sclk = sclk;
endmodule

Module instantiation with the "number sign"

I have the main module with FIFO stuff.
Here it is:
module syn_fifo #(
parameter DATA_WIDTH = 8, // inpit capacity
parameter DATA_DEPTH = 8 // the depth of the FIFO
)
(
input wire clk,
input wire rst,
// Write_______________________________________________
input wire [DATA_WIDTH-1:0]din, // the input data
input wire wren, // Write anable
output wire full,
// Read________________________________________________
output wire [DATA_WIDTH-1:0]dout, // The output data
input wire rden, // Read enable
output wire empty
);
integer q_size; // The queue size(length)
integer golova; // The queue beginning
integer hvost; // The end of queue
reg [DATA_WIDTH-1:0]fifo[DATA_DEPTH-1:0];
assign full = (q_size == DATA_DEPTH) ? 1'b1: 1'b0; // FIFO is full
/*
True { full = (q_size==DATA_TEPTH) = 1 }, then wire "full" goes to "1" value
False { full = (q_size==DATA_TEPTH) = 0 }, then wire "full" goes to "0" value
*/
assign empty = (golova == hvost); // FIFO is empty
assign dout = fifo[hvost]; // FWFT (other write mode)
integer i;
//___________(The queue fullness)___________________
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
for (i = 0; i < DATA_DEPTH; i = i + 1) // incrementing the FIFO
fifo[i] <= 0; // Resetting the FIFO
golova <= 0; // Resetting the queue start variable
end
else
begin //Write_______________________________________
if (wren && ~full)
begin
fifo[golova] <= din; // putting data in to the golova
if (golova == DATA_DEPTH-1) // restrictions for the queue beginning
golova <= 0; // Reset the beginning
else
golova <= golova + 1; // other occurence incrementing
end
end
end
//Reading
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
hvost <= 0;
end
else
begin
if (rden && !empty)
/*for staying inside the queue limits - make the check of non equality of the "hvost" & "queue size"*/
begin
if (hvost == DATA_DEPTH-1) // if hvost = DATA_DEPTH-1, then
hvost <= 0; // Reset hvost
else
hvost <= hvost + 1;
end
end
end
always # (posedge clk)
begin
if (rst == 1'b1) begin
q_size <= 0;
end
else
begin
case ({wren && ~full, rden && ~empty} )
2'b01: q_size <= q_size + 1; // RO
2'b10: q_size <= q_size - 1; // WO
default: q_size <= q_size; // read and write at the same time
endcase
end
end
endmodule
Also i've got the testbench module down delow:
`timescale 1ns / 1ps
module fifo_tb();
localparam CLK_PERIOD = 10;
reg clk;
reg rst;
always begin
clk <= 1'b0;
#(CLK_PERIOD / 2);
clk <= 1'b1;
#(CLK_PERIOD / 2);
end
localparam DATA_WIDTH = 8;
localparam DATA_DEPTH = 4;
reg [DATA_WIDTH-1:0]din;
reg wren;
reg rden;
wire [DATA_WIDTH-1:0]dout;
wire empty;
wire full;
wire wr_valid;
wire rd_valid;
task write;
input integer length;
begin
if (length) begin
#(posedge clk);
wren <= 1'b1;
while (length) begin
#(posedge clk);
if (wr_valid) begin
length <= length - 1;
if (length == 1) begin
wren <= 1'b0;
end
end
end
end
end
endtask
task read;
input integer length;
begin
if (length) begin
#(posedge clk);
rden <= 1'b1;
while (length) begin
#(posedge clk);
if (rd_valid) begin
length <= length - 1;
if (length == 1) begin
rden <= 1'b0;
end
end
end
end
end
endtask
initial begin
rst <= 1'b0;
wren <= 1'b0;
rden <= 1'b0;
#50;
rst <= 1'b1;
#50;
rst <= 1'b0;
#200;
/* Test Start */
//write(4);
//read(4);
/* Test Stop */
#1000;
$finish;
end
assign wr_valid = wren & ~full;
assign rd_valid = rden & ~empty;
always #(posedge clk) begin
if (rst == 1'b1) begin
din <= 0;
end else begin
if (wr_valid == 1'b1) begin
din <= din + 1;
end
end
end
// write?
always begin
#400;
write(5);
#15;
write(7);
#25;
write(3);
#15;
write(9);
#15;
write(1);
#10000;
end
// read?
always begin
#420;
read(3);
#37;
read(13);
#21;
read(7);
#15;
read(9);
#15;
read(4);
#20;
read(7);
#10000;
end
initial begin
$dumpfile("test.vcd");
$dumpvars(0,fifo_tb);
end
syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
.rst(rst),
.din(din),
.wren(wren),
.full(full),
.dout(dout),
.rden(rden),
.empty(empty));
endmodule
Trying to compile all of it with iVerilog + GTKwave + Win10 by next command:
C:\Program Files\iverilog\bin>iverilog -o fifo.v fifo_tb.v
The compiler gives me the next message:
fifo_tb.v:138:error: Unknown module type:syn_fifo
2 error(s) during elaboration.
These modules were missing:syn_fifo referenced 1 times
At the necessary line "138" maybe the main mistake is covered by the "Number sign" in module instantiation?
/*132|*/ initial begin
/*133|*/ $dumpfile("test.vcd");
/*134|*/ $dumpvars(0,fifo_tb);
/*135|*/ end
/*136|*/
/*137|*/ syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
/*138|*/ .DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
/*139|*/ .rst(rst),
/*140|*/ .din(din),
/*141|*/ .wren(wren),
/*142|*/ .full(full),
/*143|*/ .dout(dout),
/*144|*/ .rden(rden),
/*145|*/ .empty(empty));
/*146|*/
/*147|*/ endmodule
I'm not shure of that.
Seems like you are indicating fifo.v to be your output file, try:
iverilog -o syn_fifo.tb -s fifo_tb fifo_tb.v fifo.v
-o -> output file
-s -> top module (in this case, the test one)
(after everything, include all the files)
Then, to run it:
vvp syn_fifo.tb
Thank you, dear #m4j0rt0m
I just forgot to type in the output file name at the CMD window. Was very exhausted so haven't noticed such a detail)))
Usually it looks like:
iverilog -o OUTPUT_FILE_NAME fifo_tb.v fifo.v
And also I tried your advice, and it's finally done!

How to Model a delay in Verilog without # ? That can be synthesized

I am looking to create an AND gate which gets the result after a delay of lets say 10ns an my clock is 500 ps. How will i delay the assignment without using # delays ?
I have tried to make a counter which increments but how to model it so that it only starts when my input changes. Also the input won't change till the first output is evaluated and assigned. Initial Counter is 0 and lets say delay is 3'b111 so i want the counter to go from 1 to 3'b111 and then assign it to y. Inputs are a and b to the and gate.
always#(posedge clk)begin
if (!reset) begin y <=0; counter <=0; end
else begin
counter <= counter +1'b1;
if(counter==delay)begin
y <= a & b;
counter <=0;
end
end
Well if your clock cycle is 500 ps then you will need to count to a higher value to reach 10ns. I rewrote your code and also added a testbench for you to try. It's kind of sloppy, I usually write vhdl and not verilog. Hope this helps.
//Module
module count_and (
input clk,
input reset,
input a,
input b,
output reg y,
output reg [4:0] counter
);
reg ready;
always#(posedge clk)begin
if (!reset) begin
y <=0;
counter <=0;
ready <= 0;
end
else if (ready == 1'b1) begin
counter <= counter +1'b1;
if (counter==5'b10011) begin
y <= a & b;
counter <=0;
ready <= 0; //turn it off after passing to y
end
end
end
always #(a,b) begin
ready <= 1'b1;
end
endmodule
//TestBench
`timescale 1ps/1ps
module tb_count ();
reg a,b;
reg clk;
reg reset;
wire [4:0] counter;
wire y;
initial begin
clk = 1'b1;
reset = 1'b0;
a = 1'b0;
b = 1'b0;
end
always begin
reset <= #50 1'b1;
clk = #250 ~clk;
a <= #1000 1'b1;
b <= #1000 1'b1;
end
count_and count_and_inst (
.clk(clk),
.reset(reset),
.a(a),
.b(b),
.y(y),
.counter(counter)
);
endmodule

Event counter in verilog

i'm a verilog beginner, i'm try to write a "event counter" on verilog.... this is my code, but it work only with "period" set to 16'b0000000000000001, if try set period to 16'b0000000000001000, result(out_event) is always '0'.
Someone can help me to fix it ?
module mymodule(
input wire clk,
input wire enable,
input wire reset,
input wire [15:0] period,
input wire in_event,
output reg out_event
);
reg en = 1'b0;
reg re = 1'b0;
reg [15:0] count = 16'b0000000000000000;
always #(posedge clk) en <= enable;
always #(posedge clk) re <= reset;
always #(in_event)begin
if(in_event == 1'b1)begin
if(re)begin
count <= 0 ;
out_event <= 1'b0;
end else begin
if(en) begin
if(count == period-1)begin
out_event <= 1'b1;
count <= 0;
end else begin
count <=count + 1;
out_event <= 1'b0;
end
end else begin
out_event <= 1'b0;
end
end
end else begin
out_event <= 1'b0;
end
end
endmodule
thanks in advance
The counter counts number of posedge of in_event wire. So, can you use #(posedge in_event)?
I simulated your code, providing a testbench to it.
I do not have much knowledge about hardware synthesis, but personally, I would suggest to write your logic based on edge/level of clock.
This code works completely well. Have a look at this link.
You can configure various values of period in testbench, hope this will be helpful.
I came up with a test bench and the design for your problem and it works.
`timescale 1s / 1s
module TB();
reg clk;
reg enable;
reg reset;
reg [15:0] period;
wire out_event;
wire [15:0] counter;
initial begin
clk = 1'b0;
forever begin
#1 clk = ~clk;
end
end
stack_exch_code test (.clk(clk),
.enable(enable),
.reset(reset),
.period(period),
.out_event(out_event),
.tb_counter(counter)
);
integer i;
initial
begin
#(negedge clk) reset = 1'b1; enable = 1'b0; period = 16'h0000;
#(negedge clk) reset = 1'b0; enable = 1'b1; period = 16'h00FF;
for (i = 0 ; i < 500 ; i = i + 1) begin
#(negedge clk) period = period - 1;
#(posedge clk) $display ("Period = %h , Counter = %h, Out_Event = %b ", period, counter, out_event);
end
#(negedge clk) $finish;
end
endmodule //TB
module stack_exch_code (input clk,
input enable,
input reset,
input [15:0] period,
//input inevent,
output reg out_event,
output [15:0] tb_counter
);
// initialization doesnt matter in hardware, its not C or C++
reg en;
reg re;
reg [15:0] count;
always # (posedge clk) begin
re <= reset;
en <= enable;
end
always # (posedge clk) begin
if (re) begin
count <= 16'h0000;
out_event <= 1'b0;
end
else if (en) begin
if ((count == period - 1) && !(period == 16'h0000)) begin
out_event <= 1'b1;
count <= 16'h0000;
end
else if (!(period == 16'h0000)) begin
count <= count + 1;
out_event <= 1'b0;
end
else if (period == 16'h0000)
out_event <= 1'b0;
end
end
assign tb_counter = count;
endmodule //stack_exch_code

Resources