Logo Search packages:      
Sourcecode: xcircuit version File versions

spice.py

# spice.py
#-----------------------------------------------------------------------
# Python script which writes a SPICE-format netlist.
# Replaces the code formerly in "netlist.c" (deprecated).
# Python scripting is now the preferred method for handling
# netlist output formats.
#-----------------------------------------------------------------------

import string

#-----------------------------------------------------------------------
# Parse the output string, substituting for index, ports, parameters,
# and automatic numbering using the '?' parameter.
#-----------------------------------------------------------------------

def parsedev(lstr, portdict, devdict, classidx, paramdict):
   rstr = lstr
   ltext = ''
   classname = rstr[0]        # single-character SPICE element type
   try:
      index = classidx[classname]
   except KeyError:
      index = 1
      classidx[classname] = 1

   if string.find(rstr, '%i'):
      rstr = string.replace(rstr, '%i', str(index))
      classidx[classname] = classidx[classname] + 1

   for pt in portdict.keys():
      ptstr = '%p' + pt
      rstr = string.replace(rstr, ptstr, portdict[pt])
      ptstr = '%p' + '"' + pt + '"'
      rstr = string.replace(rstr, ptstr, portdict[pt])

   for vt in paramdict.keys():
      vtvalue = paramdict[vt]
      if vtvalue == '?':
       vtvalue = str(index);
       classidx[classname] = classidx[classname] + 1
     
      vtstr = '%v' + vt
      rstr = string.replace(rstr, vtstr, vtvalue)
      vtstr = '%v' + '"' + vt + '"'
      rstr = string.replace(rstr, vtstr, vtvalue)

   # Simple replacements (%%, %r, %t) (all occurrences)
   #...................................................
   if string.find(rstr, '%%'):
      rstr = string.replace(rstr, '%%', '%')
   if string.find(rstr, '%n'):
      rstr = string.replace(rstr, '%n', devdict['name'])
   if string.find(rstr, '%r'):
      rstr = string.replace(rstr, '%r', '\n')
   if string.find(rstr, '%t'):
      rstr = string.replace(rstr, '%t', '\t')

   return rstr

#-----------------------------------------------------------------------
# Generate a dictionary of port substitutions and create the
# device string for output
#-----------------------------------------------------------------------

def devwrite(calldict, devdict, classidx):
   ltext = ''

   # Resolve network connections to ports and store as a dictionary
   #...............................................................
   portdict = {}
   ports_from = calldict['ports']
   ports_to = devdict['ports']
   for i in range(0,len(ports_from)):
      portdict[textprint(ports_to[i], params)] = textprint(ports_from[i], [])

   # Resolve instanced vs. default parameters and store as a dictionary
   # (only for use with the "%v" statement in info labels)
   #...............................................................
   paramdict = {}
   try:
      def_params = devdict['parameters']
   except KeyError:
      def_params = []

   try:
      params = calldict['parameters']
   except KeyError:
      params = []

   params += def_params[len(params):]

   for i in range(0,len(params)):
      paramdict[textprint(def_params[i], [])] = textprint(params[i], [])

   # For each "spice:" info label, parse the info label
   #...............................................................
   w = devdict['devices']
   for y in w:
      for u in y:
       lstr = select(textprint(u, params), 'spice')
       if lstr <> '':
          ltext += parsedev(lstr, portdict, devdict, classidx, paramdict)
          ltext += '\n'
   return ltext
       
#-----------------------------------------------------------------------
# Check if a device is "fundamental";  that is, has a "devices" dictionary
# with at least one entry with "spice:" for SPICE output.
#-----------------------------------------------------------------------

def isfundamental(devdict):
   try:
      w = devdict['devices']
   except KeyError:
      return 0
   else:
      for y in w:
       for u in y:
          lstr = select(textprint(u, []), 'spice')
          if lstr <> '':
             return 1
   return 0

#-----------------------------------------------------------------------
# Select the device string corresponding to the given prefix.
# Return the body of the string, or an empty string if the prefix
# doesn't match.
#-----------------------------------------------------------------------

def select(sstr, prefix):
   ltext = ''
   if sstr.startswith(prefix):
      ltext += sstr[len(prefix) + 1:]
   return ltext
       
#-----------------------------------------------------------------------
# Generate an ASCII string from an xcircuit string (list).  Translate
# overlines to "!" and Greek "mu" (either from Symbol font or from the
# ISO-Latin1 encoding of any standard font) to "u".
# String parameter substitution is performed if "params" is a non-empty
# list and the dictionary key "Parameter" is encountered in the string
# list "slist".
#-----------------------------------------------------------------------

def textprint(slist, params):
   ltext = ''
   is_symbol = 0
   is_iso = 0
   for x in slist:
      try:
      f = x.keys()[0]
      except AttributeError:        # must be a string
      if x == 'Return':
         ltext += '\n'
      elif x == 'Underline':
         ltext += '_'
      elif x == 'Overline':
         ltext += '!'
      else:             # is a dictionary; will have only one key
      if f == 'Font':
         lfont = x[x.keys()[0]]
         if lfont.startswith('Symbol'):
            is_symbol = 1
         else:
            is_symbol = 0
         if lfont.endswith('ISO'):
            is_iso = 1
         else:
            is_iso = 0
      elif f == 'Parameter':
         try:
            plist = params[x[x.keys()[0]]]
         except IndexError:
            ltext += ' --unknown parameter %d-- ' % x[x.keys()[0]]
         else:
            ltext += textprint(plist, [])
         continue;
      else:                   # text:  SPICE translates "mu" to "u"
         for y in x[x.keys()[0]]:
            if is_symbol:
             if y == 'f':
                ltext += 'phi'
             elif y == 'm':
                ltext += 'u'
             else:
                ltext += y
            else:
             if ord(y) == 181:
                ltext += 'u'
             elif ord(y) > 127:
                ltext += '/' + str(ord(y))
             else:
                ltext += y
   return ltext
      
#-----------------------------------------------------------------------
# Write netlist to the output
#-----------------------------------------------------------------------

def writespice():
   subidx=1       # subcircuit numbering
   devdict={}           # dictionary of low-level devices
   classidx = {}  # indices of SPICE devices (other than subcircuits)
   p=netlist()          # Generate the netlist
   g=p['globals'] # Get the list of global networks
   c=p['circuit'] # Get the list of (sub)circuits
   l=len(c)
   top=c[l-1]           # Top-level circuit
   topname=top['name']  # Name of the top-level circuit
   topname += '.spc'    # Filename to write to
   try:
      outfile=open(topname, 'w')
   except IOError:
      return

   # Print header line
   #...............................................................

   outfile.write('*SPICE circuit "' + topname + '"')
   outfile.write(' from XCircuit v' + str(xc_version))
   outfile.write(' (Python script "spice.py")\n')

   # Print global variables.  This is for hspice and should be
   # commented out for spice3.
   #...............................................................

   for x in g:    # 'globals' is a list of strings
      outfile.write('.GLOBAL ' + textprint(x, []) + '\n')
   outfile.write('\n')

   # Print the (sub)circuits.  Top level circuit does not get a "subckt"
   # entry.
   #...............................................................

   for x in c:    # 'circuits' is a list of dictionaries
      is_device = 0
      try:
       w = x['ports']         # write circuit name and ports, if any
      except KeyError:
       is_top = 1
      else:
       is_top = 0
       if isfundamental(x) == 0:
            outfile.write('.subckt ' + x['name'])
            for y in w:
             outfile.write(' ' + textprint(y, []))
            outfile.write('\n')
       else:
          is_device = 1
          devdict[x['name']] = x

      try:
       v = x['calls']         # calls to subcircuits in xcircuit
      except KeyError:
       pass
      else:
         for y in v:
          try:
             d = devdict[y['name']]
          except KeyError:          # A SPICE subcircuit instance
             outfile.write('X' + str(subidx))
             subidx+=1
             for z in y['ports']:
                outfile.write(' ' + textprint(z, []))
             outfile.write(' ' + y['name'] + '\n') 
          else:               # A SPICE circuit element
             nstr = devwrite(y, d, classidx);
             outfile.write(nstr)

      if is_top:
       outfile.write('.end\n')
      elif is_device == 0:
       outfile.write('.ends\n\n')

#-----------------------------------------------------------------------
# Key binding and menu button for the spice netlist output
# bind('Alt_S', 'writespice')
#-----------------------------------------------------------------------

newbutton('Netlist', 'Write Spice', 'writespice')

#-----------------------------------------------------------------------

Generated by  Doxygen 1.6.0   Back to index