92464103b775faa7892ee5fdc2497c319d2e84e4
1 from nmigen
import Array
, Module
, Signal
2 from nmigen
.lib
.coding
import Decoder
, Encoder
, PriorityEncoder
3 from nmigen
.cli
import main
#, verilog
5 from CamEntry
import CamEntry
8 """ Content Addressable Memory (CAM)
10 The purpose of this module is to quickly look up whether an
11 entry exists given a certain key and return the mapped data.
12 This module when given a key will search for the given key
13 in all internal entries and output whether a match was found or not.
14 If an entry is found the data will be returned and data_hit is HIGH,
15 if it is not LOW is asserted on data_hit. When given a write
16 command it will write the given key and data into the given cam
18 Entry managment should be performed one level above this block
19 as lookup is performed within.
22 The search, write, and reset operations take one clock cycle
23 to complete. Performing a read immediately after a search will cause
24 the read to be ignored.
27 def __init__(self
, data_size
, cam_size
):
29 * data_size: (bit count) The size of the data
30 * cam_size: (entry count) The number of entries int he CAM
34 self
.cam_size
= cam_size
35 self
.encoder
= Encoder(cam_size
)
36 self
.p_encoder
= PriorityEncoder(cam_size
)
37 self
.decoder
= Decoder(cam_size
)
38 self
.entry_array
= Array(CamEntry(data_size
) \
39 for x
in range(cam_size
))
42 self
.enable
= Signal(1)
43 self
.write_enable
= Signal(1)
44 self
.data_in
= Signal(data_size
) # The data to be written
45 self
.data_mask
= Signal(data_size
) # mask for ternary writes
46 self
.address_in
= Signal(max=cam_size
) # address of CAM Entry to write
49 self
.read_warning
= Signal(1) # High when a read interrupts a write
50 self
.single_match
= Signal(1) # High when there is only one match
51 self
.multiple_match
= Signal(1) # High when there at least two matches
52 self
.match_address
= Signal(max=cam_size
) # The lowest address matched
54 def elaborate(self
, platform
=None):
56 # Encoder checks for multiple matches
57 m
.submodules
+= self
.encoder
58 # Priority Encoder is used to select output address
59 m
.submodules
+= self
.p_encoder
60 # Decoder is used to select which entry will be written to
61 m
.submodules
+= self
.decoder
62 # Don't forget to add all entries to the submodule list
63 entry_array
= self
.entry_array
64 m
.submodules
+= entry_array
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 m
.d
.comb
+= entry_array
[index
].command
.eq(1)
82 with m
.If(self
.decoder
.o
[index
]):
83 m
.d
.comb
+= entry_array
[index
].command
.eq(2)
85 m
.d
.comb
+= entry_array
[index
].command
.eq(0)
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 m
.d
.comb
+= self
.encoder
.i
[index
].eq(entry_array
[index
].match
)
91 # Send all entry matches to the priority encoder
92 m
.d
.comb
+= self
.p_encoder
.i
[index
].eq(entry_array
[index
].match
)
94 # If the priority encoder recieves an input of 0
95 with m
.If(self
.p_encoder
.n
):
97 self
.read_warning
.eq(0),
98 self
.single_match
.eq(0),
99 self
.multiple_match
.eq(0),
100 self
.match_address
.eq(0)
102 # If the priority encoder recieves an input > 0
104 # Multiple Match if encoder n is invalid
105 with m
.If(self
.encoder
.n
):
107 self
.single_match
.eq(0),
108 self
.multiple_match
.eq(1)
110 # Single Match if encoder n is valid
113 self
.single_match
.eq(1),
114 self
.multiple_match
.eq(0)
116 # Always set output based on priority encoder output
117 m
.d
.comb
+= self
.match_address
.eq(self
.p_encoder
.o
)
119 # If the CAM is not enabled set all outputs to 0
122 self
.read_warning
.eq(0),
123 self
.single_match
.eq(0),
124 self
.multiple_match
.eq(0),
125 self
.match_address
.eq(0)
130 if __name__
== '__main__':
132 main(cam
, ports
=[cam
.enable
, cam
.write_enable
,
133 cam
.data_in
, cam
.data_mask
,
134 cam
.read_warning
, cam
.single_match
,
135 cam
.multiple_match
, cam
.match_address
])