From 43ef2df8a296834c89d90b9959925d48c6ebbb59 Mon Sep 17 00:00:00 2001 From: Lekcyjna <309016@uwr.edu.pl> Date: Sun, 19 Nov 2023 15:50:10 +0100 Subject: [PATCH] Tweaks to BasicFifo --- test/utils/test_fifo.py | 2 ++ transactron/utils/fifo.py | 26 ++++++++------------------ transactron/utils/utils.py | 10 ++++++++++ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/test/utils/test_fifo.py b/test/utils/test_fifo.py index 2f5608141..b74667fc3 100644 --- a/test/utils/test_fifo.py +++ b/test/utils/test_fifo.py @@ -1,4 +1,5 @@ from amaranth import * +from amaranth.sim import Settle from transactron.utils.fifo import BasicFifo from transactron.lib import AdapterTrans @@ -55,6 +56,7 @@ def source(): if random.random() < 0.005: yield from fifoc.fifo_clear.call() + yield Settle() expq.clear() self.done = True diff --git a/transactron/utils/fifo.py b/transactron/utils/fifo.py index 4332fffb3..3377b350d 100644 --- a/transactron/utils/fifo.py +++ b/transactron/utils/fifo.py @@ -2,10 +2,12 @@ from transactron import Method, def_method, Priority, TModule from transactron._utils import MethodLayout from transactron.utils._typing import ValueLike +from transactron.utils.utils import mod_incr class BasicFifo(Elaboratable): """Transactional FIFO queue + Attributes ---------- read: Method @@ -17,6 +19,7 @@ class BasicFifo(Elaboratable): clear: Method Clears the FIFO entries. Has priority over `read` and `write` methods. Note that, clearing the FIFO doesn't reinitialize it to values passed in `init` parameter. + """ def __init__(self, layout: MethodLayout, depth: int) -> None: @@ -28,48 +31,40 @@ def __init__(self, layout: MethodLayout, depth: int) -> None: If integer is given, Record with field `data` and width of this paramter is used as internal layout. depth: int Size of the FIFO. + """ self.layout = layout self.width = len(Record(self.layout)) self.depth = depth + self.read = Method(o=self.layout) self.write = Method(i=self.layout) self.clear = Method() self.head = Record(self.layout) + self.buff = Memory(width=self.width, depth=self.depth) + self.write_ready = Signal() self.read_ready = Signal() + self.read_idx = Signal((self.depth - 1).bit_length()) self.write_idx = Signal((self.depth - 1).bit_length()) # current fifo depth self.level = Signal((self.depth).bit_length()) - self.clear.add_conflict(self.read, Priority.LEFT) - self.clear.add_conflict(self.write, Priority.LEFT) # for interface compatibility with MultiportFifo self.read_methods = [self.read] self.write_methods = [self.write] def elaborate(self, platform): - def mod_incr(sig: Value, mod: int) -> Value: - # perform (sig+1)%mod operation - if mod == 2 ** len(sig): - return sig + 1 - return Mux(sig == mod - 1, 0, sig + 1) - m = TModule() - m.submodules.buff_rdport = self.buff_rdport = self.buff.read_port( - domain="comb", transparent=True - ) # FWFT behaviour next_read_idx = Signal.like(self.read_idx) m.d.top_comb += next_read_idx.eq(mod_incr(self.read_idx, self.depth)) m.submodules.buff_rdport = self.buff_rdport = self.buff.read_port(domain="sync", transparent=True) m.submodules.buff_wrport = self.buff_wrport = self.buff.write_port() - m.d.comb += self.read_ready.eq(self.level > 0) - m.d.comb += self.write_ready.eq(self.level < self.depth) m.d.top_comb += self.read_ready.eq(self.level != 0) m.d.top_comb += self.write_ready.eq(self.level != self.depth) @@ -80,15 +75,11 @@ def mod_incr(sig: Value, mod: int) -> Value: with m.If(self.clear.run): m.d.sync += self.level.eq(0) - m.d.comb += self.buff_rdport.addr.eq(self.read_idx) - m.d.comb += self.head.eq(self.buff_rdport.data) m.d.top_comb += self.buff_rdport.addr.eq(Mux(self.read.run, next_read_idx, self.read_idx)) m.d.top_comb += self.head.eq(self.buff_rdport.data) @def_method(m, self.write, ready=self.write_ready) def _(arg: Record) -> None: - m.d.comb += self.buff_wrport.addr.eq(self.write_idx) - m.d.comb += self.buff_wrport.data.eq(arg) m.d.top_comb += self.buff_wrport.addr.eq(self.write_idx) m.d.top_comb += self.buff_wrport.data.eq(arg) m.d.comb += self.buff_wrport.en.eq(1) @@ -97,7 +88,6 @@ def _(arg: Record) -> None: @def_method(m, self.read, self.read_ready) def _() -> ValueLike: - m.d.sync += self.read_idx.eq(mod_incr(self.read_idx, self.depth)) m.d.sync += self.read_idx.eq(next_read_idx) return self.head diff --git a/transactron/utils/utils.py b/transactron/utils/utils.py index 13491cd7b..bbd1e7310 100644 --- a/transactron/utils/utils.py +++ b/transactron/utils/utils.py @@ -23,9 +23,19 @@ "popcount", "count_leading_zeros", "count_trailing_zeros", + "mod_incr", ] +def mod_incr(sig: Value, mod: int) -> Value: + """ + Perform `(sig+1) % mod` operation. + """ + if mod == 2 ** len(sig): + return sig + 1 + return Mux(sig == mod - 1, 0, sig + 1) + + @contextmanager def OneHotSwitch(m: ModuleLike, test: Value): """One-hot switch.