class Interface(WrapperXml): """ Manage components interfaces attributes: registerbaseaddress -- register base address registerslist -- list of register object portslist -- list of port object bus -- bustype """ def __init__(self, parent, **keys): """ Create interface object if node is a node or name. __init__(self,parent,name) __init__(self,parent,node) __init__(self,parent,nodestring) """ self._parent = parent if "name" in keys: WrapperXml.__init__(self, nodename="interface") self.name = keys["name"] elif "node" in keys: WrapperXml.__init__(self, node=keys["node"]) elif "wxml" in keys: WrapperXml.__init__(self, nodestring=keys["wxml"]) else: raise PodError("Keys unknown in Interface", 0) self._registerslist = [] self.portslist = [] self._slaveslist = [] self._bus = None if self.interface_class == "master": self.alloc_mem = AllocMem(self) if self.interface_class == "slave": self.interfacemaster = None if self.get_node("slaves") is not None: for element in self.get_subnodes("slaves", "slave"): self._slaveslist.append(Slave(self, node=element)) if self.get_node("registers") is not None: for element in self.get_subnodes("registers", "register"): self._registerslist.append(Register(self, node=element)) if self.get_node("ports") is not None: for node in self.get_subnodes("ports", "port"): self.portslist.append(Port(self, node=node)) # set bus if self.bus_name is not None: self.bus = self.bus_name @property def master(self): """ Get the master bus if exist """ if self.interface_class != "slave": raise PodError("Only slave interface could have a master", 0) if self.interfacemaster is None: raise PodError("Interface " + self.name + " is not connected on a master", 0) return self.interfacemaster @master.setter def master(self, masterinterface): """ set master interface """ if self.interface_class != "slave": raise PodError("interface " + self.name + " must be slave", 0) elif masterinterface.interface_class != "master": raise PodError("interface " + masterinterface.interface_class + " must be master", 0) self.interfacemaster = masterinterface @property def interface_class(self): """ Get the class interface """ return self.get_attr_value("class") @interface_class.setter def interface_class(self, classname): """ Set the class interface """ if classname not in INTERFACE_CLASS: raise PodError("classname " + classname + " unknown") self.set_attr("class", classname) @property def base_addr(self): """ get base address register value """ try: base = self.get_attr_value("base", "registers") if base is None: raise PodError("Base address register not set", 0) return int(base, 16) except AttributeError: raise PodError("Base address register not set", 0) @base_addr.setter def base_addr(self, baseoffset): """ Set the base offset for this interface baseoffset is an hexadecimal string the interface must be a slave bus """ if type(baseoffset) is str: baseoffset = int(baseoffset, 16) if self.bus_name is None: raise PodError("Interface is not a bus", 1) if self.interface_class != "slave": raise PodError("Bus must be slave", 1) size = self.mem_size if (baseoffset % size) != 0: raise PodError("Offset must be a multiple of " + hex(size), 1) self.set_attr("base", hex(baseoffset), "registers") @property def addr_port_size(self): """ How many pin in address port ? """ size = self.get_attr_value("addr_size") if size is not None: return int(size) try: return int( self.get_port_by_type( self.bus.sig_name("slave", "address")).size) except PodError: return 0 @property def mem_size(self): """ Get the memory size """ return int((2 ** self.addr_port_size) * self.regstep) @property def data_size(self): """ Get bus size """ size = self.get_attr_value("data_size") if size is None: return self.bus.data_size else: return size @property def addr_size(self): """ Get bus size """ size = self.get_attr_value("addr_size") if size is None: return int(self.addr_port_size) else: return int(size) @property def bus_name(self): """ Get the bus name """ return self.get_attr_value("bus") @property def bus(self): """ Get the interface bus""" return self._bus @bus.setter def bus(self, attribute): """ Set bus attribute""" self._bus = Bus(self, name=attribute) self.set_attr("bus", attribute) def is_bus(self): """ Test if this interface is a bus """ if self._bus is None: return False return True @property def ports(self): """ get the ports list of interface""" return self.portslist def get_port(self, portname): """ Get port by its name """ for port in self.portslist: if port.name == portname: return port raise PodError("Port " + portname + " does not exists", 1) def add_port(self, port): """ Adding a port """ port.parent = self self.portslist.append(port) self.add_subnode(nodename="ports", subnode=port) def get_port_by_type(self, porttypename): """ Get port using port type name as argument""" for port in self.portslist: if port.porttype == porttypename: return port raise PodError("No port with type " + str(porttypename), 1) def del_pin(self, instancedest, interfacedest=None, portdest=None, pindest=None, portsource=None, pinsource=None): """ Delete all interface pins """ if portsource is None: for port in self.ports: port.del_pin(instancedest=instancedest) else: port = self.get_port(portsource) port.del_pin(instancedest, interfacedest, portdest, pindest, pinsource) @property def slaves(self): """ Get the slaves list of interface""" return self._slaveslist def del_slave(self, slave): """ Delet slave """ self.alloc_mem.del_slave_interface(slave.get_interface()) self._slaveslist.remove(slave) self.del_subnode("slaves", "slave", {"instancename": slave.instancename, "interfacename": slave.interfacename}) def del_bus(self, instanceslavename, interfaceslavename=None): """ delete slave bus connection """ for slave in self.slaves: if slave.instancename == instanceslavename: if interfaceslavename is None: self.del_slave(slave) return elif slave.interfacename == interfaceslavename: self.del_slave(slave) return raise PodError("Bus connection " + str(self.name) + " -> " + str(instanceslavename) + "." + str(interfaceslavename) + " doesn't exist", 0) def connect_interface(self, interface_dest): """ Connect an interface between two components """ if len(interface_dest.ports) != len(self.ports): dest_len = len(interface_dest.ports) src_len = len(self.ports) if dest_len > src_len: for port in interface_dest.ports: if port.is_optional: try: if self.get_port_by_type(port.porttype) is None: pass except PodError: dest_len -= 1 else: for port in self.ports: if port.is_optional: try: if interface_dest.get_port_by_type(port.porttype) is None: pass except PodError: src_len -= 1 if src_len != dest_len : raise PodError(self.parent.name + "." + self.name + " and " + interface_dest.parent.name + "." + interface_dest.name + "are not the same number of ports") for port in self.ports: if port.porttype is None: raise PodError(self.parent.name + "." + self.name + "." + port.name + " has no type") try: port_dst = interface_dest.get_port_by_type(port.porttype) except PodError: if port.is_optional == False: raise PodError(interface_dest.parent.name + "." + interface_dest.name + " have no " + port.porttype + " port") if port_dst.direction == port.direction: raise PodError("Ports " + self.parent.name + "." + self.name + "." + port.name + " and " + interface_dest.parent.name + "." + interface_dest.name + "." + port_dst.name + " are the same direction") if port_dst.direction == "in" and port_dst.isVoid() is not True: raise PodError("Ports " + interface_dest.parent.name + "." + interface_dest.name + "." + port_dst.name + " is already connected") if port.direction == "in" and port.isVoid() is not True: raise PodError("Ports " + self.parent.name + "." + self.name + "." + port.name + " is already connected") for port in self.ports: try: port_dst = interface_dest.get_port_by_type(port.porttype) port.connect_port(port_dst) except PodError as error: if port.is_optional != True: raise error def connect_bus(self, instanceslave, interfaceslavename): """ Connect an interfaceslave to an interface bus master """ interfaceslave = instanceslave.get_interface(interfaceslavename) for slave in self.slaves: if slave.instancename == instanceslave.instancename and\ slave.interfacename == interfaceslavename: raise PodError("Bus connection for " + slave.instancename + "." + slave.interfacename + " already exists", 1) if self.bus_name is None: raise PodError("Interface " + self.name + " must be a bus ") if interfaceslave.bus_name is None: raise PodError("Interface " + interfaceslave.name + " must be a bus ") if self.bus_name != interfaceslave.bus_name: raise PodError("Can't connect " + self.bus_name + " on " + interfaceslave.bus_name, 1) if self.interface_class != "master": raise PodError(self.name + " is not a master", 0) if interfaceslave.bus_name is None: raise PodError(instanceslave.instancename + "." + interfaceslave.name + " is not a bus", 1) if interfaceslave.interface_class != "slave": raise PodError(instanceslave.instancename + "." + interfaceslave.name + " is not a slave", 1) self.add_subnode(nodename="slaves", subnodename="slave", attributedict={ "instancename": instanceslave.instancename, "interfacename": interfaceslavename}) self._slaveslist.append( Slave(self, instancename=instanceslave.instancename, interfacename=interfaceslavename)) self.alloc_mem.add_slave_interface(interfaceslave) interfaceslave.master = self interfaceslave.unique_id = self.alloc_mem.unique_id instanceslave.get_generic(genericname="id").value =\ str(interfaceslave.unique_id) @property def unique_id(self): """ Get the Identifiant number""" try: return self.get_attr_value("unique_id") except PodError: return None @unique_id.setter def unique_id(self, unique_id): """ Set the Identifiant number""" self.set_attr("unique_id", str(unique_id)) def autoconnect_pins(self): """ autoconnect pin """ for port in self.ports: port.autoconnect_pins() def connect_clk_domain(self, instancedestname, interfacedestname): """ Connect clock domain """ for slave in self.slaves: if slave.instancename == instancedestname\ and slave.interfacename == interfacedestname: raise PodError("Clock connection " + instancedestname + "." + interfacedestname + " exists", 1) self.add_subnode(nodename="slaves", subnodename="slave", attributedict={"instancename": instancedestname, "interfacename": interfacedestname}) self._slaveslist.append( Slave(self, instancename=instancedestname, interfacename=interfacedestname)) def get_register(self, registername): """ Get register by name """ for register in self.registers: if register.name == registername: return register raise PodError("No register with name " + registername, 0) @property def parent(self): """ return parent instance """ return self._parent @parent.setter def parent(self, parent): """ set parent instance """ self._parent = parent @property def registers(self): """ return registers list """ return self._registerslist @property def registers_map(self): """ Return the memory mapping for slave interface """ if len(self._registerslist) != 0: listreg = [] # sort registers dict by offset order self._registerslist.sort(key=lambda x: int(x.offset, 16)) # display each register for register in self._registerslist: listreg.append( {"offset": int(register.offset, 16) * self.regstep + self.base_addr, "name": register.name}) return listreg else: return [{"offset": self.base_addr, "name": self.name}] @property def regstep(self): """ Step between two register """ return int(self.data_size) / 8