@@ -123,18 +123,31 @@ class FIFOModelEquivalenceSpec(Elaboratable):
123123 signals, the behavior of the implementation under test exactly matches the ideal model,
124124 except for behavior not defined by the model.
125125 """
126- def __init__ (self , fifo , r_domain , w_domain ):
126+ def __init__ (self , fifo , * , is_async = False ):
127127 self .fifo = fifo
128+ self .is_async = is_async
128129
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
131136
132137 @_ignore_deprecated
133138 def elaborate (self , platform ):
134139 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+
135147 m .submodules .dut = dut = self .fifo
136148 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 )
138151
139152 m .d .comb += [
140153 gold .r_en .eq (dut .r_rdy & dut .r_en ),
@@ -158,30 +171,35 @@ class FIFOContractSpec(Elaboratable):
158171 consecutively, they must be read out consecutively at some later point, no matter all other
159172 circumstances, with the exception of reset.
160173 """
161- def __init__ (self , fifo , * , r_domain , w_domain , bound ):
174+ def __init__ (self , fifo , * , is_async = False , bound ):
162175 self .fifo = fifo
163- self .r_domain = r_domain
164- self .w_domain = w_domain
176+ self .is_async = is_async
165177 self .bound = bound
166178
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+
167186 @_ignore_deprecated
168187 def elaborate (self , platform ):
169188 m = Module ()
170189 m .submodules .dut = fifo = self .fifo
171190
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 )
180198
181199 entry_1 = AnyConst (fifo .width )
182200 entry_2 = AnyConst (fifo .width )
183201
184- with m .FSM (domain = self .w_domain ) as write_fsm :
202+ with m .FSM (domain = self .cd_write . name ) as write_fsm :
185203 with m .State ("WRITE-1" ):
186204 with m .If (fifo .w_rdy ):
187205 m .d .comb += [
@@ -199,7 +217,7 @@ def elaborate(self, platform):
199217 with m .State ("DONE" ):
200218 pass
201219
202- with m .FSM (domain = self .r_domain ) as read_fsm :
220+ with m .FSM (domain = self .cd_read . name ) as read_fsm :
203221 read_1 = Signal (fifo .width )
204222 read_2 = Signal (fifo .width )
205223 with m .State ("READ" ):
@@ -225,18 +243,18 @@ def elaborate(self, platform):
225243 with m .If (cycle == self .bound ):
226244 m .d .comb += Assert (read_fsm .ongoing ("DONE" ))
227245
228- with m .If (ResetSignal ( domain = self .w_domain ) ):
246+ with m .If (self .cd_write . rst ):
229247 m .d .comb += Assert (~ fifo .r_rdy )
230248
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 )
233251 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 )
237255 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 )
240258
241259 m .d .comb += Assume (rose_w_domain_clk | rose_r_domain_clk )
242260
@@ -245,10 +263,13 @@ def elaborate(self, platform):
245263
246264class FIFOFormalCase (FHDLTestCase ):
247265 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 ],
252273 mode = "hybrid" , depth = fifo .depth * 2 + 1 )
253274
254275 def test_sync_pot (self ):
@@ -272,11 +293,19 @@ def test_sync_buffered_one(self):
272293 def check_async_fifo (self , fifo ):
273294 # TODO: properly doing model equivalence checking on this likely requires multiclock,
274295 # 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+ # ],
276302 # 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 )
280309
281310 def test_async (self ):
282311 self .check_async_fifo (AsyncFIFO (width = 8 , depth = 4 ))
0 commit comments