Add LiteX equivalent of Xilinx FIFO_SYNC_MACRO
This commit is contained in:
parent
ca6378a207
commit
c584cb3fa7
|
@ -0,0 +1,156 @@
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
from litex.soc.interconnect.stream import SyncFIFO
|
||||||
|
|
||||||
|
class FIFOSyncMacro(Module, Record):
|
||||||
|
"""FIFOSyncMacro
|
||||||
|
|
||||||
|
Provides an equivalent of Xilinx' FIFO_SYNC_MACRO which is a unimacro dedicated for 7 series
|
||||||
|
FPGAs and Zynq-7000 SoC.
|
||||||
|
|
||||||
|
Detailed informations can be found in official documentation:
|
||||||
|
https://docs.xilinx.com/r/2021.2-English/ug953-vivado-7series-libraries/FIFO_SYNC_MACRO
|
||||||
|
"""
|
||||||
|
def __init__(self, fifo_size="18Kb", data_width=32, almost_empty_offset=0, almost_full_offset=0, do_reg=0, toolchain="vivado"):
|
||||||
|
assert data_width <= 72
|
||||||
|
assert fifo_size in ["18Kb", "36Kb"]
|
||||||
|
if do_reg and toolchain != "vivado":
|
||||||
|
raise NotImplementedError("FIFOSyncMacro: DO_REG==1 is supported only for Vivado toolchain")
|
||||||
|
|
||||||
|
fifo_sync_macro_layout = [
|
||||||
|
("rd_d", data_width),
|
||||||
|
("almostfull", 1),
|
||||||
|
("almostempty", 1),
|
||||||
|
("full", 1),
|
||||||
|
("empty", 1),
|
||||||
|
("rdcount", 13),
|
||||||
|
("rderr", 1),
|
||||||
|
("wrerr", 1),
|
||||||
|
("wrcount", 13),
|
||||||
|
("rden", 1),
|
||||||
|
("wr_d", data_width),
|
||||||
|
("wren", 1),
|
||||||
|
("reset", 1)
|
||||||
|
]
|
||||||
|
Record.__init__(self, fifo_sync_macro_layout)
|
||||||
|
|
||||||
|
if toolchain == "vivado":
|
||||||
|
self.specials += Instance("FIFO_SYNC_MACRO",
|
||||||
|
p_DEVICE = "7SERIES",
|
||||||
|
p_FIFO_SIZE = fifo_size,
|
||||||
|
p_DATA_WIDTH = data_width,
|
||||||
|
p_ALMOST_EMPTY_OFFSET = almost_empty_offset,
|
||||||
|
p_ALMOST_FULL_OFFSET = almost_full_offset,
|
||||||
|
p_DO_REG = do_reg,
|
||||||
|
i_CLK = ClockSignal(),
|
||||||
|
i_RST = self.reset,
|
||||||
|
o_ALMOSTFULL = self.almostfull,
|
||||||
|
o_ALMOSTEMPTY = self.almostempty,
|
||||||
|
o_FULL = self.full,
|
||||||
|
o_EMPTY = self.empty,
|
||||||
|
i_WREN = self.wren,
|
||||||
|
i_DI = self.wr_d,
|
||||||
|
i_RDEN = self.rden,
|
||||||
|
o_DO = self.rd_d,
|
||||||
|
o_RDCOUNT = self.rdcount,
|
||||||
|
o_RDERR = self.rderr,
|
||||||
|
o_WRCOUNT = self.wrcount,
|
||||||
|
o_WRERR = self.wrerr,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
level = Signal(14)
|
||||||
|
|
||||||
|
# FIFO size is adjusted to only match configurations supported by FIFO_SYNC_MACRO
|
||||||
|
if fifo_size == "18Kb":
|
||||||
|
fifo_size = 16
|
||||||
|
elif fifo_size == "36Kb":
|
||||||
|
fifo_size = 32
|
||||||
|
else:
|
||||||
|
raise ValueError("FIFOSyncMacro can only be configured to 18Kb or 36Kb of memory")
|
||||||
|
|
||||||
|
if data_width in range(1, 5):
|
||||||
|
macro_data_width = 4
|
||||||
|
elif data_width in range(5, 10):
|
||||||
|
macro_data_width = 8
|
||||||
|
elif data_width in range(10, 19):
|
||||||
|
macro_data_width = 16
|
||||||
|
elif data_width in range(19, 37):
|
||||||
|
macro_data_width = 32
|
||||||
|
elif data_width in range(37, 73):
|
||||||
|
if fifo_size == 36:
|
||||||
|
macro_data_width = 64
|
||||||
|
else:
|
||||||
|
raise ValueError("FIFOSyncMacro accepts data width up to 72 bits only for 36Kb FIFO size.")
|
||||||
|
else:
|
||||||
|
raise ValueError("FIFOSyncMacro only accepts data width up to 72 bits.")
|
||||||
|
|
||||||
|
self.fifo_depth = fifo_depth = (int)(fifo_size * 1024 / macro_data_width)
|
||||||
|
|
||||||
|
self.submodules.fifo = fifo = ResetInserter()(SyncFIFO([("data", data_width)], fifo_depth))
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
fifo.reset.eq(self.reset),
|
||||||
|
|
||||||
|
level.eq(fifo.level),
|
||||||
|
|
||||||
|
# connect port signals to internal fifo
|
||||||
|
# sink
|
||||||
|
fifo.sink.data.eq(self.wr_d),
|
||||||
|
fifo.sink.valid.eq(self.wren),
|
||||||
|
# source
|
||||||
|
self.rd_d.eq(fifo.source.data),
|
||||||
|
fifo.source.ready.eq(self.rden),
|
||||||
|
|
||||||
|
self.wrerr.eq(~fifo.sink.ready & self.wren),
|
||||||
|
self.rderr.eq(fifo.source.ready & self.rden),
|
||||||
|
|
||||||
|
If(level == 0,
|
||||||
|
self.empty.eq(1)
|
||||||
|
).Else(
|
||||||
|
self.empty.eq(0)
|
||||||
|
),
|
||||||
|
|
||||||
|
If(level == fifo_depth,
|
||||||
|
self.full.eq(1)
|
||||||
|
).Else(
|
||||||
|
self.full.eq(0)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
# reset only these two since other signals are dependent on fifo state
|
||||||
|
If(self.reset,
|
||||||
|
self.rdcount.eq(0),
|
||||||
|
self.wrcount.eq(0),
|
||||||
|
),
|
||||||
|
|
||||||
|
# wrcount and rdcount are counters of respectively written and read words
|
||||||
|
If(fifo.sink.ready & fifo.sink.valid,
|
||||||
|
If(self.wrcount == (fifo_depth - 1),
|
||||||
|
self.wrcount.eq(0)
|
||||||
|
).Else(
|
||||||
|
self.wrcount.eq(self.wrcount + 1),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
If(fifo.source.ready & fifo.source.valid,
|
||||||
|
If(self.rdcount == (fifo_depth - 1),
|
||||||
|
self.rdcount.eq(0)
|
||||||
|
).Else(
|
||||||
|
self.rdcount.eq(self.rdcount + 1),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
# assert almostempty when fifo level is lower than almost_empty_offset
|
||||||
|
If((level <= almost_empty_offset),
|
||||||
|
self.almostempty.eq(1)
|
||||||
|
).Else(
|
||||||
|
self.almostempty.eq(0)
|
||||||
|
),
|
||||||
|
|
||||||
|
# assert almostfull when fifo level is higher than almost_full_offset
|
||||||
|
If((level >= (fifo_depth - almost_full_offset)),
|
||||||
|
self.almostfull.eq(1)
|
||||||
|
).Else(
|
||||||
|
self.almostfull.eq(0)
|
||||||
|
),
|
||||||
|
]
|
Loading…
Reference in New Issue