Source code for hwtLib.mem.hashTableCore

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import Optional

from hwt.code import Concat
from hwt.interfaces.std import Handshaked
from hwt.interfaces.utils import propagateClkRstn, addClkRstn
from hwt.math import log2ceil
from hwt.synthesizer.unit import Unit
from hwtLib.common_nonstd_interfaces.addr_data_hs import AddrDataHs
from hwtLib.handshaked.builder import HsBuilder
from hwtLib.handshaked.ramAsHs import RamHsR
from hwtLib.handshaked.streamNode import StreamNode
from hwtLib.logic.crcComb import CrcComb
from hwtLib.logic.crcPoly import CRC_32
from hwtLib.mem.hashTable_intf import LookupKeyIntf, HashTableIntf


# https://web.stanford.edu/class/cs166/lectures/13/Small13.pdf
[docs]class HashTableCore(Unit): """ Generic hash table, in block RAM there is a input key which is hashed ad this has is used as an index into memory item on this place is checked and returned on "lookupRes" interface (item does have to be found, see "found" flag in LookupResultIntf) memory is an array of items in format .. code-block:: c struct item { bool item_vld; data_t data; key_t key; }; :ivar ~.ITEMS_CNT: number of items in memory of hash table :ivar ~.KEY_WIDTH: width of the key used by hash table :ivar ~.DATA_WIDTH: width of data, can be zero and then no data interface is instantiated :ivar ~.LOOKUP_ID_WIDTH: width of id signal for lookup (tag used only by parent component to mark this lookup for later result processing, can be 0) :ivar ~.LOOKUP_HASH: flag if lookup interface should have hash signal :ivar ~.LOOKUP_KEY: flag if lookup interface should have key signal :ivar ~.POLYNOME: polynome for crc hash used in this table .. figure:: ./_static/HashTableCore.png .. hwt-autodoc:: _example_HashTableCore """
[docs] def __init__(self, polynome): super(HashTableCore, self).__init__() self.POLYNOME = polynome
def _config(self): HashTableIntf._config(self)
[docs] def _declr_common(self): addClkRstn(self) with self._paramsShared(): self.io = HashTableIntf() h = self.hash = CrcComb() h.DATA_WIDTH = self.KEY_WIDTH h.setConfig(self.POLYNOME)
def _declr(self): self._declr_common() self.r = RamHsR()._m() self.w = AddrDataHs()._m() for i in [self.r, self.w]: i.ADDR_WIDTH = log2ceil(self.ITEMS_CNT) i.DATA_WIDTH = self.KEY_WIDTH + self.DATA_WIDTH + 1 # +1 for item_vld
[docs] def parseItem(self, sig): """ Parse data stored in hash table """ DW = self.DATA_WIDTH KW = self.KEY_WIDTH item_vld = sig[0] dataLow = 1 dataHi = dataLow + DW if dataHi > dataLow: data = sig[dataHi:dataLow] else: data = None keyLow = dataHi keyHi = keyLow + KW # assert keyHi > keyLow key = sig[keyHi:keyLow] return (key, data, item_vld)
[docs] def lookupLogic(self, ramR: RamHsR): h = self.hash lookup = self.io.lookup res = self.io.lookupRes # tmp storage for original key and hash for later check origKeyIn = LookupKeyIntf() origKeyIn.KEY_WIDTH = self.KEY_WIDTH self.origKeyIn = origKeyIn origKeyIn.key(lookup.key) if lookup.LOOKUP_ID_WIDTH: origKeyIn.lookupId(lookup.lookupId) origKey = HsBuilder(self, origKeyIn).buff(2).end # hash key and address with has in table h.dataIn(lookup.key) # hash can be wider ramR.addr.data(h.dataOut, fit=True) inputSlaves = [ramR.addr, origKeyIn] outputMasters = [origKey, ramR.data, ] if self.LOOKUP_HASH: origHashIn = Handshaked() origHashIn.DATA_WIDTH = self.io.HASH_WIDTH self.origHashIn = origHashIn origHashOut = HsBuilder(self, origHashIn).buff(2).end origHashIn.data(h.dataOut, fit=True) inputSlaves.append(origHashIn) outputMasters.append(origHashOut) StreamNode(masters=[lookup], slaves=inputSlaves).sync() # propagate loaded data StreamNode(masters=outputMasters, slaves=[res]).sync() key, data, item_vld = self.parseItem(ramR.data.data) if self.LOOKUP_HASH: res.hash(origHashOut.data) if self.LOOKUP_KEY: res.key(key) if self.LOOKUP_ID_WIDTH: res.lookupId(origKey.lookupId) if self.DATA_WIDTH: res.data(data) res.occupied(item_vld) res.found(origKey.key._eq(key) & item_vld)
[docs] def insertLogic(self, ramW: AddrDataHs): In = self.io.insert if self.DATA_WIDTH: rec = Concat(In.key, In.data, In.item_vld) else: rec = Concat(In.key, In.item_vld) ramW.data(rec) ramW.addr(In.hash) StreamNode(masters=[In], slaves=[ramW]).sync()
def _impl(self, r: Optional[RamHsR]=None, w: Optional[AddrDataHs]=None): if r is None: r = self.r if w is None: w = self.w self.lookupLogic(r) self.insertLogic(w) propagateClkRstn(self)
[docs]def _example_HashTableCore(): return HashTableCore(CRC_32)
if __name__ == "__main__": from hwt.synthesizer.utils import to_rtl_str u = _example_HashTableCore() print(to_rtl_str(u))