1
1
from collections import OrderedDict
2
2
3
- from ..hdl . _ast import *
4
- from ..lib . io import *
5
- from ..lib import wiring
3
+ from ..hdl import *
4
+ from ..hdl . _ast import SignalDict
5
+ from ..lib import wiring , io
6
6
7
7
from .dsl import *
8
8
@@ -24,6 +24,78 @@ def __init__(self, name, attrs):
24
24
self .attrs = attrs
25
25
26
26
27
+ class PinBuffer (Elaboratable ):
28
+ def __init__ (self , pin , port ):
29
+ if pin .xdr not in (0 , 1 , 2 ):
30
+ raise ValueError (f"Unsupported 'xdr' value { pin .xdr } " )
31
+ self .pin = pin
32
+ self .port = port
33
+
34
+ def elaborate (self , platform ):
35
+ m = Module ()
36
+
37
+ if self .pin .dir == "i" :
38
+ if self .pin .xdr == 0 :
39
+ m .submodules .buf = buf = io .Buffer (io .Direction .Input , self .port )
40
+ m .d .comb += self .pin .i .eq (buf .i )
41
+ elif self .pin .xdr == 1 :
42
+ m .domains .input = cd_input = ClockDomain (reset_less = True )
43
+ m .submodules .buf = buf = io .FFBuffer (io .Direction .Input , self .port , i_domain = "input" )
44
+ m .d .comb += self .pin .i .eq (buf .i )
45
+ m .d .comb += cd_input .clk .eq (self .pin .i_clk )
46
+ elif self .pin .xdr == 2 :
47
+ m .domains .input = cd_input = ClockDomain (reset_less = True )
48
+ m .submodules .buf = buf = io .DDRBuffer (io .Direction .Input , self .port , i_domain = "input" )
49
+ m .d .comb += self .pin .i0 .eq (buf .i [0 ])
50
+ m .d .comb += self .pin .i1 .eq (buf .i [1 ])
51
+ m .d .comb += cd_input .clk .eq (self .pin .i_clk )
52
+ if self .pin .dir in ("o" , "oe" ):
53
+ if self .pin .xdr == 0 :
54
+ m .submodules .buf = buf = io .Buffer (io .Direction .Output , self .port )
55
+ m .d .comb += buf .o .eq (self .pin .o )
56
+ elif self .pin .xdr == 1 :
57
+ m .domains .output = cd_output = ClockDomain (reset_less = True )
58
+ m .submodules .buf = buf = io .FFBuffer (io .Direction .Output , self .port , o_domain = "output" )
59
+ m .d .comb += buf .o .eq (self .pin .o )
60
+ m .d .comb += cd_output .clk .eq (self .pin .o_clk )
61
+ elif self .pin .xdr == 2 :
62
+ m .domains .output = cd_output = ClockDomain (reset_less = True )
63
+ m .submodules .buf = buf = io .DDRBuffer (io .Direction .Output , self .port , o_domain = "output" )
64
+ m .d .comb += buf .o [0 ].eq (self .pin .o0 )
65
+ m .d .comb += buf .o [1 ].eq (self .pin .o1 )
66
+ m .d .comb += cd_output .clk .eq (self .pin .o_clk )
67
+ if self .pin .dir == "oe" :
68
+ m .d .comb += buf .oe .eq (self .pin .oe )
69
+ if self .pin .dir == "io" :
70
+ if self .pin .xdr == 0 :
71
+ m .submodules .buf = buf = io .Buffer (io .Direction .Bidir , self .port )
72
+ m .d .comb += self .pin .i .eq (buf .i )
73
+ m .d .comb += buf .o .eq (self .pin .o )
74
+ m .d .comb += buf .oe .eq (self .pin .oe )
75
+ elif self .pin .xdr == 1 :
76
+ m .domains .input = cd_input = ClockDomain (reset_less = True )
77
+ m .domains .output = cd_output = ClockDomain (reset_less = True )
78
+ m .submodules .buf = buf = io .FFBuffer (io .Direction .Bidir , self .port , i_domain = "input" , o_domain = "output" )
79
+ m .d .comb += self .pin .i .eq (buf .i )
80
+ m .d .comb += buf .o .eq (self .pin .o )
81
+ m .d .comb += buf .oe .eq (self .pin .oe )
82
+ m .d .comb += cd_input .clk .eq (self .pin .i_clk )
83
+ m .d .comb += cd_output .clk .eq (self .pin .o_clk )
84
+ elif self .pin .xdr == 2 :
85
+ m .domains .input = cd_input = ClockDomain (reset_less = True )
86
+ m .domains .output = cd_output = ClockDomain (reset_less = True )
87
+ m .submodules .buf = buf = io .DDRBuffer (io .Direction .Bidir , self .port , i_domain = "input" , o_domain = "output" )
88
+ m .d .comb += self .pin .i0 .eq (buf .i [0 ])
89
+ m .d .comb += self .pin .i1 .eq (buf .i [1 ])
90
+ m .d .comb += buf .o [0 ].eq (self .pin .o0 )
91
+ m .d .comb += buf .o [1 ].eq (self .pin .o1 )
92
+ m .d .comb += buf .oe .eq (self .pin .oe )
93
+ m .d .comb += cd_input .clk .eq (self .pin .i_clk )
94
+ m .d .comb += cd_output .clk .eq (self .pin .o_clk )
95
+
96
+ return m
97
+
98
+
27
99
class ResourceManager :
28
100
def __init__ (self , resources , connectors ):
29
101
self .resources = OrderedDict ()
@@ -33,8 +105,11 @@ def __init__(self, resources, connectors):
33
105
self .connectors = OrderedDict ()
34
106
self ._conn_pins = OrderedDict ()
35
107
36
- # Constraint lists
108
+ # List of all IOPort instances created
37
109
self ._ports = []
110
+ # List of (pin, port, buffer) pairs for non-dir="-" requests.
111
+ self ._pins = []
112
+ # Constraint list
38
113
self ._clocks = SignalDict ()
39
114
40
115
self .add_resources (resources )
@@ -139,11 +214,12 @@ def resolve(resource, dir, xdr, path, attrs):
139
214
direction = phys .dir
140
215
if isinstance (phys , Pins ):
141
216
phys_names = phys .map_names (self ._conn_pins , resource )
142
- io = IOPort (len (phys ), name = "__" .join (path ) + "__io" , metadata = [
217
+ iop = IOPort (len (phys ), name = "__" .join (path ) + "__io" , metadata = [
143
218
PortMetadata (name , attrs )
144
219
for name in phys_names
145
220
])
146
- port = SingleEndedPort (io , invert = phys .invert , direction = direction )
221
+ self ._ports .append (iop )
222
+ port = io .SingleEndedPort (iop , invert = phys .invert , direction = direction )
147
223
if isinstance (phys , DiffPairs ):
148
224
phys_names_p = phys .p .map_names (self ._conn_pins , resource )
149
225
phys_names_n = phys .n .map_names (self ._conn_pins , resource )
@@ -156,11 +232,8 @@ def resolve(resource, dir, xdr, path, attrs):
156
232
PortMetadata (name , attrs )
157
233
for name in phys_names_n
158
234
])
159
- port = DifferentialPort (p , n , invert = phys .invert , direction = direction )
160
- if dir == "-" :
161
- pin = None
162
- else :
163
- pin = wiring .flipped (Pin (len (phys ), dir , xdr = xdr , path = path ))
235
+ self ._ports += [p , n ]
236
+ port = io .DifferentialPort (p , n , invert = phys .invert , direction = direction )
164
237
165
238
for phys_name in phys_names :
166
239
if phys_name in self ._phys_reqd :
@@ -171,12 +244,16 @@ def resolve(resource, dir, xdr, path, attrs):
171
244
"." .join (self ._phys_reqd [phys_name ])))
172
245
self ._phys_reqd [phys_name ] = path
173
246
174
- self ._ports .append ((resource , pin , port , attrs ))
175
-
176
- if pin is not None and resource .clock is not None :
177
- self .add_clock_constraint (pin .i , resource .clock .frequency )
247
+ if dir == "-" :
248
+ return port
249
+ else :
250
+ pin = wiring .flipped (io .Pin (len (phys ), dir , xdr = xdr , path = path ))
251
+ buffer = PinBuffer (pin , port )
252
+ self ._pins .append ((pin , port , buffer ))
178
253
179
- return pin if pin is not None else port
254
+ if resource .clock is not None :
255
+ self .add_clock_constraint (pin .i , resource .clock .frequency )
256
+ return pin
180
257
181
258
else :
182
259
assert False # :nocov:
@@ -188,56 +265,19 @@ def resolve(resource, dir, xdr, path, attrs):
188
265
self ._requested [resource .name , resource .number ] = value
189
266
return value
190
267
191
- def iter_single_ended_pins (self ):
192
- for res , pin , port , attrs in self ._ports :
193
- if pin is None :
194
- continue
195
- if isinstance (res .ios [0 ], Pins ):
196
- yield pin , port , attrs , res .ios [0 ].invert
197
-
198
- def iter_differential_pins (self ):
199
- for res , pin , port , attrs in self ._ports :
200
- if pin is None :
201
- continue
202
- if isinstance (res .ios [0 ], DiffPairs ):
203
- yield pin , port , attrs , res .ios [0 ].invert
204
-
205
- def should_skip_port_component (self , port , attrs , component ):
206
- return False
268
+ def iter_pins (self ):
269
+ yield from self ._pins
207
270
208
271
def iter_ports (self ):
209
- for res , pin , port , attrs in self ._ports :
210
- if isinstance (res .ios [0 ], Pins ):
211
- if not self .should_skip_port_component (port , attrs , "io" ):
212
- yield port .io
213
- elif isinstance (res .ios [0 ], DiffPairs ):
214
- if not self .should_skip_port_component (port , attrs , "p" ):
215
- yield port .p
216
- if not self .should_skip_port_component (port , attrs , "n" ):
217
- yield port .n
218
- else :
219
- assert False
220
-
221
- def iter_port_constraints (self ):
222
- for res , pin , port , attrs in self ._ports :
223
- if isinstance (res .ios [0 ], Pins ):
224
- if not self .should_skip_port_component (port , attrs , "io" ):
225
- yield port .io .name , res .ios [0 ].map_names (self ._conn_pins , res ), attrs
226
- elif isinstance (res .ios [0 ], DiffPairs ):
227
- if not self .should_skip_port_component (port , attrs , "p" ):
228
- yield port .p .name , res .ios [0 ].p .map_names (self ._conn_pins , res ), attrs
229
- if not self .should_skip_port_component (port , attrs , "n" ):
230
- yield port .n .name , res .ios [0 ].n .map_names (self ._conn_pins , res ), attrs
231
- else :
232
- assert False
272
+ yield from self ._ports
233
273
234
274
def iter_port_constraints_bits (self ):
235
- for port_name , pin_names , attrs in self .iter_port_constraints () :
236
- if len (pin_names ) == 1 :
237
- yield port_name , pin_names [0 ], attrs
275
+ for port in self ._ports :
276
+ if len (port ) == 1 :
277
+ yield port . name , port . metadata [0 ]. name , port . metadata [ 0 ]. attrs
238
278
else :
239
- for bit , pin_name in enumerate (pin_names ):
240
- yield f"{ port_name } [{ bit } ]" , pin_name , attrs
279
+ for bit , meta in enumerate (port . metadata ):
280
+ yield f"{ port . name } [{ bit } ]" , meta . name , meta . attrs
241
281
242
282
def add_clock_constraint (self , clock , frequency ):
243
283
if isinstance (clock , ClockSignal ):
@@ -267,11 +307,11 @@ def iter_clock_constraints(self):
267
307
# Constraints on nets with no corresponding input pin (e.g. PLL or SERDES outputs) are not
268
308
# affected.
269
309
pin_i_to_port = SignalDict ()
270
- for res , pin , port , attrs in self ._ports :
310
+ for pin , port , _fragment in self ._pins :
271
311
if hasattr (pin , "i" ):
272
- if isinstance (res . ios [ 0 ], Pins ):
312
+ if isinstance (port , io . SingleEndedPort ):
273
313
pin_i_to_port [pin .i ] = port .io
274
- elif isinstance (res . ios [ 0 ], DiffPairs ):
314
+ elif isinstance (port , io . DifferentialPort ):
275
315
pin_i_to_port [pin .i ] = port .p
276
316
else :
277
317
assert False
0 commit comments