Source code for basil.HL.bram_fifo
#
# ------------------------------------------------------------
# Copyright (c) All rights reserved
# SiLab, Institute of Physics, University of Bonn
# ------------------------------------------------------------
#
import logging
from time import sleep
import numpy as np
from basil.HL.RegisterHardwareLayer import RegisterHardwareLayer
logger = logging.getLogger(__name__)
[docs]
class bram_fifo(RegisterHardwareLayer):
"""BRAM-backed FIFO controller.
The corresponding firmware module stores incoming 32-bit FIFO words in
FPGA BRAM. The regular ``base_addr`` configuration key addresses the
control registers, while ``base_data_addr`` must point to the 32-bit data
window used by :meth:`get_data`.
``FIFO_SIZE`` reports the amount of buffered data in bytes. The driver
rounds this down to complete 32-bit words before reading data.
"""
_registers = {
"RESET": {"descr": {"addr": 0, "size": 8, "properties": ["writeonly"]}},
"VERSION": {"descr": {"addr": 0, "size": 8, "properties": ["ro"]}},
"ALMOST_FULL_THRESHOLD": {"descr": {"addr": 1, "size": 8}},
"ALMOST_EMPTY_THRESHOLD": {"descr": {"addr": 2, "size": 8}},
"READ_ERROR_COUNTER": {"descr": {"addr": 3, "size": 8, "properties": ["ro"]}},
"FIFO_SIZE": {"descr": {"addr": 4, "size": 32, "properties": ["ro"]}},
}
_require_version = "==2"
def __init__(self, intf, conf):
"""Create a BRAM FIFO driver.
Parameters
----------
intf : basil transfer layer
Interface used for control-register and data-window access.
conf : dict
Driver configuration. Requires ``base_addr`` for the control
registers and ``base_data_addr`` for the FIFO data window.
"""
super(bram_fifo, self).__init__(intf, conf)
[docs]
def reset(self):
"""Soft-reset the FIFO and wait briefly for the firmware to settle."""
self.RESET = 0
sleep(0.01) # wait some time for initialization
@property
def FIFO_INT_SIZE(self):
"""Get FIFO size in units of integers (32 bit).
Returns
-------
fifo_size : int
FIFO size in units of integers (32 bit).
"""
fifo_size = self.FIFO_SIZE
# sometimes reading of FIFO size happens during writing to BRAM, but we want to have a multiplicity of 32 bits
return int((fifo_size - (fifo_size % 4)) / 4)
[docs]
def get_FIFO_INT_SIZE(self):
"""Get FIFO size in units of integers (32 bit).
Returns
-------
fifo_size : int
FIFO size in units of integers (32 bit).
"""
return self.FIFO_INT_SIZE
[docs]
def get_data(self):
"""Read all currently buffered complete 32-bit words.
The method reads ``FIFO_SIZE`` twice and uses the smaller value to
avoid requesting more data while the FIFO size is changing. Data are
read from ``base_data_addr`` and returned as little-endian unsigned
32-bit integers.
Returns
-------
array : numpy.ndarray
Array of unsigned 32-bit FIFO words.
"""
fifo_int_size_1 = self.FIFO_INT_SIZE
fifo_int_size_2 = self.FIFO_INT_SIZE
if fifo_int_size_1 > fifo_int_size_2:
fifo_int_size = fifo_int_size_2 # use smaller chunk
logger.warning("Reading wrong FIFO size. Expected: %d <= %d" % (fifo_int_size_1, fifo_int_size_2))
else:
fifo_int_size = fifo_int_size_1 # use smaller chunk
return np.frombuffer(
self._intf.read(self._conf["base_data_addr"], size=4 * fifo_int_size), dtype=np.dtype("<u4")
) # size in number of bytes