@@ -272,7 +272,7 @@ def __init__(self, memid):
272
272
273
273
274
274
class ModuleEmitter :
275
- def __init__ (self , builder , netlist , module , name_map , empty_checker ):
275
+ def __init__ (self , builder , netlist : _nir . Netlist , module : _nir . Module , name_map , empty_checker ):
276
276
self .builder = builder
277
277
self .netlist = netlist
278
278
self .module = module
@@ -293,6 +293,7 @@ def __init__(self, builder, netlist, module, name_map, empty_checker):
293
293
self .sigport_wires = {} # signal or port name -> (wire, value)
294
294
self .driven_sigports = set () # set of signal or port name
295
295
self .nets = {} # net -> (wire name, bit idx)
296
+ self .ionets = {} # ionet -> (wire name, bit idx)
296
297
self .cell_wires = {} # cell idx -> wire name
297
298
self .instance_wires = {} # (cell idx, output name) -> wire name
298
299
@@ -302,6 +303,7 @@ def emit(self):
302
303
self .collect_init_attrs ()
303
304
self .emit_signal_wires ()
304
305
self .emit_port_wires ()
306
+ self .emit_io_port_wires ()
305
307
self .emit_cell_wires ()
306
308
self .emit_submodule_wires ()
307
309
self .emit_connects ()
@@ -406,11 +408,28 @@ def emit_port_wires(self):
406
408
self .sigport_wires [name ] = (wire , value )
407
409
if flow == _nir .ModuleNetFlow .Output :
408
410
continue
409
- # If we just emitted an input or inout port, it is driving the value.
411
+ # If we just emitted an input port, it is driving the value.
410
412
self .driven_sigports .add (name )
411
413
for bit , net in enumerate (value ):
412
414
self .nets [net ] = (wire , bit )
413
415
416
+ def emit_io_port_wires (self ):
417
+ for idx , (name , (value , dir )) in enumerate (self .module .io_ports .items ()):
418
+ port_id = idx + len (self .module .ports )
419
+ if self .module .parent is None :
420
+ port = self .netlist .io_ports [value [0 ].port ]
421
+ attrs = port .attrs
422
+ src_loc = port .src_loc
423
+ else :
424
+ attrs = {}
425
+ src_loc = None
426
+ wire = self .builder .wire (width = len (value ),
427
+ port_id = port_id , port_kind = dir .value ,
428
+ name = name , attrs = attrs ,
429
+ src = _src (src_loc ))
430
+ for bit , net in enumerate (value ):
431
+ self .ionets [net ] = (wire , bit )
432
+
414
433
def emit_driven_wire (self , value ):
415
434
# Emits a wire for a value, in preparation for driving it.
416
435
if value in self .value_names :
@@ -454,7 +473,9 @@ def emit_cell_wires(self):
454
473
elif isinstance (cell , _nir .Initial ):
455
474
width = 1
456
475
elif isinstance (cell , _nir .IOBuffer ):
457
- width = len (cell .pad )
476
+ if cell .dir is _nir .IODirection .Output :
477
+ continue # No outputs.
478
+ width = len (cell .port )
458
479
else :
459
480
assert False # :nocov:
460
481
# Single output cell connected to a wire.
@@ -503,6 +524,28 @@ def sigspec(self, *parts: '_nir.Net | Iterable[_nir.Net]'):
503
524
return chunks [0 ]
504
525
return "{ " + " " .join (reversed (chunks )) + " }"
505
526
527
+ def io_sigspec (self , value : _nir .IOValue ):
528
+ chunks = []
529
+ begin_pos = 0
530
+ while begin_pos < len (value ):
531
+ end_pos = begin_pos
532
+ wire , start_bit = self .ionets [value [begin_pos ]]
533
+ bit = start_bit
534
+ while (end_pos < len (value ) and
535
+ self .ionets [value [end_pos ]] == (wire , bit )):
536
+ end_pos += 1
537
+ bit += 1
538
+ width = end_pos - begin_pos
539
+ if width == 1 :
540
+ chunks .append (f"{ wire } [{ start_bit } ]" )
541
+ else :
542
+ chunks .append (f"{ wire } [{ start_bit + width - 1 } :{ start_bit } ]" )
543
+ begin_pos = end_pos
544
+
545
+ if len (chunks ) == 1 :
546
+ return chunks [0 ]
547
+ return "{ " + " " .join (reversed (chunks )) + " }"
548
+
506
549
def emit_connects (self ):
507
550
for name , (wire , value ) in self .sigport_wires .items ():
508
551
if name not in self .driven_sigports :
@@ -513,10 +556,13 @@ def emit_submodules(self):
513
556
submodule = self .netlist .modules [submodule_idx ]
514
557
if not self .empty_checker .is_empty (submodule_idx ):
515
558
dotted_name = "." .join (submodule .name )
516
- self .builder .cell (f"\\ { dotted_name } " , submodule .name [- 1 ], ports = {
517
- name : self .sigspec (value )
518
- for name , (value , _flow ) in submodule .ports .items ()
519
- }, src = _src (submodule .cell_src_loc ))
559
+ ports = {}
560
+ for name , (value , _flow ) in submodule .ports .items ():
561
+ ports [name ] = self .sigspec (value )
562
+ for name , (value , _dir ) in submodule .io_ports .items ():
563
+ ports [name ] = self .io_sigspec (value )
564
+ self .builder .cell (f"\\ { dotted_name } " , submodule .name [- 1 ], ports = ports ,
565
+ src = _src (submodule .cell_src_loc ))
520
566
521
567
def emit_assignment_list (self , cell_idx , cell ):
522
568
def emit_assignments (case , cond ):
@@ -761,14 +807,19 @@ def emit_flip_flop(self, cell_idx, cell):
761
807
self .builder .cell (cell_type , ports = ports , params = params , src = _src (cell .src_loc ))
762
808
763
809
def emit_io_buffer (self , cell_idx , cell ):
764
- self .builder .cell ("$tribuf" , ports = {
765
- "Y" : self .sigspec (cell .pad ),
766
- "A" : self .sigspec (cell .o ),
767
- "EN" : self .sigspec (cell .oe ),
768
- }, params = {
769
- "WIDTH" : len (cell .pad ),
770
- }, src = _src (cell .src_loc ))
771
- self .builder .connect (self .cell_wires [cell_idx ], self .sigspec (cell .pad ))
810
+ if cell .dir is not _nir .IODirection .Input :
811
+ if cell .dir is _nir .IODirection .Output and cell .oe == _nir .Net .from_const (1 ):
812
+ self .builder .connect (self .io_sigspec (cell .port ), self .sigspec (cell .o ))
813
+ else :
814
+ self .builder .cell ("$tribuf" , ports = {
815
+ "Y" : self .io_sigspec (cell .port ),
816
+ "A" : self .sigspec (cell .o ),
817
+ "EN" : self .sigspec (cell .oe ),
818
+ }, params = {
819
+ "WIDTH" : len (cell .port ),
820
+ }, src = _src (cell .src_loc ))
821
+ if cell .dir is not _nir .IODirection .Output :
822
+ self .builder .connect (self .cell_wires [cell_idx ], self .io_sigspec (cell .port ))
772
823
773
824
def emit_memory (self , cell_idx , cell ):
774
825
memory_info = self .memories [cell_idx ]
@@ -950,8 +1001,8 @@ def emit_instance(self, cell_idx, cell):
950
1001
ports [name ] = self .sigspec (nets )
951
1002
for name in cell .ports_o :
952
1003
ports [name ] = self .instance_wires [cell_idx , name ]
953
- for name , nets in cell .ports_io .items ():
954
- ports [name ] = self .sigspec ( nets )
1004
+ for name , ( ionets , _dir ) in cell .ports_io .items ():
1005
+ ports [name ] = self .io_sigspec ( ionets )
955
1006
self .builder .cell (f"\\ { cell .type } " , cell .name , ports = ports , params = cell .parameters ,
956
1007
attrs = cell .attributes , src = _src (cell .src_loc ))
957
1008
0 commit comments