from nmigen import Array, Module, Signal
-from nmigen.lib.coding import PriorityEncoder, Decoder
+from nmigen.lib.coding import Decoder
from nmigen.cli import main #, verilog
from CamEntry import CamEntry
+from AddressEncoder import AddressEncoder
+from VectorAssembler import VectorAssembler
class Cam():
""" Content Addressable Memory (CAM)
# Internal
self.cam_size = cam_size
- self.encoder = PriorityEncoder(cam_size)
+ self.encoder = AddressEncoder(cam_size)
self.decoder = Decoder(cam_size)
self.entry_array = Array(CamEntry(data_size) \
for x in range(cam_size))
+ self.vector_assembler = VectorAssembler(cam_size)
# Input
self.enable = Signal(1)
- self.write_enable = Signal(1)
+ self.write_enable = Signal(1)
self.data_in = Signal(data_size) # The data to be written
self.data_mask = Signal(data_size) # mask for ternary writes
self.address_in = Signal(max=cam_size) # address of CAM Entry to write
-
+
# Output
self.read_warning = Signal(1) # High when a read interrupts a write
self.single_match = Signal(1) # High when there is only one match
def elaborate(self, platform=None):
m = Module()
- # Encoder is used to selecting what data is output when searching
- m.submodules += self.encoder
+ # Encoder checks for multiple matches
+ m.submodules.AddressEncoder = self.encoder
# Decoder is used to select which entry will be written to
- m.submodules += self.decoder
+ m.submodules.Decoder = self.decoder
# Don't forget to add all entries to the submodule list
entry_array = self.entry_array
m.submodules += entry_array
+ m.submodules.VectorAssembler = self.vector_assembler
# Decoder logic
m.d.comb += [
self.decoder.n.eq(0)
]
- # Set the key value for every CamEntry
- for index in range(self.cam_size):
- with m.If(self.enable == 1):
-
- # Read Operation
- with m.If(self.write_enable == 0):
- m.d.comb += entry_array[index].command.eq(1)
-
+ with m.If(self.enable):
+ # Set the key value for every CamEntry
+ for index in range(self.cam_size):
+
# Write Operation
- with m.Else():
+ with m.If(self.write_enable):
with m.If(self.decoder.o[index]):
m.d.comb += entry_array[index].command.eq(2)
with m.Else():
- m.d.comb += entry_array[index].command.eq(0)
-
+ m.d.comb += entry_array[index].command.eq(0)
+
+ # Read Operation
+ with m.Else():
+ m.d.comb += entry_array[index].command.eq(1)
+
# Send data input to all entries
m.d.comb += entry_array[index].data_in.eq(self.data_in)
- # Send all entry matches to the priority encoder
- m.d.comb += self.encoder.i[index].eq(entry_array[index].match)
-
- # Process out data based on encoder address
- with m.If(self.encoder.n == 0):
- m.d.comb += [
- self.single_match.eq(1),
- self.match_address.eq(self.encoder.o)
- ]
- with m.Else():
- m.d.comb += [
- self.read_warning.eq(0),
- self.single_match.eq(0),
- self.multiple_match.eq(0),
- self.match_address.eq(0)
- ]
-
- with m.Else():
- m.d.comb += [
- self.read_warning.eq(0),
- self.single_match.eq(0),
- self.multiple_match.eq(0),
- self.match_address.eq(0)
- ]
+ # Send all entry matches to encoder
+ ematch = entry_array[index].match
+ m.d.comb += self.vector_assembler.i[index].eq(ematch)
+
+ # Give input to and accept output from encoder module
+ m.d.comb += [
+ self.encoder.i.eq(self.vector_assembler.o),
+ self.single_match.eq(self.encoder.single_match),
+ self.multiple_match.eq(self.encoder.multiple_match),
+ self.match_address.eq(self.encoder.o)
+ ]
+
+ # If the CAM is not enabled set all outputs to 0
+ with m.Else():
+ m.d.comb += [
+ self.read_warning.eq(0),
+ self.single_match.eq(0),
+ self.multiple_match.eq(0),
+ self.match_address.eq(0)
+ ]
+
return m
if __name__ == '__main__':
cam = Cam(4, 4)
- main(cam, ports=[cam.command, cam.address,
- cam.data_in, cam.data_hit,
- cam.data_out])
+ main(cam, ports=[cam.enable, cam.write_enable,
+ cam.data_in, cam.data_mask,
+ cam.read_warning, cam.single_match,
+ cam.multiple_match, cam.match_address])