5
5
"""
6
6
7
7
from __future__ import print_function , unicode_literals
8
+ from re import I
8
9
9
10
from .core import working_block , set_working_block , _get_debug_mode , LogicNet , PostSynthBlock
10
11
from .helperfuncs import _NetCount
@@ -351,11 +352,14 @@ def _remove_unused_wires(block, keep_inputs=True):
351
352
#
352
353
353
354
354
- def synthesize (update_working_block = True , block = None ):
355
+ def synthesize (update_working_block = True , merge_io_vectors = True , block = None ):
355
356
""" Lower the design to just single-bit "and", "or", "xor", and "not" gates.
356
357
357
- :param update_working_block: Boolean specifying if working block update
358
- :param block: The block you want to synthesize
358
+ :param update_working_block: Boolean specifying if working block should
359
+ be set to the newly synthesized block.
360
+ :param merge_io_wirevectors: if False, turn all N-bit IO wirevectors
361
+ into N 1-bit IO wirevectors (i.e. don't maintain interface).
362
+ :param block: The block you want to synthesize.
359
363
:return: The newly synthesized block (of type PostSynthesisBlock).
360
364
361
365
Takes as input a block (default to working block) and creates a new
@@ -368,7 +372,10 @@ def synthesize(update_working_block=True, block=None):
368
372
the individual bits and memories (read and write ports) which
369
373
require the reassembly and disassembly of the wirevectors immediately
370
374
before and after. These are the only two places where 'c' and 's' ops
371
- should exist.
375
+ should exist. If merge_io_vectors is False, then these individual
376
+ bits are not reassembled and disassembled before and after, and so no
377
+ 'c' and 's' ops will exist. Instead, they will be named <name>[n],
378
+ where n is the bit number of original wire to which it corresponds.
372
379
373
380
The block that results from synthesis is actually of type
374
381
"PostSynthesisBlock" which contains a mapping from the original inputs
@@ -384,7 +391,9 @@ def synthesize(update_working_block=True, block=None):
384
391
385
392
block_out = PostSynthBlock ()
386
393
# resulting block should only have one of a restricted set of net ops
387
- block_out .legal_ops = set ('~&|^nrwcsm@' )
394
+ block_out .legal_ops = set ('~&|^nrwm@' )
395
+ if merge_io_vectors :
396
+ block_out .legal_ops .update (set ('cs' ))
388
397
wirevector_map = {} # map from (vector,index) -> new_wire
389
398
390
399
with set_working_block (block_out , no_sanity_check = True ):
@@ -399,6 +408,11 @@ def synthesize(update_working_block=True, block=None):
399
408
('>' , _basic_gt )]:
400
409
net_transform (_replace_op (op , fun ), block_in )
401
410
411
+ # This is a map from the cloned io wirevector created in copy_block,
412
+ # to the original io wirevector found in block_pre. We use it to create
413
+ # the block_out.io_map that is returned to the user.
414
+ orig_io_map = {temp : orig for orig , temp in block_in .io_map .items ()}
415
+
402
416
# Next, create all of the new wires for the new block
403
417
# from the original wires and store them in the wirevector_map
404
418
# for reference.
@@ -409,21 +423,31 @@ def synthesize(update_working_block=True, block=None):
409
423
new_val = (wirevector .val >> i ) & 0x1
410
424
new_wirevector = Const (bitwidth = 1 , val = new_val )
411
425
elif isinstance (wirevector , (Input , Output )):
412
- new_wirevector = WireVector (name = "tmp_" + new_name , bitwidth = 1 )
426
+ if merge_io_vectors :
427
+ new_wirevector = WireVector (name = "tmp_" + new_name , bitwidth = 1 )
428
+ else :
429
+ # Creating N 1-bit io wires for a given single N-bit io wire.
430
+ new_name = wirevector .name
431
+ if len (wirevector ) > 1 :
432
+ new_name += '[' + str (i ) + ']'
433
+ new_wirevector = wirevector .__class__ (name = new_name , bitwidth = 1 )
434
+ block_out .io_map [orig_io_map [wirevector ]] = new_wirevector
413
435
else :
414
436
new_wirevector = wirevector .__class__ (name = new_name , bitwidth = 1 )
415
437
wirevector_map [(wirevector , i )] = new_wirevector
416
438
417
439
# Now connect up the inputs and outputs to maintain the interface
418
- for wirevector in block_in .wirevector_subset (Input ):
419
- input_vector = Input (name = wirevector .name , bitwidth = len (wirevector ))
420
- for i in range (len (wirevector )):
421
- wirevector_map [(wirevector , i )] <<= input_vector [i ]
422
- for wirevector in block_in .wirevector_subset (Output ):
423
- output_vector = Output (name = wirevector .name , bitwidth = len (wirevector ))
424
- output_bits = [wirevector_map [(wirevector , i )]
425
- for i in range (len (output_vector ))]
426
- output_vector <<= concat_list (output_bits )
440
+ if merge_io_vectors :
441
+ for wirevector in block_in .wirevector_subset (Input ):
442
+ input_vector = Input (name = wirevector .name , bitwidth = len (wirevector ))
443
+ for i in range (len (wirevector )):
444
+ wirevector_map [(wirevector , i )] <<= input_vector [i ]
445
+ block_out .io_map [orig_io_map [wirevector ]] = [input_vector ]
446
+ for wirevector in block_in .wirevector_subset (Output ):
447
+ output_vector = Output (name = wirevector .name , bitwidth = len (wirevector ))
448
+ output_bits = [wirevector_map [(wirevector , i )] for i in range (len (output_vector ))]
449
+ output_vector <<= concat_list (output_bits )
450
+ block_out .io_map [orig_io_map [wirevector ]] = [output_vector ]
427
451
428
452
# Now that we have all the wires built and mapped, walk all the blocks
429
453
# and map the logic to the equivalent set of primitives in the system
0 commit comments