1 from nmigen
import Array
, Module
, Signal
2 from nmigen
.lib
.coding
import Decoder
3 from nmigen
.cli
import main
#, verilog
5 from CamEntry
import CamEntry
6 from AddressEncoder
import AddressEncoder
7 from VectorAssembler
import VectorAssembler
10 """ Content Addressable Memory (CAM)
12 The purpose of this module is to quickly look up whether an
13 entry exists given a data key.
14 This module will search for the given data in all internal entries
15 and output whether a single or multiple match was found.
16 If an single entry is found the address be returned and single_match
17 is set HIGH. If multiple entries are found the lowest address is
18 returned and multiple_match is set HIGH. If neither single_match or
19 multiple_match are HIGH this implies no match was found. To write
20 to the CAM set the address bus to the desired entry and set write_enable
21 HIGH. Entry managment should be performed one level above this block
22 as lookup is performed within.
25 The read and write operations take one clock cycle to complete.
28 def __init__(self
, data_size
, cam_size
):
30 * data_size: (bit count) The size of the data
31 * cam_size: (entry count) The number of entries int he CAM
35 self
.cam_size
= cam_size
36 self
.encoder
= AddressEncoder(cam_size
)
37 self
.decoder
= Decoder(cam_size
)
38 self
.entry_array
= Array(CamEntry(data_size
) \
39 for x
in range(cam_size
))
40 self
.vector_assembler
= VectorAssembler(cam_size
)
43 self
.enable
= Signal(1)
44 self
.write_enable
= Signal(1)
45 self
.data_in
= Signal(data_size
) # The data to be written
46 self
.data_mask
= Signal(data_size
) # mask for ternary writes
47 self
.address_in
= Signal(max=cam_size
) # address of CAM Entry to write
50 self
.read_warning
= Signal(1) # High when a read interrupts a write
51 self
.single_match
= Signal(1) # High when there is only one match
52 self
.multiple_match
= Signal(1) # High when there at least two matches
53 self
.match_address
= Signal(max=cam_size
) # The lowest address matched
55 def elaborate(self
, platform
=None):
57 # Encoder checks for multiple matches
58 m
.submodules
.AddressEncoder
= self
.encoder
59 # Decoder is used to select which entry will be written to
60 m
.submodules
.Decoder
= self
.decoder
61 # Don't forget to add all entries to the submodule list
62 entry_array
= self
.entry_array
63 m
.submodules
+= entry_array
64 m
.submodules
.VectorAssembler
= self
.vector_assembler
68 self
.decoder
.i
.eq(self
.address_in
),
72 with m
.If(self
.enable
):
73 # Set the key value for every CamEntry
74 for index
in range(self
.cam_size
):
77 with m
.If(self
.write_enable
):
78 with m
.If(self
.decoder
.o
[index
]):
79 m
.d
.comb
+= entry_array
[index
].command
.eq(2)
81 m
.d
.comb
+= entry_array
[index
].command
.eq(0)
85 m
.d
.comb
+= entry_array
[index
].command
.eq(1)
87 # Send data input to all entries
88 m
.d
.comb
+= entry_array
[index
].data_in
.eq(self
.data_in
)
89 # Send all entry matches to encoder
90 ematch
= entry_array
[index
].match
91 m
.d
.comb
+= self
.vector_assembler
.i
[index
].eq(ematch
)
93 # Give input to and accept output from encoder module
95 self
.encoder
.i
.eq(self
.vector_assembler
.o
),
96 self
.single_match
.eq(self
.encoder
.single_match
),
97 self
.multiple_match
.eq(self
.encoder
.multiple_match
),
98 self
.match_address
.eq(self
.encoder
.o
)
101 # If the CAM is not enabled set all outputs to 0
104 self
.read_warning
.eq(0),
105 self
.single_match
.eq(0),
106 self
.multiple_match
.eq(0),
107 self
.match_address
.eq(0)
112 if __name__
== '__main__':
114 main(cam
, ports
=[cam
.enable
, cam
.write_enable
,
115 cam
.data_in
, cam
.data_mask
,
116 cam
.read_warning
, cam
.single_match
,
117 cam
.multiple_match
, cam
.match_address
])