18
18
from .passes import two_way_concat , one_bit_selects
19
19
20
20
21
+ class Subcircuit :
22
+ """
23
+ This is a way to create and track per-module-instance wire names, so there
24
+ are not name clashes when we instantiate a module more than once.
25
+ """
26
+
27
+ def __init__ (self , model , is_top = False , clk_set = {'clk' }, block = None ):
28
+ self .model = model
29
+ self .is_top = is_top
30
+ self .clk_set = clk_set
31
+ self .block = working_block (block )
32
+ self .inputs = {}
33
+ self .outputs = {}
34
+ self .wirevector_by_name = {}
35
+
36
+ def add_input (self , original_name , wire ):
37
+ self .inputs [original_name ] = wire
38
+ self .wirevector_by_name [original_name ] = wire
39
+
40
+ def add_output (self , original_name , wire ):
41
+ self .outputs [original_name ] = wire
42
+ self .wirevector_by_name [original_name ] = wire
43
+
44
+ def add_reg (self , original_name , wire ):
45
+ self .wirevector_by_name [original_name ] = wire
46
+
47
+ def add_clock (self , clock_name ):
48
+ self .clk_set .add (clock_name )
49
+
50
+ def twire (self , x ):
51
+ """ Find or make wire named x and return it. """
52
+ s = self .wirevector_by_name .get (x )
53
+ if s is None :
54
+ # Purposefully *not* setting its name to 'x', so we don't have name clashes
55
+ s = WireVector (bitwidth = 1 )
56
+ self .wirevector_by_name [x ] = s
57
+ return s
58
+
21
59
# -----------------------------------------------------------------
22
60
# __ ___
23
61
# | |\ | |__) | | |
24
62
# | | \| | \__/ |
25
63
26
64
27
- def input_from_blif (blif , block = None , merge_io_vectors = True , clock_name = 'clk' ):
65
+ def input_from_blif (blif , block = None , merge_io_vectors = True , clock_name = 'clk' , top_model = None ):
28
66
""" Read an open BLIF file or string as input, updating the block appropriately.
29
67
30
68
:param blif: An open BLIF file to read
@@ -33,6 +71,8 @@ def input_from_blif(blif, block=None, merge_io_vectors=True, clock_name='clk'):
33
71
by a indexing subscript (e.g. 1-bit wires 'a[0]' and 'a[1]') will be combined
34
72
into a single Input/Output (e.g. a 2-bit wire 'a').
35
73
:param clock_name: The name of the clock (defaults to 'clk')
74
+ :param top_model: name of top-level model to instantiate; if None, defaults to first model
75
+ listed in the BLIF
36
76
37
77
If merge_io_vectors is True, then given 1-bit Input wires 'a[0]' and 'a[1]', these
38
78
wires will be combined into a single 2-bit Input wire 'a' that can be accessed
@@ -67,29 +107,13 @@ def SKeyword(x):
67
107
def SLiteral (x ):
68
108
return Suppress (Literal (x ))
69
109
70
- def twire (x ):
71
- """ Find or make wire named x and return it. """
72
- s = block .get_wirevector_by_name (x )
73
- if s is None :
74
- s = WireVector (bitwidth = 1 , name = x )
75
- elif isinstance (s , Output ):
76
- # To allow an output wire to be used as an argument (legal in BLIF),
77
- # use the intermediate wire that was created in its place.
78
- # extract_outputs() creates this intermediate wire. Must check for
79
- # merge_io_vectors first!
80
- if not merge_io_vectors :
81
- s = block .get_wirevector_by_name (x + '_i' )
82
- elif len (s ) == 1 :
83
- s = block .get_wirevector_by_name (x + '[0]' )
84
- return s
85
-
86
110
# Begin BLIF language definition
87
- signal_start = pyparsing .alphas + r '$:[]_<>\ \\/?'
88
- signal_middle = pyparsing .alphas + pyparsing .nums + r '$:[]_<>\\\ /.?'
111
+ signal_start = pyparsing .alphas + '$:[]_<>\\ /?'
112
+ signal_middle = pyparsing .alphas + pyparsing .nums + '$:[]_<>\\ /.?- '
89
113
signal_id = Word (signal_start , signal_middle )
90
114
header = SKeyword ('.model' ) + signal_id ('model_name' )
91
- input_list = Group (SKeyword ('.inputs' ) + OneOrMore (signal_id ))('input_list' )
92
- output_list = Group (SKeyword ('.outputs' ) + OneOrMore (signal_id ))('output_list' )
115
+ input_list = Group (SKeyword ('.inputs' ) + ZeroOrMore (signal_id ))('input_list' )
116
+ output_list = Group (SKeyword ('.outputs' ) + ZeroOrMore (signal_id ))('output_list' )
93
117
94
118
cover_atom = Word ('01-' )
95
119
cover_list = Group (ZeroOrMore (cover_atom ))('cover_list' )
@@ -113,7 +137,15 @@ def twire(x):
113
137
+ SLiteral ('re' )
114
138
+ signal_id ('C' )
115
139
+ dffs_init_val ('I' ))('dffs_def' )
116
- command_def = name_def | dffas_def | dffs_def
140
+
141
+ # model reference
142
+ formal_actual = Group (signal_id ('formal' ) + SLiteral ('=' )
143
+ + signal_id ('actual' ))('formal_actual' )
144
+ formal_actual_list = Group (OneOrMore (formal_actual ))('formal_actual_list' )
145
+ model_name = signal_id ('model_name' )
146
+ model_ref = Group (SKeyword ('.subckt' ) + model_name + formal_actual_list )('model_ref' )
147
+
148
+ command_def = name_def | dffas_def | dffs_def | model_ref
117
149
command_list = Group (OneOrMore (command_def ))('command_list' )
118
150
119
151
footer = SKeyword ('.end' )
@@ -123,75 +155,115 @@ def twire(x):
123
155
124
156
# Begin actually reading and parsing the BLIF file
125
157
result = parser .parseString (blif_string , parseAll = True )
126
- # Blif file with multiple models (currently only handles one flattened models)
127
- assert (len (result ) == 1 )
128
- clk_set = set ([])
129
158
ff_clk_set = set ([])
130
-
131
- def extract_inputs (model ):
132
- start_names = [re .sub (r'\[([0-9]+)\]$' , '' , x ) for x in model ['input_list' ]]
133
- name_counts = collections .Counter (start_names )
134
- for input_name in name_counts :
135
- bitwidth = name_counts [input_name ]
136
- if input_name == clock_name :
137
- clk_set .add (input_name )
138
- elif bitwidth == 1 :
139
- block .add_wirevector (Input (bitwidth = 1 , name = input_name , block = block ))
140
- elif merge_io_vectors :
141
- wire_in = Input (bitwidth = bitwidth , name = input_name , block = block )
142
- for i in range (bitwidth ):
143
- bit_name = input_name + '[' + str (i ) + ']'
144
- bit_wire = WireVector (bitwidth = 1 , name = bit_name , block = block )
145
- bit_wire <<= wire_in [i ]
146
- else :
147
- for i in range (bitwidth ):
148
- bit_name = input_name + '[' + str (i ) + ']'
149
- block .add_wirevector (Input (bitwidth = 1 , name = bit_name , block = block ))
150
-
151
- def extract_outputs (model ):
152
- start_names = [re .sub (r'\[([0-9]+)\]$' , '' , x ) for x in model ['output_list' ]]
153
- name_counts = collections .Counter (start_names )
154
- for output_name in name_counts :
155
- bitwidth = name_counts [output_name ]
156
- # To allow an output wire to be used as an argument (legal in BLIF),
157
- # we need to create an intermediate wire, which will be used in twire()
158
- # whenever the original wire is referenced. For example, given 2-bit Output 'a',
159
- # every access to 'a[1]' will really be a reference to 'a[1]_i', a normal
160
- # WireVector connected to 'a[1]'. A key property is that the name by
161
- # which all other parts of the code refer to this wire doesn't change;
162
- # the only thing that changes is what underlying wire is used.
163
- if bitwidth == 1 :
164
- bit_internal = WireVector (bitwidth = 1 , name = output_name + '[0]' , block = block )
165
- bit_out = Output (bitwidth = 1 , name = output_name , block = block )
166
- bit_out <<= bit_internal
167
- elif merge_io_vectors :
168
- wire_out = Output (bitwidth = bitwidth , name = output_name , block = block )
169
- bit_list = []
170
- for i in range (bitwidth ):
171
- bit_name = output_name + '[' + str (i ) + ']'
172
- bit_wire = WireVector (bitwidth = 1 , name = bit_name , block = block )
173
- bit_list .append (bit_wire )
174
- wire_out <<= concat_list (bit_list )
175
- else :
176
- for i in range (bitwidth ):
177
- bit_name = output_name + '[' + str (i ) + ']'
178
- bit_internal = WireVector (bitwidth = 1 , name = bit_name + '_i' , block = block )
179
- bit_out = Output (bitwidth = 1 , name = bit_name , block = block )
159
+ models = {} # model name -> model, for subckt instantiation
160
+
161
+ def extract_inputs (subckt ):
162
+ if subckt .is_top :
163
+ # NOTE: Assumes that:
164
+ # - Top-level inputs starting with the same prefix are part of the same wire
165
+ # - Indices start at 0
166
+ start_names = [re .sub (r'\[([0-9]+)\]$' , '' , x ) for x in subckt .model ['input_list' ]]
167
+ name_counts = collections .Counter (start_names )
168
+ for input_name in name_counts :
169
+ bitwidth = name_counts [input_name ]
170
+ if input_name in subckt .clk_set :
171
+ continue
172
+ elif bitwidth == 1 :
173
+ wire_in = Input (bitwidth = 1 , name = input_name , block = block )
174
+ subckt .add_input (input_name , wire_in )
175
+ block .add_wirevector (wire_in )
176
+ elif merge_io_vectors :
177
+ wire_in = Input (bitwidth = bitwidth , name = input_name , block = block )
178
+ for i in range (bitwidth ):
179
+ bit_name = input_name + '[' + str (i ) + ']'
180
+ bit_wire = WireVector (bitwidth = 1 , block = block )
181
+ bit_wire <<= wire_in [i ]
182
+ subckt .add_input (bit_name , bit_wire )
183
+ else :
184
+ for i in range (bitwidth ):
185
+ bit_name = input_name + '[' + str (i ) + ']'
186
+ wire_in = Input (bitwidth = 1 , name = bit_name , block = block )
187
+ subckt .add_input (bit_name , wire_in )
188
+ block .add_wirevector (wire_in )
189
+ else :
190
+ # For subckts:
191
+ # - Never merge input vectors
192
+ # - All inputs are 1-bit
193
+ for input_name in subckt .model ['input_list' ]:
194
+ if input_name in subckt .clk_set :
195
+ continue
196
+ wire_in = WireVector (bitwidth = 1 , block = block ) # Internal name prevents name clash
197
+ subckt .add_input (input_name , wire_in )
198
+ block .add_wirevector (wire_in )
199
+
200
+ def extract_outputs (subckt ):
201
+ if subckt .is_top :
202
+ # NOTE: Assumes that:
203
+ # - Top-level outputs starting with the same prefix are part of the same wire
204
+ # - Indices start at 0
205
+ start_names = [re .sub (r'\[([0-9]+)\]$' , '' , x ) for x in subckt .model ['output_list' ]]
206
+ name_counts = collections .Counter (start_names )
207
+ for output_name in name_counts :
208
+ bitwidth = name_counts [output_name ]
209
+ # To allow an output wire to be used as an argument (legal in BLIF),
210
+ # we need to create an intermediate wire, which will be used in twire()
211
+ # whenever the original wire is referenced. For example, given 2-bit Output 'a',
212
+ # every access to 'a[1]' will really be a reference to 'a[1]_i', a normal
213
+ # WireVector connected to 'a[1]'. A key property is that the name by
214
+ # which all other parts of the code refer to this wire doesn't change;
215
+ # the only thing that changes is what underlying wire is used.
216
+ if bitwidth == 1 :
217
+ bit_internal = WireVector (bitwidth = 1 , block = block )
218
+ bit_out = Output (bitwidth = 1 , name = output_name , block = block )
180
219
bit_out <<= bit_internal
181
-
182
- def extract_commands (model ):
220
+ # NOTE this is important: redirecting user-visible name to internal wire
221
+ subckt .add_output (output_name , bit_internal )
222
+ elif merge_io_vectors :
223
+ wire_out = Output (bitwidth = bitwidth , name = output_name , block = block )
224
+ bit_list = []
225
+ for i in range (bitwidth ):
226
+ bit_name = output_name + '[' + str (i ) + ']'
227
+ bit_wire = WireVector (bitwidth = 1 , block = block )
228
+ bit_list .append (bit_wire )
229
+ subckt .add_output (bit_name , bit_wire )
230
+ wire_out <<= concat_list (bit_list )
231
+ else :
232
+ for i in range (bitwidth ):
233
+ bit_name = output_name + '[' + str (i ) + ']'
234
+ bit_internal = WireVector (bitwidth = 1 , block = block )
235
+ bit_out = Output (bitwidth = 1 , name = bit_name , block = block )
236
+ bit_out <<= bit_internal
237
+ # NOTE this is important: redirecting user-visible name to internal wire
238
+ subckt .add_output (bit_name , bit_internal )
239
+ else :
240
+ # For subckts:
241
+ # - Never merge outputs vectors
242
+ # - All outputs are 1-bit
243
+ for output_name in subckt .model ['output_list' ]:
244
+ bit_out = WireVector (bitwidth = 1 , block = block )
245
+ block .add_wirevector (bit_out )
246
+ subckt .add_output (output_name , bit_out )
247
+
248
+ def extract_commands (subckt ):
183
249
# for each "command" (dff or net) in the model
184
- for command in model ['command_list' ]:
250
+ for command in subckt . model ['command_list' ]:
185
251
# if it is a net (specified as a cover)
186
252
if command .getName () == 'name_def' :
187
- extract_cover (command )
253
+ extract_cover (subckt , command )
188
254
# else if the command is a d flop flop
189
255
elif command .getName () == 'dffas_def' or command .getName () == 'dffs_def' :
190
- extract_flop (command )
256
+ extract_flop (subckt , command )
257
+ elif command .getName () == 'model_ref' :
258
+ extract_model_reference (subckt , command )
191
259
else :
192
260
raise PyrtlError ('unknown command type' )
193
261
194
- def extract_cover (command ):
262
+ def extract_cover (subckt , command ):
263
+
264
+ def twire (w ):
265
+ return subckt .twire (w )
266
+
195
267
# pylint: disable=invalid-unary-operand-type
196
268
netio = command ['namesignal_list' ]
197
269
if len (command ['cover_list' ]) == 0 :
@@ -202,10 +274,10 @@ def extract_cover(command):
202
274
output_wire <<= Const (1 , bitwidth = 1 , block = block ) # const "TRUE"
203
275
elif command ['cover_list' ].asList () == ['1' , '1' ]:
204
276
# Populate clock list if one input is already a clock
205
- if (netio [1 ] in clk_set ):
206
- clk_set . add (netio [0 ])
207
- elif (netio [0 ] in clk_set ):
208
- clk_set . add (netio [1 ])
277
+ if (netio [1 ] in subckt . clk_set ):
278
+ subckt . add_clock (netio [0 ])
279
+ elif (netio [0 ] in subckt . clk_set ):
280
+ subckt . add_clock (netio [1 ])
209
281
else :
210
282
output_wire = twire (netio [1 ])
211
283
output_wire <<= twire (netio [0 ]) # simple wire
@@ -236,13 +308,18 @@ def extract_cover(command):
236
308
raise PyrtlError ('Blif file with unknown logic cover set "%s"'
237
309
'(currently gates are hard coded)' % command ['cover_list' ])
238
310
239
- def extract_flop (command ):
311
+ def extract_flop (subckt , command ):
312
+
313
+ def twire (w ):
314
+ return subckt .twire (w )
315
+
240
316
if (command ['C' ] not in ff_clk_set ):
241
317
ff_clk_set .add (command ['C' ])
242
318
243
319
# Create register and assign next state to D and output to Q
244
320
regname = command ['Q' ] + '_reg'
245
- flop = Register (bitwidth = 1 , name = regname )
321
+ flop = Register (bitwidth = 1 )
322
+ subckt .add_reg (regname , flop )
246
323
flop .next <<= twire (command ['D' ])
247
324
flop_output = twire (command ['Q' ])
248
325
init_val = command ['I' ]
@@ -255,10 +332,53 @@ def extract_flop(command):
255
332
"logic." )
256
333
flop_output <<= flop
257
334
335
+ def extract_model_reference (parent , command ):
336
+
337
+ def twire (w ):
338
+ return parent .twire (w )
339
+
340
+ def get_formal_connected_to_parent_clocks ():
341
+ clks = set ()
342
+ for fa in command ['formal_actual_list' ]:
343
+ if fa ['actual' ] in parent .clk_set :
344
+ clks .add (fa ['formal' ])
345
+ return clks
346
+ formal_clks = get_formal_connected_to_parent_clocks ()
347
+
348
+ subckt = Subcircuit (models [command ['model_name' ]], clk_set = formal_clks , block = block )
349
+ instantiate (subckt )
350
+ for fa in command ['formal_actual_list' ]:
351
+ formal = fa ['formal' ]
352
+ actual = fa ['actual' ]
353
+ if actual in parent .clk_set :
354
+ assert (formal in subckt .clk_set )
355
+ # We didn't create an input wire corresponding to this.
356
+ continue
357
+ elif formal in subckt .inputs :
358
+ wf = subckt .inputs [formal ]
359
+ wa = twire (actual )
360
+ wf <<= wa
361
+ elif formal in subckt .outputs :
362
+ wf = subckt .outputs [formal ]
363
+ wa = twire (actual )
364
+ wa <<= wf
365
+ else :
366
+ raise PyrtlError ("%s formal parameter is neither an input nor output of subckt %s"
367
+ % (formal , command ['model_name' ]))
368
+
369
+ def instantiate (subckt ):
370
+ extract_inputs (subckt )
371
+ extract_outputs (subckt )
372
+ extract_commands (subckt )
373
+
374
+ # Get all model definitions
258
375
for model in result :
259
- extract_inputs (model )
260
- extract_outputs (model )
261
- extract_commands (model )
376
+ if not top_model :
377
+ top_model = model ['model_name' ]
378
+ models [model ['model_name' ]] = model
379
+
380
+ top = Subcircuit (models [top_model ], is_top = True , clk_set = {clock_name }, block = block )
381
+ instantiate (top )
262
382
263
383
264
384
# ----------------------------------------------------------------
0 commit comments