// Synchronous FIFO. 4 x 16 bit words. // 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 = 2, // 2 bits, e.g. 4 words in the FIFO. MAX_COUNT = 2'b11; // 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) begin dout <= 16'h0000; end else begin dout <= fifomem[tail]; end 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 [15:0] value; fifo U1 ( .clk (clk), .rstp (rstp), .din (din), .readp (readp), .writep (writep), .dout (dout), .emptyp (emptyp), .fullp (fullp) ); task read_word; begin @(negedge clk); readp = 1; @(posedge clk) #5; $display ("Read %0h from FIFO", dout); readp = 0; end endtask task write_word; input [15:0] value; begin @(negedge clk); din = value; writep = 1; @(posedge clk); $display ("Write %0h to FIFO", din); #5; din = 16'hzzzz; writep = 0; end endtask initial begin clk = 0; forever begin #10 clk = 1; #10 clk = 0; end end initial begin $shm_open ("./fifo.shm"); $shm_probe (test_fifo, "AS"); //test1; test2; $shm_close; $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; read_word; // ** Write one more write_word (16'h4444); // ** Read a bunch of values repeat (6) begin read_word; end // *** 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 repeat (6) begin read_word; end $display ("Done TEST1."); end endtask // 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 #(50 + ($random % 50)); 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 + ($random % 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); endmodule `endif [ [ [ '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', ';'], ['parameter', ['DEPTH', '=', '2'], ['MAX_COUNT', '=', "2 'b 11"], ';'], ['reg', ['emptyp'], ';'], ['reg', ['fullp'], ';'], ['reg', '[', '15', ':', '0', ']', ['dout'], ';'], [ 'reg', '[', '(', [['DEPTH'], '-', '1'], ')', ':', '0', ']', ['tail'], ';'], [ 'reg', '[', '(', [['DEPTH'], '-', '1'], ')', ':', '0', ']', ['head'], ';'], [ 'reg', '[', '(', [['DEPTH'], '-', '1'], ')', ':', '0', ']', ['count'], ';'], [ 'reg', '[', '15', ':', '0', ']', ['fifomem', '[', '0', ':', ['MAX_COUNT'], ']'], ';'], [ 'always', ['@', '(', ['posedge', ['clk']], ')'], [ 'begin', [ [ 'if', ['(', ['rstp'], '==', '1', ')'], ['begin', [[[['dout'], '<=', "16 'h 0000"], ';']], 'end'], 'else', [ 'begin', [[[['dout'], '<=', ['fifomem', ['[', ['tail'], ']']]], ';']], 'end']]], 'end']], [ 'always', ['@', '(', ['posedge', ['clk']], ')'], [ 'begin', [ [ 'if', [ '(', ['rstp'], '==', "1 'b 0", '&&', ['writep'], '==', "1 'b 1", '&&', ['fullp'], '==', "1 'b 0", ')'], [ 'begin', [[[['fifomem', ['[', ['head'], ']']], '<=', ['din']], ';']], 'end']]], 'end']], [ 'always', ['@', '(', ['posedge', ['clk']], ')'], [ 'begin', [ [ 'if', ['(', ['rstp'], '==', "1 'b 1", ')'], ['begin', [[[['head'], '<=', "2 'b 00"], ';']], 'end'], 'else', [ 'begin', [ [ 'if', [ '(', ['writep'], '==', "1 'b 1", '&&', ['fullp'], '==', "1 'b 0", ')'], [ 'begin', [[[['head'], '<=', ['head'], '+', '1'], ';']], 'end']]], 'end']]], 'end']], [ 'always', ['@', '(', ['posedge', ['clk']], ')'], [ 'begin', [ [ 'if', ['(', ['rstp'], '==', "1 'b 1", ')'], ['begin', [[[['tail'], '<=', "2 'b 00"], ';']], 'end'], 'else', [ 'begin', [ [ 'if', [ '(', ['readp'], '==', "1 'b 1", '&&', ['emptyp'], '==', "1 'b 0", ')'], [ 'begin', [[[['tail'], '<=', ['tail'], '+', '1'], ';']], 'end']]], 'end']]], 'end']], [ 'always', ['@', '(', ['posedge', ['clk']], ')'], [ 'begin', [ [ 'if', ['(', ['rstp'], '==', "1 'b 1", ')'], ['begin', [[[['count'], '<=', "2 'b 00"], ';']], 'end'], 'else', [ 'begin', [ [ 'case', '(', ['{', ['readp'], ['writep'], '}'], ')', "2 'b 00", ':', [[['count'], '<=', ['count']], ';'], "2 'b 01", ':', [ 'if', ['(', ['count'], '!=', ['MAX_COUNT'], ')'], [[['count'], '<=', ['count'], '+', '1'], ';']], "2 'b 10", ':', [ 'if', ['(', ['count'], '!=', "2 'b 00", ')'], [[['count'], '<=', ['count'], '-', '1'], ';']], "2 'b 11", ':', [[['count'], '<=', ['count']], ';'], 'endcase']], 'end']]], 'end']], [ 'always', ['@', '(', [['count']], ')'], [ 'begin', [ [ 'if', ['(', ['count'], '==', "2 'b 00", ')'], [[['emptyp'], '<=', "1 'b 1"], ';'], 'else', [[['emptyp'], '<=', "1 'b 0"], ';']]], 'end']], [ 'always', ['@', '(', [['count']], ')'], [ 'begin', [ [ 'if', ['(', ['count'], '==', ['MAX_COUNT'], ')'], [[['fullp'], '<=', "1 'b 1"], ';'], 'else', [[['fullp'], '<=', "1 'b 0"], ';']]], 'end']]], 'endmodule'], [ ['module', 'test_fifo', ';'], [ ['reg', ['clk'], ';'], ['reg', ['rstp'], ';'], ['reg', '[', '15', ':', '0', ']', ['din'], ';'], ['reg', ['readp'], ';'], ['reg', ['writep'], ';'], ['wire', '[', '15', ':', '0', ']', ['dout'], ';'], ['wire', ['emptyp'], ';'], ['wire', ['fullp'], ';'], ['reg', '[', '15', ':', '0', ']', ['value'], ';'], [ 'fifo', [ ['U1'], [ '(', ['.', 'clk', '(', ['clk'], ')'], ['.', 'rstp', '(', ['rstp'], ')'], ['.', 'din', '(', ['din'], ')'], ['.', 'readp', '(', ['readp'], ')'], ['.', 'writep', '(', ['writep'], ')'], ['.', 'dout', '(', ['dout'], ')'], ['.', 'emptyp', '(', ['emptyp'], ')'], ['.', 'fullp', '(', ['fullp'], ')'], ')']], ';'], [ 'task', 'read_word', ';', [ 'begin', [ [['@', '(', ['negedge', ['clk']], ')'], ';'], [[['readp'], '=', '1'], ';'], [['@', '(', ['posedge', ['clk']], ')'], [['#', '5'], ';']], ['$display', '(', '"Read %0h from FIFO"', ['dout'], ')', ';'], [[['readp'], '=', '0'], ';']], 'end'], 'endtask'], [ 'task', 'write_word', ';', ['input', '[', '15', ':', '0', ']', 'value', ';'], [ 'begin', [ [['@', '(', ['negedge', ['clk']], ')'], ';'], [[['din'], '=', ['value']], ';'], [[['writep'], '=', '1'], ';'], [['@', '(', ['posedge', ['clk']], ')'], ';'], ['$display', '(', '"Write %0h to FIFO"', ['din'], ')', ';'], [['#', '5'], ';'], [[['din'], '=', "16 'h zzzz"], ';'], [[['writep'], '=', '0'], ';']], 'end'], 'endtask'], [ 'initial', [ 'begin', [ [[['clk'], '=', '0'], ';'], [ 'forever', [ 'begin', [ [['#', '10'], [[['clk'], '=', '1'], ';']], [['#', '10'], [[['clk'], '=', '0'], ';']]], 'end']]], 'end']], [ 'initial', [ 'begin', [ ['$shm_open', '(', '"./fifo.shm"', ')', ';'], ['$shm_probe', '(', ['test_fifo'], '"AS"', ')', ';'], ['test2', ';'], ['$shm_close', ';'], ['$finish', ';']], 'end']], [ 'task', 'test1', ';', [ 'begin', [ [[['din'], '=', "16 'h zzzz"], ';'], [[['writep'], '=', '0'], ';'], [[['readp'], '=', '0'], ';'], [[['rstp'], '=', '1'], ';'], [['#', '50'], ';'], [[['rstp'], '=', '0'], ';'], [['#', '50'], ';'], ['write_word', '(', "16 'h 1111", ')', ';'], ['write_word', '(', "16 'h 2222", ')', ';'], ['write_word', '(', "16 'h 3333", ')', ';'], ['read_word', ';'], ['read_word', ';'], ['write_word', '(', "16 'h 4444", ')', ';'], ['repeat', '(', '6', ')', ['begin', [['read_word', ';']], 'end']], ['write_word', '(', "16 'h 0001", ')', ';'], ['write_word', '(', "16 'h 0002", ')', ';'], ['write_word', '(', "16 'h 0003", ')', ';'], ['write_word', '(', "16 'h 0004", ')', ';'], ['write_word', '(', "16 'h 0005", ')', ';'], ['write_word', '(', "16 'h 0006", ')', ';'], ['write_word', '(', "16 'h 0007", ')', ';'], ['write_word', '(', "16 'h 0008", ')', ';'], ['repeat', '(', '6', ')', ['begin', [['read_word', ';']], 'end']], ['$display', '(', '"Done TEST1."', ')', ';']], 'end'], 'endtask'], [ 'task', 'test2', ';', ['reg', '[', '15', ':', '0', ']', ['writer_counter'], ';'], [ 'begin', [ [[['writer_counter'], '=', "16 'h 0001"], ';'], [[['din'], '=', "16 'h zzzz"], ';'], [[['writep'], '=', '0'], ';'], [[['readp'], '=', '0'], ';'], [[['rstp'], '=', '1'], ';'], [['#', '50'], ';'], [[['rstp'], '=', '0'], ';'], [['#', '50'], ';'], [ 'fork', [ 'begin', [ [ 'repeat', '(', '500', ')', [ 'begin', [ [['@', '(', ['negedge', ['clk']], ')'], ';'], [ 'if', ['(', ['fullp'], '==', "1 'b 0", ')'], [ 'begin', [ ['write_word', '(', ['writer_counter'], ')', ';'], [['#', '5'], ';'], [ [ ['writer_counter'], '=', ['writer_counter'], '+', '1'], ';']], 'end'], 'else', [ 'begin', [ [ '$display', '(', '"WRITER is waiting.."', ')', ';']], 'end']], [ [ '#', '(', ['50', '+', '(', [['$random'], '%', '50'], ')'], ')'], ';']], 'end']], ['$display', '(', '"Done with WRITER fork.."', ')', ';'], ['$finish', ';']], 'end'], [ 'begin', [ [ 'forever', [ 'begin', [ [['@', '(', ['negedge', ['clk']], ')'], ';'], [ 'if', ['(', ['emptyp'], '==', "1 'b 0", ')'], ['begin', [['read_word', ';']], 'end'], 'else', [ 'begin', [ [ '$display', '(', '"READER is waiting.."', ')', ';']], 'end']], [ [ '#', '(', ['50', '+', '(', [['$random'], '%', '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'], ')', ';']]], 'endmodule']]