#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from hwt.code import If
from hwt.constants import NOT_SPECIFIED
from hwt.hdl.types.bits import HBits
from hwt.hdl.types.bitsRtlSignal import HBitsRtlSignal
from hwt.hwIOs.std import HwIOFifoWriter, HwIOFifoReader, HwIOVectSignal
from hwt.hwIOs.utils import addClkRstn
from hwt.hwModule import HwModule
from hwt.hwParam import HwParam
from hwt.math import log2ceil
from hwt.pyUtils.typingFuture import override
from hwt.serializer.mode import serializeParamsUniq
from hwtLib.mem.fifoPtrLogic import FifoPtrLogic
[docs]
@serializeParamsUniq
class Fifo(HwModule):
"""
Generic FIFO usually mapped to BRAM.
:note: 1clk to write, 1clk to read
:ivar ~.EXPORT_SIZE: parameter, if true "size" signal will be exported
:ivar ~.size: optional signal with count of items stored in this fifo
:ivar ~.EXPORT_SPACE: parameter, if true "space" signal is exported
:ivar ~.space: optional signal with count of items which can be added to this fifo
.. hwt-autodoc:: _example_Fifo
"""
@override
def hwConfig(self):
self.DATA_WIDTH = HwParam(64)
self.DEPTH = HwParam(0)
self.EXPORT_SIZE = HwParam(False)
self.EXPORT_SPACE = HwParam(False)
self.INIT_DATA: tuple = HwParam(())
self.INIT_DATA_FIRST_WORD = HwParam(NOT_SPECIFIED)
[docs]
def _declr_size_and_space(self):
if self.EXPORT_SIZE:
self.size = HwIOVectSignal(log2ceil(self.DEPTH + 1), signed=False)._m()
if self.EXPORT_SPACE:
self.space = HwIOVectSignal(log2ceil(self.DEPTH + 1), signed=False)._m()
@override
def hwDeclr(self):
assert self.DEPTH > 0, \
"Fifo is disabled in this case, do not use it entirely"
assert self.DEPTH > 1, \
"Fifo DEPTH must be >1 in order to fifo pointers to work correctly"
addClkRstn(self)
with self._hwParamsShared():
self.dataIn = HwIOFifoWriter()
self.dataOut = HwIOFifoReader()._m()
self._declr_size_and_space()
[docs]
def constructFifoSizeLogic(self, fifo_read: HBitsRtlSignal, fifo_write: HBitsRtlSignal):
size = self._reg("size_reg", self.size._dtype, len(self.INIT_DATA))
If(fifo_read,
If(~fifo_write,
size(size - 1)
)
).Else(
If(fifo_write,
size(size + 1)
)
)
self.size(size)
[docs]
def constructFifoSpaceLogic(self, fifo_read: HBitsRtlSignal, fifo_write: HBitsRtlSignal):
space = self._reg("space_reg", self.space._dtype, self.DEPTH - len(self.INIT_DATA))
If(fifo_read,
If(~fifo_write,
space(space + 1)
)
).Else(
If(fifo_write,
space(space - 1)
)
)
self.space(space)
@override
def hwImpl(self):
DEPTH = self.DEPTH
dout = self.dataOut
din = self.dataIn
s = self._sig
fifoPtrs = FifoPtrLogic(self, DEPTH, INIT_SIZE=len(self.INIT_DATA))
((fifo_write, wr_ptr), (fifo_read, rd_ptr),) = fifoPtrs.fifo_pointers(
(din.en, din.wait), [(dout.en, dout.wait), ])
init_data = self.INIT_DATA
if not init_data:
init_data_expanded = None
else:
init_data_expanded = list(init_data) + [None for _ in range(self.DEPTH - len(init_data))]
if self.DATA_WIDTH:
mem = self.mem = s("memory", HBits(self.DATA_WIDTH)[DEPTH], def_val=init_data_expanded)
If(self.clk._onRisingEdge(),
If(fifo_write,
# Write Data to Memory
mem[wr_ptr](din.data)
)
)
If(self.clk._onRisingEdge(),
If(fifo_read,
# Update data output
dout.data(mem[rd_ptr])
)
if self.INIT_DATA_FIRST_WORD == NOT_SPECIFIED else
If(self.rst_n._isOn(),
dout.data(self.INIT_DATA_FIRST_WORD),
).Elif(fifo_read,
# Update data output
dout.data(mem[rd_ptr])
)
)
if self.EXPORT_SIZE:
self.constructFifoSizeLogic(fifo_read, fifo_write)
if self.EXPORT_SPACE:
self.constructFifoSpaceLogic(fifo_read, fifo_write)
[docs]
def _example_Fifo():
m = Fifo()
m.DATA_WIDTH = 8
m.EXPORT_SIZE = True
m.EXPORT_SPACE = True
m.INIT_DATA = (1, 2, 3)
m.INIT_DATA_FIRST_WORD = 0
m.DEPTH = 16
return m
if __name__ == "__main__":
from hwt.synth import to_rtl_str
m = _example_Fifo()
print(to_rtl_str(m))