mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-09-08 12:23:32 +02:00
By adding ivtest to the iverilog source tree, it is easier to keep the regression test synchronized with the source that is being tested. This should be especially helpful for PRs that add a new feature, and have a matching ivtest PR with the regression test for that feature.
376 lines
7.5 KiB
Verilog
376 lines
7.5 KiB
Verilog
`begin_keywords "1364-2005"
|
|
//
|
|
// Copyright (c) 1999 Thomas Coonan ([email protected])
|
|
//
|
|
// This source code is free software; you can redistribute it
|
|
// and/or modify it in source code form under the terms of the GNU
|
|
// General Public License as published by the Free Software
|
|
// Foundation; either version 2 of the License, or (at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
//
|
|
// Synchronous FIFO. 4 x 16 bit words.
|
|
//
|
|
// Modified by SDW to print out PASSED only if DEBUG not defined.
|
|
// Also changed TEST1 so that it is "self checking" by adding a
|
|
// passed in value to read_word.
|
|
//
|
|
module fifo (clk, rstp, din, writep, readp, dout, emptyp, fullp);
|
|
input clk;
|
|
input rstp;
|
|
input [15:0] din;
|
|
input readp;
|
|
input writep;
|
|
output [15:0] dout;
|
|
output emptyp;
|
|
output fullp;
|
|
|
|
// Defines sizes in terms of bits.
|
|
//
|
|
parameter DEPTH = 3, // 2 bits, e.g. 4 words in the FIFO.
|
|
MAX_COUNT = 3'b111; // topmost address in FIFO.
|
|
|
|
reg emptyp;
|
|
reg fullp;
|
|
|
|
// Registered output.
|
|
reg [15:0] dout;
|
|
|
|
// Define the FIFO pointers. A FIFO is essentially a circular queue.
|
|
//
|
|
reg [(DEPTH-1):0] tail;
|
|
reg [(DEPTH-1):0] head;
|
|
|
|
// Define the FIFO counter. Counts the number of entries in the FIFO which
|
|
// is how we figure out things like Empty and Full.
|
|
//
|
|
reg [(DEPTH-1):0] count;
|
|
|
|
// Define our regsiter bank. This is actually synthesizable!
|
|
//
|
|
reg [15:0] fifomem[0:MAX_COUNT];
|
|
|
|
// Dout is registered and gets the value that tail points to RIGHT NOW.
|
|
//
|
|
always @(posedge clk)
|
|
begin
|
|
if (rstp == 1)
|
|
dout <= 16'h0000;
|
|
else
|
|
dout <= fifomem[tail];
|
|
end
|
|
|
|
|
|
// Update FIFO memory.
|
|
always @(posedge clk) begin
|
|
if (rstp == 1'b0 && writep == 1'b1 && fullp == 1'b0) begin
|
|
fifomem[head] <= din;
|
|
end
|
|
end
|
|
|
|
// Update the head register.
|
|
//
|
|
always @(posedge clk) begin
|
|
if (rstp == 1'b1) begin
|
|
head <= 2'b00;
|
|
end
|
|
else begin
|
|
if (writep == 1'b1 && fullp == 1'b0) begin
|
|
// WRITE
|
|
head <= head + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// Update the tail register.
|
|
//
|
|
always @(posedge clk) begin
|
|
if (rstp == 1'b1) begin
|
|
tail <= 2'b00;
|
|
end
|
|
else begin
|
|
if (readp == 1'b1 && emptyp == 1'b0) begin
|
|
// READ
|
|
tail <= tail + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// Update the count regsiter.
|
|
//
|
|
always @(posedge clk) begin
|
|
if (rstp == 1'b1) begin
|
|
count <= 2'b00;
|
|
end
|
|
else begin
|
|
case ({readp, writep})
|
|
2'b00: count <= count;
|
|
2'b01:
|
|
// WRITE
|
|
if (count != MAX_COUNT)
|
|
count <= count + 1;
|
|
2'b10:
|
|
// READ
|
|
if (count != 2'b00)
|
|
count <= count - 1;
|
|
2'b11:
|
|
// Concurrent read and write.. no change in count
|
|
count <= count;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
|
|
// *** Update the flags
|
|
//
|
|
// First, update the empty flag.
|
|
//
|
|
always @(count) begin
|
|
if (count == 2'b00)
|
|
emptyp <= 1'b1;
|
|
else
|
|
emptyp <= 1'b0;
|
|
end
|
|
|
|
|
|
// Update the full flag
|
|
//
|
|
always @(count) begin
|
|
if (count == MAX_COUNT)
|
|
fullp <= 1'b1;
|
|
else
|
|
fullp <= 1'b0;
|
|
end
|
|
|
|
endmodule
|
|
|
|
// synopsys translate_off
|
|
|
|
`define TEST_FIFO
|
|
// synopsys translate_off
|
|
`ifdef TEST_FIFO
|
|
|
|
|
|
module test_fifo;
|
|
|
|
reg clk;
|
|
reg rstp;
|
|
reg [15:0] din;
|
|
reg readp;
|
|
reg writep;
|
|
wire [15:0] dout;
|
|
wire emptyp;
|
|
wire fullp;
|
|
reg error ;
|
|
|
|
reg [15:0] value;
|
|
|
|
fifo U1 (
|
|
.clk (clk),
|
|
.rstp (rstp),
|
|
.din (din),
|
|
.readp (readp),
|
|
.writep (writep),
|
|
.dout (dout),
|
|
.emptyp (emptyp),
|
|
.fullp (fullp)
|
|
);
|
|
|
|
//
|
|
// SDW Added self testing aspect here..
|
|
//
|
|
task read_word;
|
|
input [15:0] expect;
|
|
begin
|
|
@(negedge clk);
|
|
readp = 1;
|
|
@(posedge clk) #5;
|
|
`ifdef DEBUG
|
|
$display ("Expect %0h, Read %0h from FIFO",
|
|
`endif // DEBUG
|
|
if(expect !== dout)
|
|
begin
|
|
$display ("FAILED - Expect %0h, Read %0h from FIFO",
|
|
expect,dout);
|
|
error = 1;
|
|
end
|
|
readp = 0;
|
|
end
|
|
endtask
|
|
|
|
task write_word;
|
|
input [15:0] value;
|
|
begin
|
|
@(negedge clk);
|
|
din = value;
|
|
writep = 1;
|
|
@(posedge clk);
|
|
`ifdef DEBUG
|
|
$display ("Write %0h to FIFO", din);
|
|
`endif // DEBUG
|
|
#5;
|
|
din = 16'hzzzz;
|
|
writep = 0;
|
|
end
|
|
endtask
|
|
|
|
initial begin
|
|
clk = 0;
|
|
forever begin
|
|
#10 clk = 1;
|
|
#10 clk = 0;
|
|
end
|
|
end
|
|
|
|
initial begin
|
|
error = 0; // Set error to zero here.
|
|
`ifdef DEBUG
|
|
$dumpfile("test.vcd");
|
|
$dumpvars(0,test_fifo);
|
|
`endif // DEBUG
|
|
test1;
|
|
//test2;
|
|
|
|
if(error == 0)
|
|
$display("PASSED");
|
|
$finish;
|
|
end
|
|
|
|
task test1;
|
|
begin
|
|
din = 16'hzzzz;
|
|
writep = 0;
|
|
readp = 0;
|
|
|
|
// Reset
|
|
rstp = 1;
|
|
#50;
|
|
rstp = 0;
|
|
#50;
|
|
|
|
// ** Write 3 values.
|
|
write_word (16'h1111);
|
|
write_word (16'h2222);
|
|
write_word (16'h3333);
|
|
|
|
// ** Read 2 values
|
|
read_word(16'h1111);
|
|
read_word(16'h2222);
|
|
|
|
// ** Write one more
|
|
write_word (16'h4444);
|
|
|
|
// ** Read a bunch of values
|
|
read_word(16'h3333);
|
|
|
|
// *** Write a bunch more values
|
|
write_word (16'h0001);
|
|
write_word (16'h0002);
|
|
write_word (16'h0003);
|
|
write_word (16'h0004);
|
|
write_word (16'h0005);
|
|
write_word (16'h0006);
|
|
write_word (16'h0007);
|
|
write_word (16'h0008);
|
|
|
|
// ** Read a bunch of values
|
|
read_word(16'h4444);
|
|
read_word(16'h0001);
|
|
read_word(16'h0002);
|
|
read_word(16'h0003);
|
|
read_word(16'h0004);
|
|
read_word(16'h0005);
|
|
read_word(16'h0006);
|
|
end
|
|
endtask
|
|
`ifdef TEST2
|
|
// TEST2
|
|
//
|
|
// This test will operate the FIFO in an orderly manner the way it normally works.
|
|
// 2 threads are forked; a reader and a writer. The writer writes a counter to
|
|
// the FIFO and obeys the fullp flag and delays randomly. The reader likewise
|
|
// obeys the emptyp flag and reads at random intervals. The result should be that
|
|
// the reader reads the incrementing counter out of the FIFO. The empty/full flags
|
|
// should bounce around depending on the random delays. The writer repeats some
|
|
// fixed number of times and then terminates both threads and kills the sim.
|
|
//
|
|
task test2;
|
|
reg [15:0] writer_counter;
|
|
begin
|
|
writer_counter = 16'h0001;
|
|
din = 16'hzzzz;
|
|
writep = 0;
|
|
readp = 0;
|
|
|
|
// Reset
|
|
rstp = 1;
|
|
#50;
|
|
rstp = 0;
|
|
#50;
|
|
|
|
fork
|
|
// Writer
|
|
begin
|
|
repeat (500) begin
|
|
@(negedge clk);
|
|
if (fullp == 1'b0) begin
|
|
write_word (writer_counter);
|
|
#5;
|
|
writer_counter = writer_counter + 1;
|
|
end
|
|
else begin
|
|
$display ("WRITER is waiting..");
|
|
end
|
|
// Delay a random amount of time between 0ns and 100ns
|
|
#22 ;
|
|
end
|
|
$display ("Done with WRITER fork..");
|
|
$finish;
|
|
end
|
|
|
|
// Reader
|
|
begin
|
|
forever begin
|
|
@(negedge clk);
|
|
if (emptyp == 1'b0) begin
|
|
read_word;
|
|
end
|
|
else begin
|
|
$display ("READER is waiting..");
|
|
end
|
|
// Delay a random amount of time between 0ns and 100ns
|
|
#50;
|
|
end
|
|
end
|
|
join
|
|
end
|
|
endtask
|
|
|
|
/*
|
|
always @(fullp)
|
|
$display ("fullp = %0b", fullp);
|
|
|
|
always @(emptyp)
|
|
$display ("emptyp = %0b", emptyp);
|
|
|
|
always @(U1.head)
|
|
$display ("head = %0h", U1.head);
|
|
|
|
always @(U1.tail)
|
|
$display ("tail = %0h", U1.tail);
|
|
*/
|
|
|
|
`endif // TEST2
|
|
|
|
endmodule
|
|
`endif
|
|
`end_keywords
|