11# amaranth: UnusedElaboratable=no
22
33# SPDX-License-Identifier: BSD-2-Clause
4+ import copy
45import logging
56import os
67import re
@@ -71,46 +72,50 @@ def elaborate(self, platform):
7172class SiliconPlatformPort (io .PortLike ):
7273 def __init__ (self ,
7374 name : str ,
74- port_desc : PortDesc ,
75- * ,
76- invert : bool = False ):
75+ port_desc : PortDesc ):
7776 self ._port_desc = port_desc
78- self ._invert = invert
77+ if 'invert' in port_desc .iomodel :
78+ if isinstance (port_desc .iomodel ['invert' ], bool ):
79+ self ._invert = [port_desc .iomodel ['invert' ]]* port_desc .iomodel ['width' ]
80+ else :
81+ self ._invert = port_desc .iomodel ['invert' ]
82+ else :
83+ self ._invert = [False ]* port_desc .iomodel ['width' ]
84+
7985 self ._name = name
8086
8187 # Initialize signal attributes to None
8288 self ._i = None
8389 self ._o = None
8490 self ._oe = None
91+ self ._ie = None
8592
8693 # Create signals based on direction
8794 if self .direction in (io .Direction .Input , io .Direction .Bidir ):
88- self ._i = Signal (self ._port_desc .width , name = f"{ self ._name } __i" )
95+ self ._i = Signal (self ._port_desc .width , name = f"{ self ._name } $i" )
96+ self ._ie = Signal (self ._port_desc .width , name = f"{ self ._name } $inp_dis" )
8997 if self .direction in (io .Direction .Output , io .Direction .Bidir ):
90- self ._o = Signal (self ._port_desc .width , name = f"{ self ._name } __o " )
91- if self . direction is io . Direction . Bidir :
92- # the signals that get wired out to iocells. Always one per io.
98+ self ._o = Signal (self ._port_desc .width , name = f"{ self ._name } $o " )
99+
100+ # the oe signals that get wired out to iocells. Always one per io.
93101 init_oe = - 1
94102 if 'init_oe' in port_desc .iomodel and port_desc .iomodel ['init_oe' ]:
95103 init_oe = port_desc .iomodel ['init_oe' ]
96- self ._oes = Signal (self ._port_desc .width , name = f"{ self ._name } __oe" , init = init_oe )
104+ self ._oes = Signal (self ._port_desc .width , name = f"{ self ._name } $oe" , init = init_oe )
105+
97106 # the oe on the user side.
98107 if "individual_oe" not in self .iomodel or not self .iomodel ["individual_oe" ]:
99- self ._oe = Signal (1 , name = f"{ self ._name } __oe " , init = - 1 )
108+ self ._oe = Signal (1 , name = f"{ self ._name } $oe " , init = - 1 )
100109 else :
101110 self ._oe = self ._oes
102111
103- elif self .direction is io .Direction .Output :
104- # Always create an _oe for output ports
105- self ._oe = Signal (1 , name = f"{ self ._name } __oe" , init = - 1 )
106-
107- logger .debug (f"Created SiliconPlatformPort { self ._name } , invert={ invert } with port description:\n { pformat (self ._port_desc )} " )
112+ logger .debug (f"Created SiliconPlatformPort { self ._name } , with port description:\n { pformat (self ._port_desc )} " )
108113
109114 def wire (self , m : Module , interface : PureInterface ):
110115 assert self .direction == interface .signature .direction #type: ignore
111116 if hasattr (interface , '_i' ):
112117 m .d .comb += interface .i .eq (self .i ) # type: ignore
113- for d in ['_o' , '_oe' ]:
118+ for d in ['_o' , '_oe' , '_ie' ]:
114119 if hasattr (interface , d ):
115120 m .d .comb += getattr (self , d ).eq (getattr (interface , d ))
116121 if self ._oe is not None \
@@ -122,12 +127,27 @@ def instantiate_toplevel(self):
122127 ports = []
123128 if self .direction in (io .Direction .Input , io .Direction .Bidir ):
124129 ports .append ((f"io${ self ._name } $i" , self .i , PortDirection .Input ))
130+ ports .append ((f"io${ self ._name } $ie" , self .ie , PortDirection .Output ))
125131 if self .direction in (io .Direction .Output , io .Direction .Bidir ):
126132 ports .append ((f"io${ self ._name } $o" , self .o , PortDirection .Output ))
127- if self .direction is io .Direction .Bidir :
128133 ports .append ((f"io${ self ._name } $oe" , self .oe , PortDirection .Output ))
129134 return ports
130135
136+ def wire_up (self , m , wire ):
137+ inv_mask = sum (inv << bit for bit , inv in enumerate (self .invert ))
138+ if hasattr (wire , 'i' ):
139+ m .d .comb += wire .i .eq (self .i ^ inv_mask )
140+ if hasattr (wire , 'o' ):
141+ m .d .comb += self .o .eq (wire .o ^ inv_mask )
142+ if hasattr (wire , 'oe' ):
143+ m .d .comb += self .oe .eq (wire .oe )
144+
145+ if hasattr (wire , 'ie' ):
146+ m .d .comb += self .ie .eq (wire .ie )
147+ elif hasattr (wire , 'oe' ):
148+ m .d .comb += self .ie .eq (wire .oe )
149+
150+
131151 @property
132152 def name (self ) -> str :
133153 return self ._name
@@ -162,6 +182,13 @@ def oe(self):
162182 "output enable signal" )
163183 return self ._oe
164184
185+ @property
186+ def ie (self ):
187+ if self ._ie is None :
188+ raise AttributeError ("SiliconPlatformPort with input direction does not have an "
189+ "input enable signal" )
190+ return self ._ie
191+
165192 @property
166193 def direction (self ):
167194 return self ._port_desc .iomodel ['direction' ]
@@ -189,14 +216,16 @@ def __getitem__(self, key):
189216 return NotImplemented
190217
191218 def __invert__ (self ):
192- result = SiliconPlatformPort (self ._name , self ._port_desc , invert = not self .invert )
219+ new_port_desc = copy .deepcopy (self ._port_desc )
220+ new_port_desc .iomodel ['invert' ] = tuple ([ not i for i in self .invert ])
221+ result = SiliconPlatformPort (self ._name , new_port_desc )
193222 return result
194223
195224 def __add__ (self , other ):
196225 return NotImplemented
197226
198227 def __repr__ (self ):
199- return (f"SiliconPlatformPort(name={ self ._name } , invert= { self . _invert } , iomode ={ self .iomodel } )" )
228+ return (f"SiliconPlatformPort(name={ self ._name } , iomodel ={ self .iomodel } )" )
200229
201230
202231class Sky130Port (SiliconPlatformPort ):
@@ -237,24 +266,22 @@ class Sky130Port(SiliconPlatformPort):
237266 # TODO: slew rate, hold points
238267 def __init__ (self ,
239268 name : str ,
240- port_desc : PortDesc ,
241- * ,
242- invert : bool = False ):
243- super ().__init__ (name , port_desc , invert = invert )
269+ port_desc : PortDesc ):
270+ super ().__init__ (name , port_desc )
244271
245272 # keep a list of signals we create
246273 self ._signals = []
247274
248- # Now create the signals for ``gpio_oeb`` (``oe_n``), ``gpio_inp_dis`` (``ie ``)
275+ # Now create the signals for ``gpio_oeb`` (``oe_n``), ``gpio_inp_dis`` (``ie_n ``)
249276 self ._oe_n = None
250- self ._ie = None
251277
252278 if self ._oe is not None :
253279 self ._oe_n = Signal (self ._oe .shape ().width , name = f"{ self ._name } $oeb" )
254280 self ._signals .append ((self ._oe_n , PortDirection .Output ))
255- if self ._i is not None :
256- self ._ie = Signal (self ._i .shape ().width , name = f"{ self ._name } $inp_dis" )
257- self ._signals .append ((self ._ie , PortDirection .Output ))
281+
282+ if self ._ie is not None :
283+ self ._ie_n = Signal (self ._ie .shape ().width , name = f"{ self ._name } $inp_dis" )
284+ self ._signals .append ((self ._ie_n , PortDirection .Output ))
258285
259286 # Port Configuration
260287 # Input voltage trip level
@@ -303,13 +330,7 @@ def __init__(self,
303330
304331 def wire (self , m : Module , interface : PureInterface ):
305332 super ().wire (m , interface )
306- # don't wire up oe_n
307- if hasattr (interface , 'ie' ):
308- m .d .comb += interface .ie .eq (self ._ie ) # type: ignore
309- # wire up oe_n = ~oe
310- if self ._oe is not None :
311- assert self ._oe_n is not None
312- m .d .comb += self ._oe_n .eq (~ self ._oe )
333+
313334 # wire up drive mode bits
314335 bit = 0
315336 for i in self ._dms :
@@ -325,12 +346,19 @@ def instantiate_toplevel(self):
325346 ports .append ((f"io${ s .name } " , s , d ))
326347 return ports
327348
328- @property
329- def ie (self ):
330- if self ._ie is None :
331- raise AttributeError ("SiliconPlatformPort with input direction does not have an "
332- "input enable signal" )
333- return self ._ie
349+ def wire_up (self , m , wire ):
350+ super ().wire_up (m , wire )
351+ # wire up oe_n = ~oe
352+ if self ._oe is not None :
353+ assert self ._oe_n is not None
354+ m .d .comb += self ._oe_n .eq (~ self ._oe )
355+
356+ if self ._ie is not None :
357+ assert self ._ie_n is not None
358+ m .d .comb += self ._ie_n .eq (~ self ._ie )
359+
360+ if hasattr (wire , 'drive_mode' ):
361+ m .d .comb += self .drive_mode .eq (wire .drive_mode )
334362
335363 @property
336364 def drive_mode (self ):
@@ -342,11 +370,13 @@ def drive_mode(self):
342370 #TODO: trip selection
343371
344372 def __invert__ (self ):
345- result = Sky130Port (self ._name , self ._port_desc , invert = not self .invert )
373+ new_port_desc = copy .deepcopy (self ._port_desc )
374+ new_port_desc .iomodel ['invert' ] = tuple ([ not i for i in self .invert ])
375+ result = SiliconPlatformPort (self ._name , new_port_desc )
346376 return result
347377
348378 def __repr__ (self ):
349- return (f"Sky130Port(name={ self ._name } , invert= { self . _invert } , iomode ={ self .iomodel } )" )
379+ return (f"Sky130Port(name={ self ._name } , iomodel ={ self .iomodel } )" )
350380
351381
352382
@@ -368,18 +398,17 @@ def elaborate(self, platform):
368398 raise TypeError (f"Cannot elaborate SiliconPlatform buffer with port { self .port !r} " )
369399
370400 m = Module ()
371-
401+ invert = sum ( bit << idx for idx , bit in enumerate ( self . port . invert ))
372402 if self .direction is not io .Direction .Input :
373- if self . port . invert :
403+ if invert != 0 :
374404 o_inv = Signal .like (self .o )
375- m .d .comb += o_inv .eq (~ self .o )
405+ m .d .comb += o_inv .eq (self .o ^ invert )
376406 else :
377407 o_inv = self .o
378-
379408 if self .direction is not io .Direction .Output :
380- if self . port . invert :
409+ if invert :
381410 i_inv = Signal .like (self .i )
382- m .d .comb += self .i .eq (~ i_inv )
411+ m .d .comb += self .i .eq (i_inv ^ invert )
383412 else :
384413 i_inv = self .i
385414
0 commit comments