1 |
3 |
kfleming |
// import standard library
|
2 |
|
|
import FIFO::*;
|
3 |
|
|
import RegFile::*;
|
4 |
|
|
import StmtFSM::*;
|
5 |
|
|
import Vector::*;
|
6 |
|
|
|
7 |
|
|
// import self-made library
|
8 |
|
|
import BRAM::*;
|
9 |
|
|
import VLevelFIFO::*;
|
10 |
|
|
|
11 |
|
|
// implementation of VLevelFIFO with BRAM
|
12 |
|
|
module mkBRAMVLevelFIFO (VLevelFIFO#(no_fifo, fifo_sz, data_t))
|
13 |
|
|
provisos (Bits#(data_t,data_sz),
|
14 |
|
|
Add#(TLog#(no_fifo),TLog#(fifo_sz),bram_idx_sz));
|
15 |
|
|
|
16 |
|
|
// instantiate an unguarded 1 cycle latency bram (i.e. the read response will only valid for 1 cycle)
|
17 |
|
|
UGBRAM#(Bit#(bram_idx_sz), data_t) ugbram <- mkBypassUGBRAM_Full();
|
18 |
|
|
|
19 |
|
|
RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz))) head <- mkRegFileFull();
|
20 |
|
|
RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz))) tail <- mkRegFileFull();
|
21 |
|
|
Reg#(Bit#(TLog#(no_fifo))) i <- mkReg(0);
|
22 |
|
|
Reg#(Bool) finishInit <- mkReg(False);
|
23 |
|
|
|
24 |
|
|
Reg#(Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1))))) usedReg <- mkReg(replicate(0));
|
25 |
|
|
Wire#(Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1))))) usedW <- mkDWire(replicate(0));
|
26 |
|
|
|
27 |
|
|
Reg#(Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1))))) freeReg <- mkReg(replicate(fromInteger(valueOf(fifo_sz))));
|
28 |
|
|
|
29 |
|
|
Wire#(Maybe#(Bit#(TLog#(no_fifo)))) enqIdx <- mkDWire(tagged Invalid);
|
30 |
|
|
Wire#(data_t) enqVal <- mkDWire(?);
|
31 |
|
|
|
32 |
|
|
Wire#(Maybe#(Bit#(TLog#(no_fifo)))) deqIdx <- mkDWire(tagged Invalid);
|
33 |
|
|
|
34 |
|
|
Wire#(Maybe#(Bit#(TLog#(no_fifo)))) firstIdx <- mkDWire(tagged Invalid);
|
35 |
|
|
|
36 |
|
|
Wire#(Maybe#(Bit#(TLog#(no_fifo)))) decrFreeIdx <- mkDWire(tagged Invalid);
|
37 |
|
|
|
38 |
|
|
let enqIdxVal = fromMaybe(0,enqIdx);
|
39 |
|
|
let deqIdxVal = fromMaybe(0,deqIdx);
|
40 |
|
|
let firstIdxVal = fromMaybe(0,firstIdx);
|
41 |
|
|
let decrFreeIdxVal = fromMaybe(0,decrFreeIdx);
|
42 |
|
|
let deqIdxNEQFirstIdx = deqIdxVal != firstIdxVal;
|
43 |
|
|
let readResp = ugbram.read_resp();
|
44 |
|
|
|
45 |
|
|
// start the initialization processor
|
46 |
|
|
rule initialization(!finishInit);
|
47 |
|
|
head.upd(i,0);
|
48 |
|
|
tail.upd(i,0);
|
49 |
|
|
i <= i + 1;
|
50 |
|
|
if (i == fromInteger(valueOf(no_fifo)-1))
|
51 |
|
|
finishInit <= True;
|
52 |
|
|
endrule
|
53 |
|
|
|
54 |
|
|
rule updateUsedReg(finishInit && (isValid(enqIdx) || isValid(deqIdx)));
|
55 |
|
|
Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) newUsedReg = newVector();
|
56 |
|
|
|
57 |
|
|
for (Integer i = 0; i < valueOf(no_fifo); i = i + 1)
|
58 |
|
|
newUsedReg[i] = usedReg[i];
|
59 |
|
|
|
60 |
|
|
if (isValid(enqIdx))
|
61 |
|
|
newUsedReg[enqIdxVal] = usedReg[enqIdxVal] + 1;
|
62 |
|
|
|
63 |
|
|
if (isValid(deqIdx))
|
64 |
|
|
newUsedReg[deqIdxVal] = newUsedReg[deqIdxVal] - 1;
|
65 |
|
|
|
66 |
|
|
usedReg <= newUsedReg;
|
67 |
|
|
usedW <= newUsedReg;
|
68 |
|
|
|
69 |
|
|
// $display("updateUsedReg");
|
70 |
|
|
endrule
|
71 |
|
|
|
72 |
|
|
rule updateUsedW(finishInit && !(isValid(enqIdx) || isValid(deqIdx)));
|
73 |
|
|
usedW <= usedReg;
|
74 |
|
|
endrule
|
75 |
|
|
|
76 |
|
|
rule updateFreeReg(finishInit && (isValid(decrFreeIdx) || isValid(deqIdx)));
|
77 |
|
|
Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) newFreeReg = newVector();
|
78 |
|
|
|
79 |
|
|
for (Integer i = 0; i < valueOf(no_fifo); i = i + 1)
|
80 |
|
|
newFreeReg[i] = freeReg[i];
|
81 |
|
|
|
82 |
|
|
if (isValid(decrFreeIdx))
|
83 |
|
|
newFreeReg[decrFreeIdxVal] = freeReg[decrFreeIdxVal] - 1;
|
84 |
|
|
|
85 |
|
|
if (isValid(deqIdx))
|
86 |
|
|
newFreeReg[deqIdxVal] = newFreeReg[deqIdxVal] + 1;
|
87 |
|
|
|
88 |
|
|
freeReg <= newFreeReg;
|
89 |
|
|
|
90 |
|
|
// $display("updateFreeReg");
|
91 |
|
|
endrule
|
92 |
|
|
|
93 |
|
|
rule processEnq(finishInit && isValid(enqIdx));
|
94 |
|
|
let tailVal = tail.sub(enqIdxVal);
|
95 |
|
|
tail.upd(enqIdxVal, (tailVal + 1));
|
96 |
|
|
ugbram.write({enqIdxVal,tailVal},enqVal);
|
97 |
|
|
|
98 |
|
|
// $display("enq data %d to fifo %d with tailVal %d",data,idx,tailVal);
|
99 |
|
|
endrule
|
100 |
|
|
|
101 |
|
|
rule processFirstReq(finishInit && isValid(firstIdx));
|
102 |
|
|
let headVal = head.sub(firstIdxVal);
|
103 |
|
|
if (deqIdxNEQFirstIdx || !isValid(deqIdx))
|
104 |
|
|
begin
|
105 |
|
|
ugbram.read_req({firstIdxVal,headVal});
|
106 |
|
|
//$display("first read idx %d headVal %d",firstIdxVal,headVal);
|
107 |
|
|
end
|
108 |
|
|
else // the fifo is dequeued at that cycle, we should read the next head
|
109 |
|
|
begin
|
110 |
|
|
ugbram.read_req({firstIdxVal,headVal+1});
|
111 |
|
|
//$display("first read idx %d headVal+1 %d",firstIdxVal,headVal+1);
|
112 |
|
|
end
|
113 |
|
|
endrule
|
114 |
|
|
|
115 |
|
|
rule processDeq(finishInit && isValid(deqIdx));
|
116 |
|
|
let headVal = head.sub(deqIdxVal);
|
117 |
|
|
head.upd(deqIdxVal, (headVal + 1));
|
118 |
|
|
endrule
|
119 |
|
|
|
120 |
|
|
// enq is unguarded here, we expect the user to check it before they enq
|
121 |
|
|
method Action enq(Bit#(TLog#(no_fifo)) idx, data_t data) if (finishInit);
|
122 |
|
|
enqIdx <= tagged Valid idx;
|
123 |
|
|
enqVal <= data;
|
124 |
|
|
endmethod
|
125 |
|
|
|
126 |
|
|
// deq is unguarded here, we expect the user to check it before they deq
|
127 |
|
|
method Action deq(Bit#(TLog#(no_fifo)) idx) if (finishInit);
|
128 |
|
|
deqIdx <= tagged Valid idx;
|
129 |
|
|
|
130 |
|
|
// $display("deq fifo %d",idx);
|
131 |
|
|
endmethod
|
132 |
|
|
|
133 |
|
|
method Action firstReq(Bit#(TLog#(no_fifo)) idx) if (finishInit);
|
134 |
|
|
firstIdx <= tagged Valid idx;
|
135 |
|
|
endmethod
|
136 |
|
|
|
137 |
|
|
// first is unguarded here, we expecte the user to check it before they call first
|
138 |
|
|
method data_t firstResp() if (finishInit);
|
139 |
|
|
return readResp;
|
140 |
|
|
endmethod
|
141 |
|
|
|
142 |
|
|
method Action clear() if (finishInit);
|
143 |
|
|
noAction;
|
144 |
|
|
endmethod
|
145 |
|
|
|
146 |
|
|
// return the usage of each fifo at the beginning of the cycle
|
147 |
|
|
method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) used() if (finishInit);
|
148 |
|
|
return usedReg;
|
149 |
|
|
endmethod
|
150 |
|
|
|
151 |
|
|
// return the usage of each fifo at the end of the cycle
|
152 |
|
|
method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) used2() if (finishInit);
|
153 |
|
|
return usedW;
|
154 |
|
|
endmethod
|
155 |
|
|
|
156 |
|
|
// return enq credit token available for each fifo
|
157 |
|
|
method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) free() if (finishInit);
|
158 |
|
|
return freeReg;
|
159 |
|
|
endmethod
|
160 |
|
|
|
161 |
|
|
// get credit token to enq fifo idx in the future
|
162 |
|
|
// this method is unguarded (i.e. user need to call method free
|
163 |
|
|
// and check for token availability before calling this action)
|
164 |
|
|
method Action decrFree(Bit#(TLog#(no_fifo)) idx) if (finishInit);
|
165 |
|
|
decrFreeIdx <= tagged Valid idx;
|
166 |
|
|
endmethod
|
167 |
|
|
|
168 |
|
|
endmodule
|
169 |
|
|
|
170 |
|
|
(* synthesize *)
|
171 |
|
|
module mkBRAMVLevelFIFOInstance(VLevelFIFO#(32, 16, Bit#(129)));
|
172 |
|
|
let fifo <- mkBRAMVLevelFIFO();
|
173 |
|
|
return fifo;
|
174 |
|
|
endmodule
|
175 |
|
|
|
176 |
|
|
/*
|
177 |
|
|
(* synthesize *)
|
178 |
|
|
module mkBRAMVLevelFIFOTest(Empty);
|
179 |
|
|
let fifo <- mkBRAMVLevelFIFOInstance();
|
180 |
|
|
Reg#(Bit#(8)) enqIdx <- mkReg(0);
|
181 |
|
|
Reg#(Bit#(129)) enqData <- mkReg(0);
|
182 |
|
|
Reg#(Bit#(8)) firstIdx <- mkReg(0);
|
183 |
|
|
FIFO#(Bit#(0)) reqQ <- mkFIFO();
|
184 |
|
|
Reg#(Bit#(8)) deqIdx <- mkReg(0);
|
185 |
|
|
Reg#(Bit#(32)) cycleCnt <- mkReg(0);
|
186 |
|
|
let used = fifo.used();
|
187 |
|
|
let free = fifo.free();
|
188 |
|
|
|
189 |
|
|
rule enqFifo(free[enqIdx[7:2]] > 0);
|
190 |
|
|
enqIdx <= enqIdx + 1;
|
191 |
|
|
enqData <= enqData + 1;
|
192 |
|
|
fifo.enq(enqIdx[7:2],enqData);
|
193 |
|
|
fifo.decrFree(enqIdx[7:2]);
|
194 |
|
|
|
195 |
|
|
$display("enq fifo %d with data %d",enqIdx[7:2],enqData);
|
196 |
|
|
endrule
|
197 |
|
|
|
198 |
|
|
rule firstFifo(used[deqIdx[7:2]] > 0);
|
199 |
|
|
firstIdx <= firstIdx + 1;
|
200 |
|
|
fifo.firstReq(firstIdx[7:2]);
|
201 |
|
|
reqQ.enq(?);
|
202 |
|
|
|
203 |
|
|
$display("first req fifo %d",firstIdx[7:2]);
|
204 |
|
|
endrule
|
205 |
|
|
|
206 |
|
|
rule deqFifo(True);
|
207 |
|
|
reqQ.deq();
|
208 |
|
|
if (used[deqIdx[7:2]] > 0)
|
209 |
|
|
begin
|
210 |
|
|
deqIdx <= deqIdx + 1;
|
211 |
|
|
let deqData = fifo.firstResp();
|
212 |
|
|
fifo.deq(deqIdx[7:2]);
|
213 |
|
|
|
214 |
|
|
$display("deq fifo %d with data %d",deqIdx[7:2],deqData);
|
215 |
|
|
end
|
216 |
|
|
else
|
217 |
|
|
$display("last first req is not reading valid data");
|
218 |
|
|
endrule
|
219 |
|
|
|
220 |
|
|
rule displayStat(True);
|
221 |
|
|
for (Integer i = 0; i < 64; i = i + 1)
|
222 |
|
|
$display("%d: used %d, free %d",i,used[i],free[i]);
|
223 |
|
|
endrule
|
224 |
|
|
|
225 |
|
|
rule countCycle(True);
|
226 |
|
|
cycleCnt <= cycleCnt + 1;
|
227 |
|
|
$display("cycle %d",cycleCnt);
|
228 |
|
|
if (cycleCnt == 5000)
|
229 |
|
|
$finish();
|
230 |
|
|
endrule
|
231 |
|
|
|
232 |
|
|
endmodule
|
233 |
|
|
*/
|