@@ -234,32 +234,106 @@ def elaborate(self, platform):
234234 ]
235235 return m
236236
237- # Effectively, this queue treats the output register of the non-FWFT inner queue as
238- # an additional storage element.
239- m .submodules .unbuffered = fifo = SyncFIFO (width = self .width , depth = self .depth - 1 ,
240- fwft = False )
237+ do_write = self .w_rdy & self .w_en
238+ do_read = self .r_rdy & self .r_en
241239
242240 m .d .comb += [
243- fifo .w_data .eq (self .w_data ),
244- fifo .w_en .eq (self .w_en ),
245- self .w_rdy .eq (fifo .w_rdy ),
241+ self .w_level .eq (self .level ),
242+ self .r_level .eq (self .level ),
243+ ]
244+
245+ if self .depth == 1 :
246+ # Special case: a single register. Note that, by construction, this will
247+ # only be able to push a value every other cycle (alternating between
248+ # full and empty).
249+ m .d .comb += [
250+ self .w_rdy .eq (self .level == 0 ),
251+ self .r_rdy .eq (self .level == 1 ),
252+ ]
253+ with m .If (do_write ):
254+ m .d .sync += [
255+ self .r_data .eq (self .w_data ),
256+ self .level .eq (1 ),
257+ ]
258+ with m .If (do_read ):
259+ m .d .sync += [
260+ self .level .eq (0 ),
261+ ]
262+
263+ return m
264+
265+ inner_depth = self .depth - 1
266+ inner_level = Signal (range (inner_depth + 1 ))
267+ inner_r_rdy = Signal ()
268+
269+ m .d .comb += [
270+ self .w_rdy .eq (inner_level != inner_depth ),
271+ inner_r_rdy .eq (inner_level != 0 ),
246272 ]
247273
274+ do_inner_read = inner_r_rdy & (~ self .r_rdy | self .r_en )
275+
276+ m .submodules .storage = storage = Memory (width = self .width , depth = inner_depth )
277+ w_port = storage .write_port ()
278+ r_port = storage .read_port (domain = "sync" , transparent = False )
279+ produce = Signal (range (inner_depth ))
280+ consume = Signal (range (inner_depth ))
281+
248282 m .d .comb += [
249- self .r_data .eq (fifo .r_data ),
250- fifo .r_en .eq (fifo .r_rdy & (~ self .r_rdy | self .r_en )),
283+ w_port .addr .eq (produce ),
284+ w_port .data .eq (self .w_data ),
285+ w_port .en .eq (do_write ),
251286 ]
252- with m .If (fifo .r_en ):
287+ with m .If (do_write ):
288+ m .d .sync += produce .eq (_incr (produce , inner_depth ))
289+
290+ m .d .comb += [
291+ r_port .addr .eq (consume ),
292+ self .r_data .eq (r_port .data ),
293+ r_port .en .eq (do_inner_read )
294+ ]
295+ with m .If (do_inner_read ):
296+ m .d .sync += consume .eq (_incr (consume , inner_depth ))
297+
298+ with m .If (do_write & ~ do_inner_read ):
299+ m .d .sync += inner_level .eq (inner_level + 1 )
300+ with m .If (do_inner_read & ~ do_write ):
301+ m .d .sync += inner_level .eq (inner_level - 1 )
302+
303+ with m .If (do_inner_read ):
253304 m .d .sync += self .r_rdy .eq (1 )
254305 with m .Elif (self .r_en ):
255306 m .d .sync += self .r_rdy .eq (0 )
256307
257308 m .d .comb += [
258- self .level .eq (fifo .level + self .r_rdy ),
259- self .w_level .eq (self .level ),
260- self .r_level .eq (self .level ),
309+ self .level .eq (inner_level + self .r_rdy ),
261310 ]
262311
312+ if platform == "formal" :
313+ # TODO: move this logic to SymbiYosys
314+ with m .If (Initial ()):
315+ m .d .comb += [
316+ Assume (produce < inner_depth ),
317+ Assume (consume < inner_depth ),
318+ ]
319+ with m .If (produce == consume ):
320+ m .d .comb += Assume ((inner_level == 0 ) | (inner_level == inner_depth ))
321+ with m .If (produce > consume ):
322+ m .d .comb += Assume (inner_level == (produce - consume ))
323+ with m .If (produce < consume ):
324+ m .d .comb += Assume (inner_level == (inner_depth + produce - consume ))
325+ with m .Else ():
326+ m .d .comb += [
327+ Assert (produce < inner_depth ),
328+ Assert (consume < inner_depth ),
329+ ]
330+ with m .If (produce == consume ):
331+ m .d .comb += Assert ((inner_level == 0 ) | (inner_level == inner_depth ))
332+ with m .If (produce > consume ):
333+ m .d .comb += Assert (inner_level == (produce - consume ))
334+ with m .If (produce < consume ):
335+ m .d .comb += Assert (inner_level == (inner_depth + produce - consume ))
336+
263337 return m
264338
265339
0 commit comments