def __init__(self, filename=None): # Open ZipFile in RAM, so we can modify the archive without loosing previous data. self.zfp = ZipString(filename) xml_data = "" # Scan Zipfile to find XML descriptor for name in self.zfp.namelist(): if name.lower().endswith('.xml'): xml_data = self.zfp.read(name) self.__xml_name = name break XmlFileBase.__init__(self, COMPONENTS_NODES, COMPONENTS_ATTRIBS, None, xml_data) if not filename is None: self.filename = path.basename(filename) # HDL files attributes clean-up for hdl_file in self.hdl_files.iteritems(): hdl_file.order = int(hdl_file.order) hdl_file.istop = to_boolean(hdl_file.istop) # Interfaces attributes clean-up for iface in self.interfaces.iteritems(): iface.type = str(iface.type).upper() iface.name = str(iface.name).lower() # Signals attributes clean-up for port in self.ports.iteritems(): port.name = str(port.name).lower() # Generics attributes clean-up for generic in self.generics.iteritems(): generic.name = str(generic.name).lower() # Perform component valid check self.check()
class Component(XmlFileBase): """Components management class. @param filename: Name of Zip archive which describe/include a component """ archive_name = None xml_basename = "component" filename = None __xml_name = "description.xml" _wb_ifaces = {} _errors = {} @property def has_errors(self): """Is true, if there are errors detected during last check.""" return len(self._errors) > 0 @property def last_errors(self): """Returns errors detected during last check.""" return self._errors def __init__(self, filename=None): # Open ZipFile in RAM, so we can modify the archive without loosing previous data. self.zfp = ZipString(filename) xml_data = "" # Scan Zipfile to find XML descriptor for name in self.zfp.namelist(): if name.lower().endswith('.xml'): xml_data = self.zfp.read(name) self.__xml_name = name break XmlFileBase.__init__(self, COMPONENTS_NODES, COMPONENTS_ATTRIBS, None, xml_data) if not filename is None: self.filename = path.basename(filename) # HDL files attributes clean-up for hdl_file in self.hdl_files.iteritems(): hdl_file.order = int(hdl_file.order) hdl_file.istop = to_boolean(hdl_file.istop) # Interfaces attributes clean-up for iface in self.interfaces.iteritems(): iface.type = str(iface.type).upper() iface.name = str(iface.name).lower() # Signals attributes clean-up for port in self.ports.iteritems(): port.name = str(port.name).lower() # Generics attributes clean-up for generic in self.generics.iteritems(): generic.name = str(generic.name).lower() # Perform component valid check self.check() def save(self, filename=None): """Update component settings in archive.""" # Update XML description in archive self.zfp.updatestr(self.__xml_name, self.asXML()) # Save to disk if file specified if not filename is None: self.zfp.saveAs(filename) def setTop(self, name): """Define IP top file.""" is_possible = False for hdl_file in self.hdl_files.iteritems(): if hdl_file.name == name: is_possible = True break if not is_possible: raise ComponentError("*** File '%s' don't exist in component, operation canceled.\n" % name) # Extract Top file entity declaration try: hdl = Entity(StringIO(self.zfp.read(name))) except EntityError: raise ComponentError("*** File '%s' has no valid entity declaration, operation canceled.\n" % name) # Erase previous generics, ports and interfaces self.generics.clear() self.ports.clear() self.interfaces.clear() # Add new Generics and Ports values for (name, attr) in hdl.generics.iteritems(): gen_type = combine_type(attr[0]) if len(attr) > 1: self.generics.add(name=name, type=gen_type, value=attr[1]) else: self.generics.add(name=name, type=gen_type) # parsing signals to extract interfaces interfaces = {} clocks = [] for port in hdl.ports.keys(): # Extracting interface type, name and signal (wb_type, if_name, wb_signal) = split_signal(port) # Adding interface to list if not interfaces.has_key(if_name): interfaces[if_name] = [wb_type] if wb_type == "WBC": clocks.append(if_name.upper()) # Checking interface name validity if interfaces[if_name][0] != wb_type: raise ComponentError("*** Error during top file signals parsing. Duplicate interface name '%s'\n" % if_name) if wb_signal is None: raise ComponentError("*** Error during top file signals parsing. Unknown signal '%s'\n" % port) # Saving interface in current list interfaces[if_name].append(port) # Adding signal to XML file self.ports.add(name=port, interface=if_name, type=wb_signal) # parsing interfaces to extract clock and reset signals for (key, value) in interfaces.items(): if key.upper() in clocks: self.interfaces.add(name=key, type=value[0]) else: clock = None if len(clocks) == 1: clock = clocks[0] else: for clk in clocks: if clk.startswith(key.upper()): clock = clk self.interfaces.add(name=key, type=value[0], clockandreset=clock) def getAttached(self, name, interface=False): """Search all signals attached to a given interface. Attributes: name - interface name interface - if true, seach for attached interfaces else for signals returns: (iface, list) iface - interface properties list - list of attached signals or interfaces. """ name = name.lower() src = self.interfaces.getElement(name) if src is None: raise ComponentError("*** No interface '%s' found, operation canceled.\n" % name) src = src[0] attached = [] if interface: if src.type.lower() == "wbc": attached = [iface for iface in self.interfaces.iteritems() if cmp_stri(iface.clockandreset, name) ] else: attached = [port for port in self.ports.iteritems() if port.interface.lower() == name ] return (src, attached) def addHdl(self, filename, scope="all", order=0, istop=False): """Append new HDL file to component. filename = new HDL file to add to this IP scope = Scope of this file. By default 'all'. order = load order. By default index of the file. istop = to declare this file as top entity. By default False. """ # First check if file exist if not path.isfile(filename): raise ComponentError("*** File '%s' not found, file addition canceled.\n" % filename) # Then get base name and directory and check if file already included name = path.basename(filename) dir_name = path.dirname(path.realpath(filename)) for hdl_file in self.hdl_files.iteritems(): if hdl_file.name == name: raise ComponentError("*** File '%s' already exist in component, file addition canceled.\n" % name) # Then adjust file load order if order >= len(self.hdl_files): order = len(self.hdl_files) + 1 if order == 0: order = len(self.hdl_files) + 1 # Now we push down every file that has to loaded after this file for hdl_file in self.hdl_files.iteritems(): if hdl_file.order >= order: hdl_file.order += 1 # Finally add this file to XML description and to ZIP archive self.hdl_files.add(name=name, scope=scope, order=order, istop=istop) self.zfp.update(name, path.join(dir_name, name)) # Hmmm, not finished if this file is the Top Entity if istop: self.setTop(name) def removeHdl(self, filename): """Remove HDL file from the component. filename = Name of the HDL file. """ # Look if this file exist or not filename = str(filename).lower() order = None istop = False for hdl_file in self.hdl_files.iteritems(): if hdl_file.name == filename: order = hdl_file.order istop = hdl_file.istop self.hdl_files.remove(hdl_file) break if order is None: raise ComponentError("*** File '%s' don't exist in component, file suppression canceled.\n" % filename) # Delete file from Zip archive try: self.zfp.removeFile(filename) except: pass # if this was the top entity, remove generics and ports declaration if istop: self.generics.clear() self.ports.clear() self.interfaces.clear() # and finally remove the file from the XML description for hdl_file in self.hdl_files.iteritems(): if hdl_file.order >= order: hdl_file.order -= 1 def extractHDL(self, base_dir, context=None): """Copy components HDL files to a given directory. @param base_dir: destination directory @param context: used to define type of project (xilinx, altera, etc.) @return: list containing file names """ #TODO: Extract file base on context value files = [] for hdl_file in self.hdl_files.iteritems(): files.append(hdl_file.name) filename = path.join(base_dir, hdl_file.name) try: vhdl_fd = open(filename, "wb") except IOError: raise ComponentError("Can't create %s file." % hdl_file.name) vhdl_fd.write(self.zfp.read(hdl_file.name)) vhdl_fd.close() return files def check(self): """Verify component integrity.""" # First search top entity topFile = None errors = [] for hdl_file in self.hdl_files.iteritems(): if hdl_file.istop: if not topFile is None: errors.append("*** Multiple top entity declaration ('%s' and '%s')."%(topFile,hdl_file.name)) topFile = hdl_file.name hdl = None if not topFile: errors.append("No Top entity declaration.") else: # Extract Top file entity declaration topFileStr = StringIO(self.zfp.read(topFile)) try: hdl = Entity(topFileStr) except EntityError: errors.append("Entity declaration parsing error.") self._wb_ifaces = {} if hdl: # Verify entity signals errors.extend(check_xml_entity(hdl, self.interfaces, self.ports)) # Verify interfaces signals for iface in self.interfaces.iteritems(): (_, signals) = self.getAttached(iface.name) if_name = iface.name.lower() wb_if = WishboneInterface(iface, signals, hdl) self._wb_ifaces[if_name] = wb_if errors.extend(wb_if.check()) # Verify that declared file is present in archive namelist = self.zfp.namelist() for hdl_file in self.hdl_files.iteritems(): try: namelist.index(hdl_file.name) except ValueError: errors.append("*** File '%s' don't exist in archive." % hdl_file.name) self._errors = errors return errors # pylint: disable-msg=W0622 def addInterface(self, name=None, type="export", clockandreset=None): """Add new interface to component. name = interface name type = type of interface (WBM, WBC, WBS or export) clockandreset = interface clock domain """ # Check parameters if not name: raise ComponentError("*** Parameter error, no interface name specified.") name = name.lower() if not type: raise ComponentError("*** Parameter error, no interface type specified.") type = str(type).upper() if not WB_INTERFACES.has_key(type): raise ComponentError("*** Parameter error, unknown interface type '%s'." % type) if (type=="WBS" or type=="WBM"): if clockandreset==None: raise ComponentError("*** Parameter error, interface type '%s' need clockandreset interface." % type) clockandreset = clockandreset.lower() # Check if there is no interface with same name if self.interfaces.hasElement(name): raise ComponentError("*** Parameter error, interface name '%s' already defined." % name) self.interfaces.add(name=name, type=type, clockandreset=clockandreset) def delInterface(self, name=None): """Remove interface from component. name = interface name """ if not self.interfaces.hasElement(name): raise ComponentError("*** Parameter error, no interface '%s' exist." % name) self.interfaces.remove(name) def cleanInterfaces(self): """Remove unused interfaces from component XML file. """ # Get component interfaces ifaces = {} for iface in self.interfaces: ifaces[iface[0].name.lower()] = 0 # Check to entity ports declaration for port in self.ports.iteritems(): port_iface_name = port.name.lower() if ifaces.has_key(port_iface_name): ifaces[port_iface_name] += 1 # Verify that each interface has signal attached for (ifname, ifsignals) in ifaces.iteritems(): if ifsignals == 0: self.interfaces.remove(ifname) def asEntity(self, context=None): """Convert component into VHDL entity object. """ # First search top entity for hdl_file in self.hdl_files.iteritems(): #TODO: Extract entity value based on context value if hdl_file.istop: # Extract Top file entity declaration topFileStr = StringIO(self.zfp.read(hdl_file.name)) try: return Entity(topFileStr) except EntityError: raise ComponentError("No entity declaration in top file.") raise ComponentError("No top file specified.") def asInstance(self, name, generics): """Convert component into project instance object. @param name: instance name @generics: VHDL generics parameters values """ try: return Instance(entity=self.asEntity(), name=name, generics=generics, interfaces=self._wb_ifaces) except InstanceError: raise ComponentError("Instance %s of %s creation error." % (name, self.name))