Source code for hwtLib.mem.cam

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

from hwt.code import If, Concat
from hwt.hdl.types.bits import Bits
from hwt.hdl.types.defs import BIT
from hwt.interfaces.std import Handshaked
from hwt.interfaces.utils import addClkRstn
from hwt.math import log2ceil
from hwt.serializer.mode import serializeParamsUniq
from hwt.synthesizer.hObjList import HObjList
from hwt.synthesizer.param import Param
from hwt.synthesizer.unit import Unit
from hwtLib.common_nonstd_interfaces.addr_data_hs import AddrDataVldHs, AddrDataHs
from hwtLib.handshaked.streamNode import StreamNode


[docs]@serializeParamsUniq class Cam(Unit): """ Content addressable memory. MATCH_LATENCY = 1 :note: a combinational version :ivar USE_VLD_BIT: if true the validity bit is a part of the CAM record .. hwt-autodoc:: """ def _config(self): self.KEY_WIDTH = Param(15) self.ITEMS = Param(32) self.USE_VLD_BIT = Param(True)
[docs] def _declr_match_io(self): self.match = m = Handshaked() m.DATA_WIDTH = self.KEY_WIDTH # one hot encoded self.out = o = Handshaked()._m() o.DATA_WIDTH = self.ITEMS
def _declr(self): addClkRstn(self) self._declr_match_io() # address is index of CAM cell, data is key to store if self.USE_VLD_BIT: w = AddrDataVldHs() else: w = AddrDataHs() w.DATA_WIDTH = self.KEY_WIDTH w.ADDR_WIDTH = log2ceil(self.ITEMS - 1) self.write = w
[docs] def writeHandler(self, mem): w = self.write w.rd(1) key_data = w.data if self.USE_VLD_BIT: key_data = Concat(w.data, w.vld_flag) If(self.clk._onRisingEdge(), If(w.vld, mem[w.addr](key_data) ) )
[docs] def matchHandler(self, mem, key: Handshaked, match_res: Handshaked): key_data = key.data if self.USE_VLD_BIT: key_data = Concat(key.data, BIT.from_py(1)) out_one_hot = [] for i in range(self.ITEMS): b = mem[i]._eq(key_data) out_one_hot.append(b) match_res.data(Concat(*reversed(out_one_hot))) StreamNode([key], [match_res]).sync()
def _impl(self): KEY_WIDTH = self.KEY_WIDTH if self.USE_VLD_BIT: # +1 bit to validity check KEY_WIDTH += 1 self._mem = self._sig("cam_mem", Bits(KEY_WIDTH)[self.ITEMS], [0 for _ in range(self.ITEMS)] ) self.writeHandler(self._mem) self.matchHandler(self._mem, self.match, self.out)
[docs]@serializeParamsUniq class CamMultiPort(Cam): """ A variant of :class:`~.Cam` with multiple ports for lookup :ivar MATCH_PORT_CNT: number of CAM ports for matching, if None there is only as single port otherwise there is an array of such a ports of specified size .. hwt-autodoc:: _example_CamMultiPort """ def _config(self): Cam._config(self) self.MATCH_PORT_CNT = Param(None)
[docs] def _declr_match_io(self): if self.MATCH_PORT_CNT is None: # single port version Cam._declr_match_io(self) else: # muliport version self.match = HObjList([Handshaked() for _ in range(self.MATCH_PORT_CNT)]) for m in self.match: m.DATA_WIDTH = self.KEY_WIDTH self.out = HObjList([Handshaked()._m() for _ in range(self.MATCH_PORT_CNT)]) for o in self.out: o.DATA_WIDTH = self.ITEMS
[docs] def matchHandler(self, mem, key:Handshaked, match_res:Handshaked): if self.MATCH_PORT_CNT is None: Cam.matchHandler(self, mem, key, match_res) else: # multiport version for _match, _match_res in zip(self.match, self.out): Cam.matchHandler(self, mem, _match, _match_res)
[docs]def _example_CamMultiPort(): u = CamMultiPort() u.MATCH_PORT_CNT = 2 return u
if __name__ == "__main__": from hwt.synthesizer.utils import to_rtl_str u = _example_CamMultiPort() print(to_rtl_str(u))