1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
// Since this FIFO uses a ZBT/NoBL SRAM for its storage which is a since port
// device it can only sustain data throughput at half the RAM clock rate.
// Fair arbitration to ensure this occurs is included in this logic and
// requests for transactions that can not be completed are held off.
// This FIFO requires a an external signal driving read_strobe that assures space for at least 6
// reads since this the theopretical maximum number in flight due to pipeling.
module nobl_fifo
#(parameter WIDTH=18,RAM_DEPTH=19,FIFO_DEPTH=19)
(
input clk,
input rst,
input [WIDTH-1:0] RAM_D_pi,
output [WIDTH-1:0] RAM_D_po,
output RAM_D_poe,
output [RAM_DEPTH-1:0] RAM_A,
output RAM_WEn,
output RAM_CENn,
output RAM_LDn,
output RAM_OEn,
output RAM_CE1n,
input [WIDTH-1:0] write_data,
input write_strobe,
output reg space_avail,
output [WIDTH-1:0] read_data,
input read_strobe, // Triggers a read, result in approximately 6 cycles.
output data_avail, // Qulaifys read data available this cycle on read_data.
output reg [FIFO_DEPTH-1:0] capacity
);
//reg [FIFO_DEPTH-1:0] capacity;
reg [FIFO_DEPTH-1:0] wr_pointer;
reg [FIFO_DEPTH-1:0] rd_pointer;
wire [RAM_DEPTH-1:0] address;
reg data_avail_int; // Internal not empty flag.
assign read = read_strobe && data_avail_int;
assign write = write_strobe && space_avail;
// When a read and write collision occur, supress the space_avail flag next cycle
// and complete write followed by read over 2 cycles. This forces balanced arbitration
// and makes for a simple logic design.
always @(posedge clk)
if (rst)
begin
capacity <= (1 << FIFO_DEPTH) - 1;
wr_pointer <= 0;
rd_pointer <= 0;
space_avail <= 1;
data_avail_int <= 0;
end
else
begin
// No space available if:
// Capacity is already zero; Capacity is 1 and write is asserted (lookahead); both read and write are asserted (collision)
space_avail <= ~((capacity == 0) || (read&&write) || ((capacity == 1) && write) );
// Capacity has 1 cycle delay so look ahead here for corner case of read of last item in FIFO.
data_avail_int <= ~((capacity == ((1 << FIFO_DEPTH)-1)) || ((capacity == ((1 << FIFO_DEPTH)-2)) && (~write && read)) );
wr_pointer <= wr_pointer + write;
rd_pointer <= rd_pointer + (~write && read);
capacity <= capacity - write + (~write && read) ;
end // else: !if(rst)
assign address = write ? wr_pointer : rd_pointer;
assign enable = write || read;
//
// Simple NoBL SRAM interface, 4 cycle read latency.
// Read/Write arbitration via temprary application of empty/full flags.
//
nobl_if nobl_if_i1
(
.clk(clk),
.rst(rst),
.RAM_D_pi(RAM_D_pi),
.RAM_D_po(RAM_D_po),
.RAM_D_poe(RAM_D_poe),
.RAM_A(RAM_A),
.RAM_WEn(RAM_WEn),
.RAM_CENn(RAM_CENn),
.RAM_LDn(RAM_LDn),
.RAM_OEn(RAM_OEn),
.RAM_CE1n(RAM_CE1n),
.address(address),
.data_out(write_data),
.data_in(read_data),
.data_in_valid(data_avail),
.write(write),
.enable(enable)
);
endmodule // nobl_fifo
|