Skip to content

Commit a60b996

Browse files
wanda-phiwhitequark
authored andcommitted
lib.fifo: reimplement SyncFIFOBuffered without inner SyncFIFO.
1 parent bfd9626 commit a60b996

File tree

2 files changed

+90
-13
lines changed

2 files changed

+90
-13
lines changed

amaranth/lib/fifo.py

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

tests/test_lib_fifo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ def test_sync_buffered_potp1(self):
270270
def test_sync_buffered_potm1(self):
271271
self.check_sync_fifo(SyncFIFOBuffered(width=8, depth=3))
272272

273+
def test_sync_buffered_one(self):
274+
self.check_sync_fifo(SyncFIFOBuffered(width=8, depth=1))
275+
273276
def check_async_fifo(self, fifo):
274277
# TODO: properly doing model equivalence checking on this likely requires multiclock,
275278
# which is not really documented nor is it clear how to use it.

0 commit comments

Comments
 (0)