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 HBits
from hwt.hdl.types.defs import BIT
from hwt.hwIOs.hwIOArray import HwIOArray
from hwt.hwIOs.std import HwIODataRdVld
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.commonHwIO.addr_data import HwIOAddrDataVldRdVld, HwIOAddrDataRdVld
from hwtLib.handshaked.streamNode import StreamNode
[docs]
@serializeParamsUniq
class Cam(HwModule):
"""
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::
"""
@override
def hwConfig(self):
self.KEY_WIDTH = HwParam(15)
self.ITEMS = HwParam(32)
self.USE_VLD_BIT = HwParam(True)
[docs]
def _declr_match_io(self):
self.match = m = HwIODataRdVld()
m.DATA_WIDTH = self.KEY_WIDTH
# one hot encoded
self.out = o = HwIODataRdVld()._m()
o.DATA_WIDTH = self.ITEMS
@override
def hwDeclr(self):
addClkRstn(self)
self._declr_match_io()
# address is index of CAM cell, data is key to store
if self.USE_VLD_BIT:
w = HwIOAddrDataVldRdVld()
else:
w = HwIOAddrDataRdVld()
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: HwIODataRdVld, match_res: HwIODataRdVld):
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()
@override
def hwImpl(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",
HBits(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
"""
@override
def hwConfig(self):
Cam.hwConfig(self)
self.MATCH_PORT_CNT = HwParam(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 = HwIOArray([HwIODataRdVld() for _ in range(self.MATCH_PORT_CNT)])
for m in self.match:
m.DATA_WIDTH = self.KEY_WIDTH
self.out = HwIOArray([HwIODataRdVld() for _ in range(self.MATCH_PORT_CNT)])._m()
for o in self.out:
o.DATA_WIDTH = self.ITEMS
[docs]
def matchHandler(self, mem, key:HwIODataRdVld, match_res:HwIODataRdVld):
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():
m = CamMultiPort()
m.MATCH_PORT_CNT = 2
return m
if __name__ == "__main__":
from hwt.synth import to_rtl_str
m = _example_CamMultiPort()
print(to_rtl_str(m))