Source code for spice.spice_module

"""
============
Spice Module
============

Class for Spice netlist parsing.

"""
import os
import pdb
import shutil
import fileinput
import sys
from thesdk import *
from spice import *
from copy import deepcopy
import traceback

[docs] class spice_module(thesdk): """ This class parses source netlist for subcircuits and handles the generation of a separate pruned subckt_* -file. This class is internally utilized by the spice_testbench module. """ def __init__(self, **kwargs): # No need to propertize these yet self._file=kwargs.get('file','') self._name=kwargs.get('name','') self.parent=kwargs.get('parent') # There should be no need for parent in this module if not self.file and not self._name: self.print_log(type='F', msg='Either name or file must be defined') @property def file(self): """ Filepath to the entity's spice netlist source file (i.e. './spice/entityname.scs'). :type: str """ if not hasattr(self,'_file'): self._file=None return self._file @file.setter def file(self,value): self._file=value @property def name(self): """Entity name :type: str """ if not self._name: self._name=os.path.splitext(os.path.basename(self.file))[0] return self._name @property def custom_subckt_name(self): """Custom name of the subcircuit to look from from the netlist file during parsing for 'subckt' property. Enables using compatible (in term sof IOs paremeters) netlists defined for designs of different name. :type: str Example: Most common use case of module is a dut in a testbench. There you can set this parameter before execution as:: self.spice_tb.dut.custom_subckt_name = 'some_name' self.run_spice() """ if not hasattr(self,'_custom_subckt_name'): self._custom_subckt_name = None return self._custom_subckt_name @custom_subckt_name.setter def custom_subckt_name(self,value): self._custom_subckt_name = value @property def subckt(self): """The contents of the subcircuit definition file of the entity. Extract the definitions form the source netlist. The source netlist when accessed. Can be written to the subckt_file with export_subckt method. :type: str """ if not hasattr(self,'_subckt'): self._subckt="%s Subcircuit definitions\n\n" % self.parent.spice_simulator.commentchar # Extract the module definition if os.path.isfile(self.file): try: self.print_log(type='D',msg='Parsing source netlist %s' % self.file) if self.custom_subckt_name: #Replace subcircuit_custom_name with parent.name self._subckt += subprocess.check_output( 'sed -n \'/\.*[sS][uU][bB][cC][kK][tT]\s\s*/,/\.*[eE][nN][dD][sS]/p\' %s | sed \'s/%s/%s/g\'' % (self.file,self.custom_subckt_name,self.parent.name), shell=True).decode('utf-8') else: self._subckt += subprocess.check_output( 'sed -n \'/\.*[sS][uU][bB][cC][kK][tT]\s\s*/,/\.*[eE][nN][dD][sS]/p\' %s' % self.file, shell=True).decode('utf-8') except: self.print_log(type='E',msg='Something went wrong while parsing %s.' % self.file) self.print_log(type='E',msg=traceback.format_exc()) else: self.print_log(type='W',msg='File %s not found.' % self.file) return self._subckt @subckt.setter def subckt(self,value): self._subckt=value @subckt.deleter def subckt(self,value): self._subckt=None @property def instance(self): """The subcircuit instance to be placed in the testbench. Parsed from the subckt property :type: str """ try: if not hasattr(self,'_instance'): subckt = self.subckt.split('\n') startmatch=re.compile(r"%s %s " %(self.parent.spice_simulator.subckt, self.parent.name) ,re.IGNORECASE) if len(subckt) <= 3: self.print_log(type='W',msg='No subcircuit found.') self._instance = "%s Empty subcircuit\n" % (self.parent.spice_simulator.commentchar) else: self._instance = "%s Subcircuit instance\n" % (self.parent.spice_simulator.commentchar) startfound = False endfound = False lastline = False for line in subckt: if startmatch.search(line) != None: startfound = True # For spectre we need to process the statline as potential endline if self.parent.model == 'spectre': if startfound and len(line) > 0: if lastline: endfound = True startfound = False if not line[-1] == '\\': lastline = True elif startfound and len(line) > 0: if self.parent.model == 'eldo': if line[0] != '+': endfound = True startfound = False elif self.parent.model == 'spectre': if lastline: endfound = True startfound = False if not line[-1] == '\\': lastline = True # For consistency, even though identical to eldo elif self.parent.model == 'ngspice': if line[0] != '+': endfound = True startfound = False if startfound and not endfound: words = line.split(" ") if words[0].lower() == self.parent.spice_simulator.subckt: if self.parent.model == 'eldo': words[0] = "X%s%s" % (self.parent.name,'') elif self.parent.model == 'spectre': words[0] = "X%s%s" % (self.parent.name, ' (') elif self.parent.model == 'ngspice': words[0] = "X%s%s" % (self.parent.name,'') words.pop(1) line = ' '.join(words) self._instance += line + "%s\n" % (' \\' if lastline else '') if self.parent.model == 'eldo': self._instance += ('+') + self.parent.name elif self.parent.model == 'spectre': self._instance += (') ' ) + self.parent.name elif self.parent.model == 'ngspice': self._instance += ('+') + self.parent.name return self._instance except: self.print_log(type='E',msg='Something went wrong while generating subcircuit instance.') self.print_log(type='E',msg=traceback.format_exc()) @instance.setter def instance(self,value): self._instance=value @instance.deleter def instance(self,value): self._instance=None
[docs] def export_subckts(self,**kwargs): """ Internally called function to write the parsed subcircuit definitions to a file. Parameters ---------- file : str Path to file where to write. force : Bool, False Force writing """ file = kwargs.get('file') force = kwargs.get('force', False) if not os.path.isfile(file): self.print_log(type='D',msg='Exporting spice subcircuit to %s' %(file)) with open(file, "w") as module_file: module_file.write(self.subckt) elif os.path.isfile(file) and not force: self.print_log(type='F', msg=('Export target file %s exists.\n Force overwrite with force=True.' %(file))) elif force: self.print_log(type='I',msg='Forcing overwrite of spice subcircuit to %s.' %(file)) with open(file, "w") as module_file: module_file.write(self.subckt)
if __name__=="__main__": pass