Source code for hwtLib.amba.axi_comp.sim.ram

from collections import deque

from hwt.hdl.types.bits import Bits
from hwt.hdl.value import HValue
from hwtLib.abstract.sim_ram import SimRam
from hwtLib.amba.constants import RESP_OKAY
from hwtLib.amba.datapump.sim_ram import AxiDpSimRam
from pyMathBitPrecise.bit_utils import mask, set_bit_range, get_bit, \
    get_bit_range


[docs]class AxiSimRam(AxiDpSimRam): """ Simulation memory for Axi3/4 interfaces (slave component) """
[docs] def __init__(self, axi=None, axiAR=None, axiR=None, axiAW=None, axiW=None, axiB=None, parent=None, allow_unaligned_addr=False): """ :param clk: clk which should this memory use in simulation :param axi: axi (Axi3/4 master) interface to listen on :param axiAR, axiR, axiAW, axiW, axiB: splited interface use this if you do not have full axi interface :attention: use axi or axi parts not bouth :param parent: parent instance of this memory, memory will operate with same memory as parent one :attention: memories are commiting into memory in "data" property after transaction is complete """ if axi is not None: assert axiAR is None assert axiR is None assert axiAW is None assert axiW is None assert axiB is None if axi.HAS_R: axiAR = axi.ar axiR = axi.r if axi.HAS_W: axiAW = axi.aw axiW = axi.w axiB = axi.b if axiAR is not None: self.arAg = axiAR._ag self.rAg = axiR._ag DW = int(axiR.DATA_WIDTH) clk = axiAR._getAssociatedClk() else: assert axiR is None self.arAg = None self.rAg = None if axiAW is not None: self.awAg = axiAW._ag self.wAg = axiW._ag self.wAckAg = axiB._ag DW = int(axiW.DATA_WIDTH) clk = axiAW._getAssociatedClk() else: assert axiW is None assert axiB is None self.awAg = None self.wAg = None self.wAckAg = None assert axiAR is not None or axiAW is not None if self.wAg is not None: self.HAS_W_ID = hasattr(self.wAg.intf, "id") else: self.HAS_W_ID = False self.allow_unaligned_addr = allow_unaligned_addr SimRam.__init__(self, DW // 8, parent=parent) self.allMask = mask(self.cellSize) self.word_t = Bits(self.cellSize * 8) self.rPending = deque() self.wPending = deque() self.clk = clk self._registerOnClock()
[docs] def parseReq(self, req): try: req = [int(v) for v in req] except ValueError: raise AssertionError("Invalid AXI request", req) from None _id = req[0] addr = req[1] size = req[4] + 1 return (_id, addr, size, self.allMask)
[docs] def add_r_ag_data(self, _id, data, isLast): self.rAg.data.append((_id, data, RESP_OKAY, isLast))
[docs] def doRead(self): _id, addr, size, _ = self.rPending.popleft() baseIndex = addr // self.cellSize if baseIndex * self.cellSize != addr: if not self.allow_unaligned_addr: raise ValueError("not aligned", addr) offset = addr % self.cellSize word_t = self.word_t word_mask0 = mask(8 * self.cellSize) word_mask1 = mask((self.cellSize - offset) * 8) else: offset = 0 mem = self.data for i in range(size): isLast = i == size - 1 data = mem.get(baseIndex + i, None) if offset != 0: data1 = mem.get(baseIndex + i + 1, None) if data is None: if data1 is None: # data = None pass else: data = data1 << ((self.cellSize - offset) * 8) data = data & word_mask1 else: if data1 is None: if isinstance(data, int): data = word_t.from_py( data >> (offset * 8), word_mask0) else: data = ((data >> (offset * 8)) & word_mask0) \ | ((data1 << ((self.cellSize - offset) * 8)) & word_mask1) if data is None: raise AssertionError( "Invalid read of uninitialized value on addr 0x%x" % (addr + i * self.cellSize)) self.add_r_ag_data(_id, data, isLast)
[docs] def pop_w_ag_data(self, _id): if self.HAS_W_ID: _id2, data, strb, last = self.wAg.data.popleft() _id2 = int(_id2) assert _id == _id2 else: data, strb, last = self.wAg.data.popleft() return (data, strb, last)
[docs] def _write_single_word(self, data: HValue, strb: int, word_i: int): if strb == 0: return if strb != self.allMask: cur = self.data.get(word_i, None) if cur is None: cur_val = 0 cur_mask = 0 elif isinstance(cur, int): cur_val = cur cur_mask = self.allMask else: cur_val = cur.val cur_mask = cur.vld_mask for i in range(self.cellSize): if get_bit(strb, i): cur_val = set_bit_range( cur_val, i * 8, 8, get_bit_range(data.val, i * 8, 8)) cur_mask = set_bit_range( cur_mask, i * 8, 8, get_bit_range(data.vld_mask, i * 8, 8)) if cur_mask == self.allMask: data = cur_val else: data = self.word_t.from_py(cur_val, cur_mask) # print(f"data[{word_i:d}] = {data}") self.data[word_i] = data
[docs] def doWrite(self): _id, addr, size, _ = self.wPending.popleft() baseIndex = addr // self.cellSize offset = addr % self.cellSize if offset and not self.allow_unaligned_addr: raise ValueError("not aligned", addr) for i in range(size): data, strb, last = self.pop_w_ag_data(_id) strb = int(strb) last = int(last) last = bool(last) isLast = i == size - 1 assert last == isLast, (addr, size, i) if offset == 0: # print("alig", data, strb) self._write_single_word(data, strb, baseIndex + i) else: # print("init", data, strb) d0 = data << (offset * 8) strb0 = strb << offset d1 = (data >> (offset * 8)) & self.allMask strb1 = (strb >> offset) & mask(self.cellSize) # print("split", d0, d1, strb0, strb1) self._write_single_word(d0, strb0, baseIndex + i) self._write_single_word(d1, strb1, baseIndex + i + 1) self.doWriteAck(_id)
[docs] def doWriteAck(self, _id): self.wAckAg.data.append((_id, RESP_OKAY))