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 94e136e13..1ee3ffa90 100644 --- a/transactron/utils/fifo.py +++ b/transactron/utils/fifo.py @@ -2,6 +2,7 @@ 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): @@ -51,25 +52,21 @@ def __init__(self, layout: MethodLayout, depth: int) -> None: # 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.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.comb += self.read_ready.eq(self.level != 0) + m.d.comb += self.write_ready.eq(self.level != self.depth) with m.If(self.read.run & ~self.write.run): m.d.sync += self.level.eq(self.level - 1) @@ -78,20 +75,20 @@ 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.buff_rdport.addr.eq(Mux(self.read.run, next_read_idx, self.read_idx)) m.d.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) m.d.sync += self.write_idx.eq(mod_incr(self.write_idx, self.depth)) @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 @def_method(m, self.clear) 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.