def make_arbiter(name, base_dir, masters, slave=None):
    """Arbiter module generation.
    
    The arbiter module is used to generate all the necessary logic glue to
    allow multi-masters to got access to a bus or a slave.
    
        @param name: arbiter module name
        @param base_dir: destination directory
        @param masters: master interfaces signals
        @param slave: slave interface signals
        @return: vhdl.Entity instance from Arbiter module.
        
        master[0] = InstanceInterface object
        master[1] = {'signal_name' : 'signal attached'}
    """
    base_name = ("arbiter_%s" % name)
    filename = path.join(base_dir, ("%s.vhd" % base_name))

    try:
        vhdl_fd = open(filename, "w")
    except IOError:
        raise ArbiterError("Can't create %s.vhd file." % base_name)

    vhdl_fd.write(make_header("Wishbone Round-Robin arbiter module", 
                                base_name))
    
    # 1. Building Entity declaration
    entity = "entity %s is\n" % base_name
    entity += "  port (\n"
    entity += "    -- Global signals\n"
    entity += "    clk : in std_logic;\n"
    entity += "    reset : in std_logic;\n\n"
    

    entity += "\n  );"
    entity += "\nend entity;\n"

    vhdl_fd.write(entity)

    # 2. Starting Architecture declaration
    vhdl_fd.write(_VHDL_ARCHITECTURE % (base_name))

    # 3. Adding local signals
    vhdl_fd.write(to_comment(['Signals declaration']))
    
    vhdl_fd.write("begin\n")
     
    
    # 7. Closing module
    vhdl_fd.write("end architecture;\n")
    vhdl_fd.close()
    
    # 8. Create vhdl.Entity object
    entity = Entity(StringIO(entity))
    instance = Instance(entity, base_name)
    
    # 9. Adding signals interconnection
    
    # 10. Returning instance
    return instance, ("%s.vhd" % base_name)
def make_intercon(name, base_dir, master, slaves):
    """Intercon module generation.
    
    The intercon module is used to generate all the necessary logic glue to
    allow master interface to communicate with each slave.
    
        @param name: intercon module name
        @param base_dir: destination directory
        @param masters: master interfaces signals
        @param slaves: slave interfaces signals
        @return: vhdl.Entity instance from Intercom module.
        
        master[0] = InstanceInterface object
        master[1] = {'signal_name' : 'signal attached'}
    """
    base_name = ("intercon_%s" % name)
    filename = path.join(base_dir, ("%s.vhd" % base_name))

    # Generate master bytes selection signals list
    _, sel_width = master.wb_signal_width("SEL")
    byte_width = master.data_width // 8

    master_sel = [ mk_sel_bit(master, idx, sel_width, byte_width)
                    for idx in range(byte_width)
                 ]
    
    try:
        vhdl_fd = open(filename, "w")
    except IOError:
        raise InterconError("Can't create %s.vhd file." % base_name)

    vhdl_fd.write(make_header("Wishbone address decoder module", base_name))
    
    # 1. Building Entity declaration
    entity = "entity %s is\n" % base_name
    entity += "  port (\n"
    #entity += "    -- Global signals\n"
    #entity += "    clk : in std_logic;\n"
    #entity += "    reset : in std_logic;\n\n"
    
    entity += "    -- Master signals\n"
    
    # for signal in master.
    entity_ports =  dict(port_matrix(master, signal, "wbs_master") 
                            for _, signal in master.signals.iteritems()
                            )
    ports = ["    %s : %s" % (key, value[0]) 
                for key, value in entity_ports.iteritems()
            ]
    entity += ";\n".join(ports)

    slaves_max_width = 8
    for slave in slaves:
        entity += ";\n\n    -- Slave %s.%s signals\n" % (slave.instance_name,
                                                         slave.name)
        
        if slave.data_width > slaves_max_width:
            slaves_max_width = slave.data_width 
        # for signal out slave.

        slave_ports =  dict(port_matrix(slave, signal) 
                                for _, signal in slave.signals.iteritems()
                                )
        entity_ports.update(slave_ports)
        entity += ";\n".join(["    %s : %s" % (key, value[0]) 
                              for key, value in slave_ports.iteritems()
                              ])

    entity += "\n  );"
    entity += "\nend entity;\n"

    vhdl_fd.write(entity)

    # 2. Starting Architecture declaration
    vhdl_fd.write(_VHDL_ARCHITECTURE % (base_name))

    slaves_max_width //= 8
    slaves_max_sel = 0
    while 2**slaves_max_sel < slaves_max_width:
        slaves_max_sel += 1
    
    master_sels = [mk_sel_array(master, master_sel, 2**idx) 
                        for idx in range(slaves_max_sel+1)]
    
    if(len(slaves) > 1):
        slave_cnx = [InterconRegisterIface(slave, master, 
                                           "slave_sel(%d)"%idx,
                                           master_sels)
                        for idx, slave in enumerate(slaves)
                    ]
    else:
        slave_cnx = [InterconRegisterIface(slaves[0], master, 
                                           "slave_sel",
                                           master_sels)
                    ]

    # 3. Adding local signals
    vhdl_fd.write(to_comment(['Signals declaration']))
    if(len(slaves) > 1):
        vhdl_fd.write("  signal slave_sel : std_logic_vector(%u downto 0);\n" % 
                      (len(slaves) - 1))
    else:
        vhdl_fd.write("  signal slave_sel : std_logic;\n") 

    # 3.1 Adding bytes selection signals
    for idx, sels in enumerate(master_sels):
        (_, signals) = sels
        if len(signals) == 1:
            vhdl_fd.write("  signal master_sel%u : std_logic;\n" % (8 * (2 ** idx)))
        else:
            vhdl_fd.write("  signal master_sel%u : std_logic_vector(%d downto 0);\n" % 
                          (8 * (2 ** idx),  len(signals) - 1))
    
    vhdl_fd.write("\nbegin\n")
     
    # 4. Building address decoders
    vhdl_fd.write(to_comment(['Byte selection signals']))
    for idx, sels in enumerate(master_sels):
        def _to_signal(sig):
            if sig == None:
                return "'1'"
            else:
                return sig
            
        (_, signals) = sels
        if len(signals) == 1:
            vhdl_fd.write("  master_sel%u <= %s;\n" % 
                          (8 * (2 ** idx), _to_signal(signals[0])))
        else:
            vhdl = ["  master_sel%u(%u) <= %s;\n" % 
                          (8 * (2 ** idx), idx2, _to_signal(signals[idx2]))
                          for idx2 in range(len(signals))]
            vhdl_fd.write("".join(vhdl))

    # 4. Building address decoders
    vhdl_fd.write(to_comment(['Address decoders']))
    vhdl = [slave.addr_sel for slave in slave_cnx]
    vhdl_fd.write("  %s;\n" % ";\n  ".join(vhdl))

    vhdl = [slave.addr for slave in slave_cnx]
    vhdl_fd.write("  %s;\n" % ";\n  ".join(vhdl))
    
    # 5. Building acknowledge signal
    vhdl_fd.write(to_comment(['Control signals']))
    vhdl = [slave.ack for slave in slave_cnx]
    vhdl.append("'0'")
    vhdl_fd.write("  wbs_master_ack_o <= %s;\n" % 
                  "\n                      else ".join(vhdl))

    vhdl = ["  %s;\n" % ";\n  ".join(slave.control) for slave in slave_cnx]
    vhdl_fd.write("\n".join(vhdl))
    
    # 6. Building datapath
    vhdl_fd.write(to_comment(['Datapath wrapping']))
    vhdl = [slave.byte_sel for slave in slave_cnx if slave.byte_ok]
    if len(vhdl):
        vhdl_fd.write("  %s;\n" % ";\n  ".join(vhdl))

    vhdl = [slave.writedata for slave in slave_cnx if slave.writedata_ok]
    if len(vhdl):
        vhdl_fd.write("  %s;\n" % ";\n  ".join(vhdl))

    if master.has_signal("dat", True):
        for idx in range(byte_width):
            vhdl = [slave.readdata(idx) for slave in slave_cnx 
                                            if slave.readdata_ok(idx)
                    ]
            vhdl = [elmt for elmt in reduce(list.__add__, vhdl) if elmt != None]
            name = "wbs_master_dat_o(%d downto %d)" % ((idx*8)+7, idx*8)
            if len(vhdl) == 0:
                vhdl_fd.write("  %s <= (others => '0');\n" % name)
            else:
                vhdl.append("(others => '0')")
                sep = "\n%s else " % (" " * (len(name) + 5))
                vhdl_fd.write("  %s <= %s;\n" % 
                              (name, sep.join(vhdl)))

    # 7. Closing module
    vhdl_fd.write("\nend architecture;\n")
    vhdl_fd.close()
    
    # 8. Create vhdl.Entity object
    entity = Entity(StringIO(entity))
    instance = Instance(entity, "CP_" + base_name)
    
    # 9. Adding signals interconnection
    ports = dict((key, value[1]) 
                 for key, value in entity_ports.iteritems())

    instance.setPorts(ports)

    # 10. Returning instance
    return instance, base_name+".vhd"
def make_testbench(project):
    """Testbench module generation.
    
    The testbench module is used to generate all the necessary code to
    create a instance of System on Chip and to start simulation.
    
        @param project: System on Chip project settings 
    """
    base_name = ("%s_tb" % project.name)
    project.entity.name = base_name
    filename = path.join(project.path, ("%s.vhd" % base_name))

    try:
        vhdl_fd = open(filename, "w")
    except IOError:
        raise TestbenchError("Can't create %s.vhd file." % base_name)

    vhdl_fd.write(make_header("System on Chip testbench skeleton.", 
                                base_name))
    
    # 1. Building Entity declaration
    vhdl_fd.write("entity %s is\nend entity;\n" % base_name)

    # 2. Starting Architecture declaration
    vhdl_fd.write(_VHDL_ARCHITECTURE % (base_name))

    # 3. Adding project constants
    vhdl_fd.write(to_comment(['Project constants']))
    reset_min = 0
    const_def = []
    
    # 3.1 Define constant for each clock frequency
    for clk in project.soc.clocks.iteritems():
        const_def.append("  constant %s_PERIOD : time := 1 sec / %d;" % 
                          (clk.name.upper(), clk.frequency))
        if clk.frequency < reset_min or reset_min == 0:
            reset_min = clk.frequency
    
    # 3.2 Define reset timing
    const_def.append("  constant RESET_ON : time := 1 sec / %d;" % 
                     (reset_min * 3))
    const_def.append("  constant RESET_OFF : time := RESET_ON * 5;")
    
    # 3.3 Define constant for each slave interface base address
    for inst in project.instances.itervalues():
        for iface in inst.interfaces.itervalues():
            if iface.type == "WBS":
                const_def.append("  constant %s_%s_BASE_ADDR : integer := %d;" % 
                                 (inst.name.upper(), iface.name.upper(),
                                  iface.offset))
    
    vhdl_fd.write("\n".join(const_def))
    vhdl_fd.write("\n")
    
    # 4. Adding local signals
    vhdl_fd.write(to_comment(['Signals declaration']))
    vhdl_fd.write("  signal reset : std_logic;\n")
    vhdl_fd.write("".join(["  signal %s : %s := '0';\n" % (name, sig_type)
                           for name, sig_type in project.clock_list.iteritems()
                           ]))
    vhdl_fd.write("".join(["  signal %s : %s;\n" % (name, sig_type)
                            for name, sig_type in project.port_list.iteritems()
                            ]))

    # 4.1. Connecting signals to Top entity
    project.entity.setPorts(dict((name, name) 
                                 for name in project.port_list.iterkeys()))
    
    project.entity.setPorts(dict((name, name) 
                                 for name in project.clock_list.iterkeys()))
    project.entity.setPorts({"reset":"reset"}) 

    # 5. Adding entity declaration
    vhdl_fd.write(to_comment(['Components declaration']))
    vhdl_fd.write(project.entity.asComponent)

    vhdl_fd.write("\n\nbegin\n")
    
    # 6. Clocks and reset signals generation
    vhdl_fd.write("  reset <= '0', '1' after RESET_ON, '0' after RESET_OFF;\n")
    vhdl_fd.write("".join(["  %s <= not %s after %s_PERIOD/2;\n" % 
                           (name, name, name)
                            for name in project.clock_list.keys()
                            ]))
    
    # 7. Adding SoC Top entity
    vhdl_fd.write(str(project.entity))
    
    # 8. Closing testbench
    vhdl_fd.write("end architecture;\n")
    vhdl_fd.close()
    
    # 9. Returning file name
    return ("%s.vhd" % base_name)