@@ -123,18 +123,31 @@ class FIFOModelEquivalenceSpec(Elaboratable):
123
123
signals, the behavior of the implementation under test exactly matches the ideal model,
124
124
except for behavior not defined by the model.
125
125
"""
126
- def __init__ (self , fifo , r_domain , w_domain ):
126
+ def __init__ (self , fifo , * , is_async = False ):
127
127
self .fifo = fifo
128
+ self .is_async = is_async
128
129
129
- self .r_domain = r_domain
130
- self .w_domain = w_domain
130
+ if is_async :
131
+ self .cd_read = ClockDomain ()
132
+ self .cd_write = ClockDomain ()
133
+ else :
134
+ self .cd_sync = ClockDomain ()
135
+ self .cd_read = self .cd_write = self .cd_sync
131
136
132
137
@_ignore_deprecated
133
138
def elaborate (self , platform ):
134
139
m = Module ()
140
+
141
+ if self .is_async :
142
+ m .domains += self .cd_read
143
+ m .domains += self .cd_write
144
+ else :
145
+ m .domains += self .cd_sync
146
+
135
147
m .submodules .dut = dut = self .fifo
136
148
m .submodules .gold = gold = FIFOModel (width = dut .width , depth = dut .depth ,
137
- r_domain = self .r_domain , w_domain = self .w_domain )
149
+ r_domain = self .cd_read .name ,
150
+ w_domain = self .cd_write .name )
138
151
139
152
m .d .comb += [
140
153
gold .r_en .eq (dut .r_rdy & dut .r_en ),
@@ -158,30 +171,35 @@ class FIFOContractSpec(Elaboratable):
158
171
consecutively, they must be read out consecutively at some later point, no matter all other
159
172
circumstances, with the exception of reset.
160
173
"""
161
- def __init__ (self , fifo , * , r_domain , w_domain , bound ):
174
+ def __init__ (self , fifo , * , is_async = False , bound ):
162
175
self .fifo = fifo
163
- self .r_domain = r_domain
164
- self .w_domain = w_domain
176
+ self .is_async = is_async
165
177
self .bound = bound
166
178
179
+ self .cd_sync = ClockDomain ()
180
+ if is_async :
181
+ self .cd_read = ClockDomain ()
182
+ self .cd_write = ClockDomain ()
183
+ else :
184
+ self .cd_read = self .cd_write = self .cd_sync
185
+
167
186
@_ignore_deprecated
168
187
def elaborate (self , platform ):
169
188
m = Module ()
170
189
m .submodules .dut = fifo = self .fifo
171
190
172
- m .domains += ClockDomain ("sync" )
173
- m .d .comb += ResetSignal ().eq (0 )
174
- if self .w_domain != "sync" :
175
- m .domains += ClockDomain (self .w_domain )
176
- m .d .comb += ResetSignal (self .w_domain ).eq (0 )
177
- if self .r_domain != "sync" :
178
- m .domains += ClockDomain (self .r_domain )
179
- m .d .comb += ResetSignal (self .r_domain ).eq (0 )
191
+ m .domains += self .cd_sync
192
+ m .d .comb += self .cd_sync .rst .eq (0 )
193
+ if self .is_async :
194
+ m .domains += self .cd_read
195
+ m .domains += self .cd_write
196
+ m .d .comb += self .cd_write .rst .eq (0 )
197
+ m .d .comb += self .cd_read .rst .eq (0 )
180
198
181
199
entry_1 = AnyConst (fifo .width )
182
200
entry_2 = AnyConst (fifo .width )
183
201
184
- with m .FSM (domain = self .w_domain ) as write_fsm :
202
+ with m .FSM (domain = self .cd_write . name ) as write_fsm :
185
203
with m .State ("WRITE-1" ):
186
204
with m .If (fifo .w_rdy ):
187
205
m .d .comb += [
@@ -199,7 +217,7 @@ def elaborate(self, platform):
199
217
with m .State ("DONE" ):
200
218
pass
201
219
202
- with m .FSM (domain = self .r_domain ) as read_fsm :
220
+ with m .FSM (domain = self .cd_read . name ) as read_fsm :
203
221
read_1 = Signal (fifo .width )
204
222
read_2 = Signal (fifo .width )
205
223
with m .State ("READ" ):
@@ -225,18 +243,18 @@ def elaborate(self, platform):
225
243
with m .If (cycle == self .bound ):
226
244
m .d .comb += Assert (read_fsm .ongoing ("DONE" ))
227
245
228
- with m .If (ResetSignal ( domain = self .w_domain ) ):
246
+ with m .If (self .cd_write . rst ):
229
247
m .d .comb += Assert (~ fifo .r_rdy )
230
248
231
- if self .w_domain != "sync" or self . r_domain != "sync" :
232
- # rose_w_domain_clk = Rose(ClockSignal( self.w_domain) )
249
+ if self .is_async :
250
+ # rose_w_domain_clk = Rose(self.cd_write.clk )
233
251
past_w_domain_clk = Signal ()
234
- m .d .sync += past_w_domain_clk .eq (ClockSignal ( self .w_domain ) )
235
- rose_w_domain_clk = (past_w_domain_clk == 0 ) & (ClockSignal ( self .w_domain ) == 1 )
236
- # rose_r_domain_clk = Rose(ClockSignal( self.r_domain) )
252
+ m .d .sync += past_w_domain_clk .eq (self .cd_write . clk )
253
+ rose_w_domain_clk = (past_w_domain_clk == 0 ) & (self .cd_write . clk == 1 )
254
+ # rose_r_domain_clk = Rose(self.cd_read.clk )
237
255
past_r_domain_clk = Signal ()
238
- m .d .sync += past_r_domain_clk .eq (ClockSignal ( self .r_domain ) )
239
- rose_r_domain_clk = (past_r_domain_clk == 0 ) & (ClockSignal ( self .r_domain ) == 1 )
256
+ m .d .sync += past_r_domain_clk .eq (self .cd_read . clk )
257
+ rose_r_domain_clk = (past_r_domain_clk == 0 ) & (self .cd_read . clk == 1 )
240
258
241
259
m .d .comb += Assume (rose_w_domain_clk | rose_r_domain_clk )
242
260
@@ -245,10 +263,13 @@ def elaborate(self, platform):
245
263
246
264
class FIFOFormalCase (FHDLTestCase ):
247
265
def check_sync_fifo (self , fifo ):
248
- self .assertFormal (FIFOModelEquivalenceSpec (fifo , r_domain = "sync" , w_domain = "sync" ),
249
- mode = "bmc" , depth = fifo .depth + 1 )
250
- self .assertFormal (FIFOContractSpec (fifo , r_domain = "sync" , w_domain = "sync" ,
251
- bound = fifo .depth * 2 + 1 ),
266
+ spec_equiv = FIFOModelEquivalenceSpec (fifo , is_async = False )
267
+ self .assertFormal (spec_equiv , [
268
+ spec_equiv .cd_sync .clk , spec_equiv .cd_sync .rst ,
269
+ fifo .w_en , fifo .w_data , fifo .r_en ,
270
+ ], mode = "bmc" , depth = fifo .depth + 1 )
271
+ spec_contract = FIFOContractSpec (fifo , is_async = False , bound = fifo .depth * 2 + 1 )
272
+ self .assertFormal (spec_contract , [spec_contract .cd_sync .clk ],
252
273
mode = "hybrid" , depth = fifo .depth * 2 + 1 )
253
274
254
275
def test_sync_pot (self ):
@@ -272,11 +293,19 @@ def test_sync_buffered_one(self):
272
293
def check_async_fifo (self , fifo ):
273
294
# TODO: properly doing model equivalence checking on this likely requires multiclock,
274
295
# which is not really documented nor is it clear how to use it.
275
- # self.assertFormal(FIFOModelEquivalenceSpec(fifo, r_domain="read", w_domain="write"),
296
+ # spec_equiv = FIFOModelEquivalenceSpec(fifo, is_async=True)
297
+ # self.assertFormal(spec_equiv, [
298
+ # spec_equiv.cd_write.clk, spec_equiv.cd_write.rst,
299
+ # spec_equiv.cd_read.clk, spec_equiv.cd_read.rst,
300
+ # fifo.w_en, fifo.w_data, fifo.r_en,
301
+ # ],
276
302
# mode="bmc", depth=fifo.depth * 3 + 1)
277
- self .assertFormal (FIFOContractSpec (fifo , r_domain = "read" , w_domain = "write" ,
278
- bound = fifo .depth * 4 + 1 ),
279
- mode = "hybrid" , depth = fifo .depth * 4 + 1 )
303
+ spec_contract = FIFOContractSpec (fifo , is_async = True , bound = fifo .depth * 4 + 1 )
304
+ self .assertFormal (spec_contract , [
305
+ spec_contract .cd_sync .clk ,
306
+ spec_contract .cd_write .clk ,
307
+ spec_contract .cd_read .clk ,
308
+ ], mode = "hybrid" , depth = fifo .depth * 4 + 1 )
280
309
281
310
def test_async (self ):
282
311
self .check_async_fifo (AsyncFIFO (width = 8 , depth = 4 ))
0 commit comments