1 from nmigen
import Array
, Cat
, 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
9 """ Content Addressable Memory (CAM)
11 The purpose of this module is to quickly look up whether an
12 entry exists given a data key.
13 This module will search for the given data in all internal entries
14 and output whether a single or multiple match was found.
15 If an single entry is found the address be returned and single_match
16 is set HIGH. If multiple entries are found the lowest address is
17 returned and multiple_match is set HIGH. If neither single_match or
18 multiple_match are HIGH this implies no match was found. To write
19 to the CAM set the address bus to the desired entry and set write_enable
20 HIGH. Entry managment should be performed one level above this block
21 as lookup is performed within.
24 The read and write operations take one clock cycle to complete.
25 Currently the read_warning line is present for interfacing but
26 is not necessary for this design. This module is capable of writing
27 in the first cycle, reading on the second, and output the correct
31 def __init__(self
, data_size
, cam_size
):
33 * data_size: (bits) The bit size of the data
34 * cam_size: (number) The number of entries in the CAM
38 self
.cam_size
= cam_size
39 self
.encoder
= AddressEncoder(cam_size
)
40 self
.decoder
= Decoder(cam_size
)
41 self
.entry_array
= Array(CamEntry(data_size
) for x
in range(cam_size
))
44 self
.enable
= Signal(1)
45 self
.write_enable
= Signal(1)
46 self
.data_in
= Signal(data_size
) # The data to be written
47 self
.data_mask
= Signal(data_size
) # mask for ternary writes
48 self
.address_in
= Signal(max=cam_size
) # address of CAM Entry to write
51 self
.read_warning
= Signal(1) # High when a read interrupts a write
52 self
.single_match
= Signal(1) # High when there is only one match
53 self
.multiple_match
= Signal(1) # High when there at least two matches
54 self
.match_address
= Signal(max=cam_size
) # The lowest address matched
56 def elaborate(self
, platform
=None):
58 # AddressEncoder for match types and output address
59 m
.submodules
.AddressEncoder
= self
.encoder
60 # Decoder is used to select which entry will be written to
61 m
.submodules
.Decoder
= self
.decoder
62 # CamEntry Array Submodules
63 # Note these area added anonymously
64 entry_array
= self
.entry_array
65 m
.submodules
+= entry_array
69 self
.decoder
.i
.eq(self
.address_in
),
74 with m
.If(self
.enable
):
75 # Set the key value for every CamEntry
76 for index
in range(self
.cam_size
):
79 with m
.If(self
.write_enable
):
80 with m
.If(self
.decoder
.o
[index
]):
81 m
.d
.comb
+= entry_array
[index
].command
.eq(2)
83 m
.d
.comb
+= entry_array
[index
].command
.eq(0)
87 m
.d
.comb
+= entry_array
[index
].command
.eq(1)
89 # Send data input to all entries
90 m
.d
.comb
+= entry_array
[index
].data_in
.eq(self
.data_in
)
91 # Send all entry matches to encoder
92 ematch
= entry_array
[index
].match
93 encoder_vector
.append(ematch
)
95 # Give input to and accept output from encoder module
97 self
.encoder
.i
.eq(Cat(*encoder_vector
)),
98 self
.single_match
.eq(self
.encoder
.single_match
),
99 self
.multiple_match
.eq(self
.encoder
.multiple_match
),
100 self
.match_address
.eq(self
.encoder
.o
)
103 # If the CAM is not enabled set all outputs to 0
106 self
.read_warning
.eq(0),
107 self
.single_match
.eq(0),
108 self
.multiple_match
.eq(0),
109 self
.match_address
.eq(0)
115 return [self
.enable
, self
.write_enable
,
116 self
.data_in
, self
.data_mask
,
117 self
.read_warning
, self
.single_match
,
118 self
.multiple_match
, self
.match_address
]
121 if __name__
== '__main__':
123 main(cam
, ports
=cam
.ports())