ABSTRACT
An improved technique for fifo design is to perform asynchronous comparisons between the fifo write and read pointers that are generated in
clock domains and asynchronous to each other. The asynchronous fifo pointer comparison technique uses fewer synchronization flip-flops to build the fifo. This method requires additional techniques to correctly synthesize and analyze the design, which are detailed in this paper. To increase the speed of the fifo, this design uses combined binary/Gray counters that take advantage of the built-in binary ripple carry logic. This fifo design is used to implement the AMBA AHB Compliant Memory Controller. This means, Advanced Microcontroller Bus Architecture compliant Microcontroller .The MC is designed for system memory control with the main memory consisting of STRAM and ROM.
CONTENT
Verification Of FIFO Part - I
Verification Of FIFO Part - II
Verification Of FIFO Part - III
In this example, we verify a simple synchronous FIFO. Of course in real life we really don't get to verify a FIFO model, as in companies this are generated using script.
This testbench will slightly different from what we have seen till now. |
So the verification components are split into following blocks |
- Push Generator
- Pop Generator
- Push Monitor
- Pop Monitor
- Scoreboard
- E testbench top
- HDL Testbench top
We are going to have some more components that like reset. Push/Pop Driver, Push/Pop Monitor are going to be part of fifo_driver.e |
Device Under Test
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
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
HDL Testbench Top
1 `include "ram_dp_ar_aw.v"
2 `include "syn_fifo.v"
3
4 module top();
5
6 parameter DATA_WIDTH = 8;
7 parameter ADDR_WIDTH = 3;
8
9 reg clk, rst, wr_cs, rd_cs;
10 reg rd_en, wr_en;
11 reg [DATA_WIDTH-1:0] data_in ;
12 wire full, empty;
13 wire [DATA_WIDTH-1:0] data_out ;
14
15 initial begin
16 clk = 0;
17 rst = 0;
18 wr_cs = 0;
19 rd_cs = 0;
20 rd_en = 0;
21 wr_en = 0;
22 data_in = 0;
23 end
24
25 always #1 clk = ~clk;
26
27 syn_fifo #(DATA_WIDTH,ADDR_WIDTH) fifo(
28 .clk (clk), // Clock input
29 .rst (rst), // Active high reset
30 .wr_cs (wr_cs), // Write chip select
31 .rd_cs (rd_cs), // Read chipe select
32 .data_in (data_in), // Data input
33 .rd_en (rd_en), // Read enable
34 .wr_en (wr_en), // Write Enable
35 .data_out (data_out),// Data Output
36 .empty (empty), // FIFO empty
37 .full (full) // FIFO full
38 );
39
40 endmodule
E Testbench Top
1 <'
2 import fifo_clk.e;
3 import fifo_sb.e;
4 import fifo_driver.e;
5
6 struct fifo_tb {
7 scoreboard : fifo_sb;
8
9 driver : fifo_driver;
10 keep driver.sb == scoreboard;
11
12 go()@sys.clk is {
13 start driver.go();
14 };
15 };
16
17 extend sys {
18 tb : fifo_tb;
19 run() is also {
20 start tb.go();
21 };
22 };
23 '>
FIFO Clock |
. |
1 <'
2 extend sys {
3 event clk is rise('top.clk') @sim;
4 };
5 '>Device Under Test
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
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
HDL Testbench Top
1 `include "ram_dp_ar_aw.v"
2 `include "syn_fifo.v"
3
4 module top();
5
6 parameter DATA_WIDTH = 8;
7 parameter ADDR_WIDTH = 3;
8
9 reg clk, rst, wr_cs, rd_cs;
10 reg rd_en, wr_en;
11 reg [DATA_WIDTH-1:0] data_in ;
12 wire full, empty;
13 wire [DATA_WIDTH-1:0] data_out ;
14
15 initial begin
16 clk = 0;
17 rst = 0;
18 wr_cs = 0;
19 rd_cs = 0;
20 rd_en = 0;
21 wr_en = 0;
22 data_in = 0;
23 end
24
25 always #1 clk = ~clk;
26
27 syn_fifo #(DATA_WIDTH,ADDR_WIDTH) fifo(
28 .clk (clk), // Clock input
29 .rst (rst), // Active high reset
30 .wr_cs (wr_cs), // Write chip select
31 .rd_cs (rd_cs), // Read chipe select
32 .data_in (data_in), // Data input
33 .rd_en (rd_en), // Read enable
34 .wr_en (wr_en), // Write Enable
35 .data_out (data_out),// Data Output
36 .empty (empty), // FIFO empty
37 .full (full) // FIFO full
38 );
39
40 endmodule
E Testbench Top
1 <'
2 import fifo_clk.e;
3 import fifo_sb.e;
4 import fifo_driver.e;
5
6 struct fifo_tb {
7 scoreboard : fifo_sb;
8
9 driver : fifo_driver;
10 keep driver.sb == scoreboard;
11
12 go()@sys.clk is {
13 start driver.go();
14 };
15 };
16
17 extend sys {
18 tb : fifo_tb;
19 run() is also {
20 start tb.go();
21 };
22 };
23 '>
FIFO Clock |
. |
1 <'
2 extend sys {
3 event clk is rise('top.clk') @sim;
4 };
5 '>
FIFO Scoreboard
1 <'
2 struct fifo_sb {
3 ! fifo : list of byte;
4
5 addItem(data : byte) is {
6 if (fifo.size() == 7) {
7 outf("%dns : ERROR : Over flow detected, current occupancy %d\n",
8 sys.time, fifo.size());
9 } else {
10 fifo.push(data);
11 };
12 };
13
14 compareItem (data : byte) is {
15 var cdata : byte = 0;
16 if (fifo.size() == 0) {
17 outf("%dns : ERROR : Under flow detected\n", sys.time);
18 } else {
19 cdata = fifo.pop0();
20 if (data ! = cdata) {
21 outf("%dns : ERROR : Data mismatch, Expected %x Got %x\n",
22 sys.time, cdata, data );
23 };
24 };
25 };
26 };
27 '>
FIFO Driver
1 <'
2 struct fifo_driver {
3 sb : fifo_sb;
4
5 rd_wt : uint [0..100];
6 rd_nop_wt : uint [0..100];
7 wr_wt : uint [0..100];
8 wr_nop_wt : uint [0..100];
9
10 keep soft wr_wt == 50;
11 keep soft rd_wt == 100;
12 keep soft wr_nop_wt == 100;
13 keep soft rd_nop_wt == 50;
14
15 rd : bit;
16 wr : bit;
17
18 rd_cmds : uint;
19 keep rd_cmds == 100;
20 wr_cmds : uint;
21 keep wr_cmds == 100;
22
23 ! rdDone : bool;
24 ! wrDone : bool;
25
26 monitorPush()@sys.clk is {
27 var data : byte = 0;
28 while (TRUE) {
29 wait cycle;
30 if ('top.wr_cs' == 1 && 'top.wr_en' == 1) {
31 data = 'top.data_in';
32 sb.addItem(data);
33 outf("%dns : Write posting to scoreboard data = %x\n",sys.time, data);
34 };
35 };
36 };
37
38 monitorPop()@sys.clk is {
39 var data : byte = 0;
40 while (TRUE) {
41 wait cycle;
42 if ('top.rd_cs' == 1 && 'top.rd_en' == 1) {
43 data = 'top.data_out';
44 sb.compareItem(data);
45 outf("%dns : Read posting to scoreboard data = %x\n",sys.time, data);
46 };
47 };
48 };
49
50 go()@sys.clk is {
51 // Assert reset first
52 reset();
53 // Start the monitors
54 wait [5]*cycle;
55 outf("%dns : Starting Pop and Push monitors\n",sys.time);
56 start monitorPop();
57 start monitorPush();
58 outf("%dns : Starting Pop and Push generators\n",sys.time);
59 start genPush();
60 start genPop();
61
62 while ( ! rdDone && ! wrDone) {
63 wait cycle;
64 };
65 wait [10]*cycle;
66 outf("%dns : Terminating simulations\n",sys.time);
67 stop_run();
68 };
69
70 reset()@sys.clk is {
71 wait [5]*cycle;
72 outf("%dns : Asserting reset\n",sys.time);
73 'top.rst' = 1'b1;
74 // Init all variables
75 rdDone = FALSE;
76 wrDone = FALSE;
77 wait [5]*cycle;
78 'top.rst' = 1'b0;
79 outf("%dns : Done asserting reset\n",sys.time);
80 };
81
82 genPush()@sys.clk is {
83 var data : byte = 0;
84 for {var i : uint = 0; i < wr_cmds; i = i + 1} do {
85 gen wr keeping {
86 soft it == select {
87 wr_wt : 1;
88 wr_nop_wt : 0;
89 };
90 };
91 gen data;
92 wait cycle;
93 while ('top.full' == 1'b1) {
94 'top.wr_cs' = 1'b0;
95 'top.wr_en' = 1'b0;
96 'top.data_in' = 8'b0;
97 wait cycle;
98 };
99 if (wr == 1) {
100 'top.wr_cs' = 1'b1;
101 'top.wr_en' = 1'b1;
102 'top.data_in' = data;
103 } else {
104 'top.wr_cs' = 1'b0;
105 'top.wr_en' = 1'b0;
106 'top.data_in'