@@ -77,7 +77,7 @@ def elaborate(self, platform):
7777 return m
7878
7979
80- def _make_oereg (m , domain , oe , q ):
80+ def _make_oereg_ecp5_machxo2 (m , domain , oe , q ):
8181 for bit in range (len (q )):
8282 m .submodules [f"oe_ff{ bit } " ] = Instance ("OFS1P3DX" ,
8383 i_SCLK = ClockSignal (domain ),
@@ -88,7 +88,18 @@ def _make_oereg(m, domain, oe, q):
8888 )
8989
9090
91- class FFBuffer (io .FFBuffer ):
91+ def _make_oereg_nexus (m , domain , oe , q ):
92+ for bit in range (len (q )):
93+ m .submodules [f"oe_ff{ bit } " ] = Instance ("OFD1P3DX" ,
94+ i_CK = ClockSignal (domain ),
95+ i_SP = Const (1 ),
96+ i_CD = Const (0 ),
97+ i_D = oe ,
98+ o_Q = q [bit ],
99+ )
100+
101+
102+ class FFBufferECP5 (io .FFBuffer ):
92103 def elaborate (self , platform ):
93104 m = Module ()
94105
@@ -118,7 +129,42 @@ def elaborate(self, platform):
118129 i_D = o_inv [bit ],
119130 o_Q = buf .o [bit ],
120131 )
121- _make_oereg (m , self .o_domain , ~ self .oe , buf .t )
132+ _make_oereg_ecp5_machxo2 (m , self .o_domain , ~ self .oe , buf .t )
133+
134+ return m
135+
136+
137+ class FFBufferNexus (io .FFBuffer ):
138+ def elaborate (self , platform ):
139+ m = Module ()
140+
141+ m .submodules .buf = buf = InnerBuffer (self .direction , self .port )
142+ inv_mask = sum (inv << bit for bit , inv in enumerate (self .port .invert ))
143+
144+ if self .direction is not io .Direction .Output :
145+ i_inv = Signal .like (self .i )
146+ for bit in range (len (self .port )):
147+ m .submodules [f"i_ff{ bit } " ] = Instance ("IFD1P3DX" ,
148+ i_CK = ClockSignal (self .i_domain ),
149+ i_SP = Const (1 ),
150+ i_CD = Const (0 ),
151+ i_D = buf .i [bit ],
152+ o_Q = i_inv [bit ],
153+ )
154+ m .d .comb += self .i .eq (i_inv ^ inv_mask )
155+
156+ if self .direction is not io .Direction .Input :
157+ o_inv = Signal .like (self .o )
158+ m .d .comb += o_inv .eq (self .o ^ inv_mask )
159+ for bit in range (len (self .port )):
160+ m .submodules [f"o_ff{ bit } " ] = Instance ("OFD1P3DX" ,
161+ i_CK = ClockSignal (self .o_domain ),
162+ i_SP = Const (1 ),
163+ i_CD = Const (0 ),
164+ i_D = o_inv [bit ],
165+ o_Q = buf .o [bit ],
166+ )
167+ _make_oereg_nexus (m , self .o_domain , ~ self .oe , buf .t )
122168
123169 return m
124170
@@ -159,7 +205,7 @@ def elaborate(self, platform):
159205 i_D1 = o1_inv [bit ],
160206 o_Q = buf .o [bit ],
161207 )
162- _make_oereg (m , self .o_domain , ~ self .oe , buf .t )
208+ _make_oereg_ecp5_machxo2 (m , self .o_domain , ~ self .oe , buf .t )
163209
164210 return m
165211
@@ -200,7 +246,7 @@ def elaborate(self, platform):
200246 i_D1 = o1_inv [bit ],
201247 o_Q = buf .o [bit ],
202248 )
203- _make_oereg (m , self .o_domain , ~ self .oe , buf .t )
249+ _make_oereg_ecp5_machxo2 (m , self .o_domain , ~ self .oe , buf .t )
204250
205251 return m
206252
@@ -241,7 +287,7 @@ def elaborate(self, platform):
241287 i_D1 = o1_inv [bit ],
242288 o_Q = buf .o [bit ],
243289 )
244- _make_oereg (m , self .o_domain , ~ self .oe , buf .t )
290+ _make_oereg_nexus (m , self .o_domain , ~ self .oe , buf .t )
245291
246292 return m
247293
@@ -951,7 +997,12 @@ def get_io_buffer(self, buffer):
951997 if isinstance (buffer , io .Buffer ):
952998 result = IOBuffer (buffer .direction , buffer .port )
953999 elif isinstance (buffer , io .FFBuffer ):
954- result = FFBuffer (buffer .direction , buffer .port )
1000+ if self .family in ("ecp5" , "machxo2" ):
1001+ result = FFBufferECP5 (buffer .direction , buffer .port )
1002+ elif self .family == "nexus" :
1003+ result = FFBufferNexus (buffer .direction , buffer .port )
1004+ else :
1005+ raise NotImplementedError # :nocov:
9551006 elif isinstance (buffer , io .DDRBuffer ):
9561007 if self .family == "ecp5" :
9571008 result = DDRBufferECP5 (buffer .direction , buffer .port )
0 commit comments