|
|
|
|
|
|
|
|
|
|
|
|
Verification Of FIFO
|
|
|
Our first example is the verification of a synchronous FIFO. Here we will build a simple testbench around the FIFO model and use simple assertions to show how they can be used to check simple protocols. If you have any better suggestion, please let me know. |
|
|
|
|
|
|
|
|
|
|
|
FIFO Model
|
|
|
Below is the original code found in examples directory. |
|
|
1 //-----------------------------------------------------
2 // Design Name : syn_fifo
3 // File Name : syn_fifo.v
4 // Function : Synchronous (single clock) FIFO
5 // Coder : Deepak Kumar Tala
6 //-----------------------------------------------------
7 module syn_fifo (
8 clk , // Clock input
9 rst , // Active high reset
10 wr_cs , // Write chip select
11 rd_cs , // Read chipe select
12 data_in , // Data input
13 rd_en , // Read enable
14 wr_en , // Write Enable
15 data_out , // Data Output
16 empty , // FIFO empty
17 full // FIFO full
18 );
19
20 // FIFO constants
21 parameter DATA_WIDTH = 8;
22 parameter ADDR_WIDTH = 8;
23 parameter RAM_DEPTH = (1 << ADDR_WIDTH);
24 // Port Declarations
25 input clk ;
26 input rst ;
27 input wr_cs ;
28 input rd_cs ;
29 input rd_en ;
30 input wr_en ;
31 input [DATA_WIDTH-1:0] data_in ;
32 output full ;
33 output empty ;
34 output [DATA_WIDTH-1:0] data_out ;
35
36 //-----------Internal variables-------------------
37 reg [ADDR_WIDTH-1:0] wr_pointer;
38 reg [ADDR_WIDTH-1:0] rd_pointer;
39 reg [ADDR_WIDTH :0] status_cnt;
40 reg [DATA_WIDTH-1:0] data_out ;
41 wire [DATA_WIDTH-1:0] data_ram ;
42
43 //-----------Variable assignments---------------
44 assign full = (status_cnt == (RAM_DEPTH-1));
45 assign empty = (status_cnt == 0);
46
47 //-----------Code Start---------------------------
48 always @ (posedge clk or posedge rst)
49 begin : WRITE_POINTER
50 if (rst) begin
51 wr_pointer <= 0;
52 end else if (wr_cs && wr_en ) begin
53 wr_pointer <= wr_pointer + 1;
54 end
55 end
56
57 always @ (posedge clk or posedge rst)
58 begin : READ_POINTER
59 if (rst) begin
60 rd_pointer <= 0;
61 end else if (rd_cs && rd_en ) begin
62 rd_pointer <= rd_pointer + 1;
63 end
64 end
65
66 always @ (posedge clk or posedge rst)
67 begin : READ_DATA
68 if (rst) begin
69 data_out <= 0;
70 end else if (rd_cs && rd_en ) begin
71 data_out <= data_ram;
72 end
73 end
74
75 always @ (posedge clk or posedge rst)
76 begin : STATUS_COUNTER
77 if (rst) begin
78 status_cnt <= 0;
79 // Read but no write.
80 end else if ((rd_cs && rd_en) && ! (wr_cs && wr_en)
81 && (status_cnt ! = 0)) begin
82 status_cnt <= status_cnt - 1;
83 // Write but no read.
84 end else if ((wr_cs && wr_en) && ! (rd_cs && rd_en)
85 && (status_cnt ! = RAM_DEPTH)) begin
86 status_cnt <= status_cnt + 1;
87 end
88 end
89
90 ram_dp_ar_aw #(DATA_WIDTH,ADDR_WIDTH)DP_RAM (
91 .address_0 (wr_pointer) , // address_0 input
92 .data_0 (data_in) , // data_0 bi-directional
93 .cs_0 (wr_cs) , // chip select
94 .we_0 (wr_en) , // write enable
95 .oe_0 (1'b0) , // output enable
96 .address_1 (rd_pointer) , // address_q input
97 .data_1 (data_ram) , // data_1 bi-directional
98 .cs_1 (rd_cs) , // chip select
99 .we_1 (1'b0) , // Read enable
100 .oe_1 (rd_en) // output enable
101 );
102
103 endmodule
You could download file here
|
|
|
|
|
|
Ram Model
|
|
|
|
|
|
1 //-----------------------------------------------------
2 // Design Name : ram_dp_ar_aw
3 // File Name : ram_dp_ar_aw.v
4 // Function : Asynchronous read write RAM
5 // Coder : Deepak Kumar Tala
6 //-----------------------------------------------------
7 module ram_dp_ar_aw (
8 address_0 , // address_0 Input
9 data_0 , // data_0 bi-directional
10 cs_0 , // Chip Select
11 we_0 , // Write Enable/Read Enable
12 oe_0 , // Output Enable
13 address_1 , // address_1 Input
14 data_1 , // data_1 bi-directional
15 cs_1 , // Chip Select
16 we_1 , // Write Enable/Read Enable
17 oe_1 // Output Enable
18 );
19
20 parameter DATA_WIDTH = 8 ;
21 parameter ADDR_WIDTH = 8 ;
22 parameter RAM_DEPTH = 1 << ADDR_WIDTH;
23
24 //--------------Input Ports-----------------------
25 input [ADDR_WIDTH-1:0] address_0 ;
26 input cs_0 ;
27 input we_0 ;
28 input oe_0 ;
29 input [ADDR_WIDTH-1:0] address_1 ;
30 input cs_1 ;
31 input we_1 ;
32 input oe_1 ;
33
34 //--------------Inout Ports-----------------------
35 inout [DATA_WIDTH-1:0] data_0 ;
36 inout [DATA_WIDTH-1:0] data_1 ;
37
38 //--------------Internal variables----------------
39 reg [DATA_WIDTH-1:0] data_0_out ;
40 reg [DATA_WIDTH-1:0] data_1_out ;
41 reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
42
43 //--------------Code Starts Here------------------
44 // Memory Write Block
45 // Write Operation : When we_0 = 1, cs_0 = 1
46 always @ (address_0 or cs_0 or we_0 or data_0
47 or address_1 or cs_1 or we_1 or data_1)
48 begin : MEM_WRITE
49 if ( cs_0 && we_0 ) begin
50 mem[address_0] <= data_0;
51 end else if (cs_1 && we_1) begin
52 mem[address_1] <= data_1;
53 end
54 end
55
56 // Tri-State Buffer control
57 // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
58 assign data_0 = (cs_0 && oe_0 && ! we_0) ? data_0_out : 8'bz;
59
60 // Memory Read Block
61 // Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
62 always @ (address_0 or cs_0 or we_1 or oe_0)
63 begin : MEM_READ_0
64 if (cs_0 && ! we_0 && oe_0) begin
65 data_0_out <= mem[address_0];
66 end else begin
67 data_0_out <= 0;
68 end
69 end
70
71 //Second Port of RAM
72 // Tri-State Buffer control
73 // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
74 assign data_1 = (cs_1 && oe_1 && ! we_1) ? data_1_out : 8'bz;
75 // Memory Read Block 1
76 // Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
77 always @ (address_1 or cs_1 or we_1 or oe_1)
78 begin : MEM_READ_1
79 if (cs_1 && ! we_1 && oe_1) begin
80 data_1_out <= mem[address_1];
81 end else begin
82 data_1_out <= 0;
83 end
84 end
85
86 endmodule // End of Module ram_dp_ar_aw
You could download file here
|
|
|
|
|
|
Testbench Code
|
|
|
In the testbench code below, we are causing overflow and underflow conditions. What I mean to say is that FIFO depth is 8, so we can do 8 writes without reading from FIFO. If we do 9 writes then 9th data overwrites the content of FIFO. |
|
|
|
|
|
Similarly if we read from FIFO, when FIFO is empty it causes underflow. This kind of things happen when the code interface block is buggy. We can code assertion either in RTL or in the testbench. For assertions like our example, it is better that the RTL designer codes it along with his code. |
|
|
|
|
|
1 module fifo_tb ();
2 parameter DATA_WIDTH = 8;
3 // Limit depth to 8
4 parameter ADDR_WIDTH = 3;
5
6 reg clk, rst, rd_en, wr_en;
7 reg [DATA_WIDTH-1:0] data_in ;
8 wire [DATA_WIDTH-1:0] data_out ;
9 wire empty, full;
10 integer i;
11
12 initial begin
13 $monitor ("%g wr:%h wr_data:%h rd:%h rd_data:%h",
14 $time, wr_en, data_in, rd_en, data_out);
15 clk = 0;
16 rst = 0;
17 rd_en = 0;
18 wr_en = 0;
19 data_in = 0;
20 #5 rst = 1;
21 #5 rst = 0;
22 @ (negedge clk);
23 wr_en = 1;
24 // We are causing over flow
25 for (i = 0 ; i < 10; i = i + 1) begin
26 data_in = i;
27 @ (negedge clk);
28 end
29 wr_en = 0;
30 @ (negedge clk);
31 rd_en = 1;
32 // We are causing under flow
33 for (i = 0 ; i < 10; i = i + 1) begin
34 @ (negedge clk);
35 end
36 rd_en = 0;
37 #100 $finish;
38 end
39
40 always #1 clk = ! clk;
41
42 syn_fifo #(DATA_WIDTH,ADDR_WIDTH) fifo(
43 .clk (clk) , // Clock input
44 .rst (rst) , // Active high reset
45 .wr_cs (1'b1) , // Write chip select
46 .rd_cs (1'b1) , // Read chipe select
47 .data_in (data_in) , // Data input
48 .rd_en (rd_en) , // Read enable
49 .wr_en (wr_en) , // Write Enable
50 .data_out (data_out), // Data Output
51 .empty (empty) , // FIFO empty
52 .full (full) // FIFO full
53 );
54
55 endmodule
You could download file fifo_tb.v here
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|