Simple port modification

From Verific Design Automation FAQ
Revision as of 15:39, 8 November 2024 by Mohammad (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This example converts module with struct ports into flat ports.

from invio import *

set_preference("invio_insert_ports_with_newline", 1)
add_sv_file("test.sv")
analyze()
elaborate("top")

# Convert instance of the module with struct ports into flat ports 
mod = get_modules("child").first
for i in get_instances(mod):
    for p in i.portmaps:
        pin = p.pin
        if pin and pin.data_type.is_named_user_type:
                print(f'... Replacing portmap: {p.full_name}')
                portmap = ''
                for m in pin.data_type.members:
                    portmap = portmap + f'.{pin.base_name}_{m.base_name} ({p.connected.first.base_name}.{m.base_name})' + ', \n'
                rt = create_raw_text_object(ref=p)
                replace_orig_text_of_object(rt, portmap[:len(portmap)-3]) # trim off the last ', '
# You will need to write out the modification and relaod to see the effect of text replacement in the parse tree.

    
# Replace the assignment with raw text
a =  get_assigns(mod).first
new_assign = """assign out_bus_clk = in_bus_clk;
    assign out_bus_rst = in_bus_rst;
    assign out_bus_addr = in_bus_addr;
    assign out_bus_data = in_bus_data;
"""
print(f'... Replacing assignment: {a.full_name}')
replace_orig_text_of_object(a, new_assign)


# flatten the ports
new_ports = []
for p in get_ports(mod):
    p_type = p.data_type
    if (p_type.is_named_user_type):
        print(f'... Replacing port: {p.full_name}')
        # Create new ports for each memeber and add them to the module
        for m in p_type.members:
            portname = f"{p.base_name}_{m.base_name}"
            dims = []
            for d in m.dimensions:
                dims.append( (d.left_index, d.right_index) )
            # Create a port with the same attributes as struct memebers
            new_port = create_port(portname, p.direction, datatype_name=m.data_type_name, dimensions=dims);
            new_ports.append(new_port)

        # Delete the old struct port
        delete_object(p)

# Insert them into top module after removing the old ports
for p in new_ports:
    insert_into(p, mod)

# Write out the modifications
write_modified_file("test.sv", "test_mod.sv")
 

"test.sv"

typedef struct {
    logic clk;
    logic rst;
    logic [1:0] addr;
    int data;
} bus_t;

module child (
              input bus_t in_bus,
              output bus_t out_bus
              );

   assign out_bus = in_bus;
endmodule // child

module top #(WIDTH = 4)(
   input bus_t top_in_bus, 
   input [0:WIDTH-1] a,
   output [0:WIDTH-1] d,
   output bus_t top_out_bus
) ;

   child u_child (
                  .in_bus (top_in_bus),
                  .out_bus (top_out_bus)
                  );

endmodule
 

Testcase after modification, "test_mod.sv":

typedef struct {
    logic clk;
    logic rst;
    logic [1:0] addr;
    int data;
} bus_t;

module child (
input logic in_bus_clk,
input logic in_bus_rst,
input logic [1:0] in_bus_addr,
input int in_bus_data,
output logic out_bus_clk,
output logic out_bus_rst,
output logic [1:0] out_bus_addr,
output int out_bus_data              
              );

   assign out_bus_clk = in_bus_clk;
    assign out_bus_rst = in_bus_rst;
    assign out_bus_addr = in_bus_addr;
    assign out_bus_data = in_bus_data;

endmodule // child

module top #(WIDTH = 4)(
   input bus_t top_in_bus, 
   input [0:WIDTH-1] a,
   output [0:WIDTH-1] d,
   output bus_t top_out_bus
) ;

   child u_child (
                  .in_bus_clk (top_in_bus.clk), 
.in_bus_rst (top_in_bus.rst), 
.in_bus_addr (top_in_bus.addr), 
.in_bus_data (top_in_bus.data),
                  .out_bus_clk (top_out_bus.clk), 
.out_bus_rst (top_out_bus.rst), 
.out_bus_addr (top_out_bus.addr), 
.out_bus_data (top_out_bus.data)
                  );

endmodule