files: # Copyright 2020 Silicon Compiler Authors. All Rights Reserved.
  
  import re
  import os
  import textwrap
  import sys
  
  ###############################################################################
  # CHIP CONFIGURATION
  ###############################################################################
  
  def schema_cfg():
      '''Method for defining Chip configuration schema
      All the keys defined in this dictionary are reserved words.
      '''
  
      cfg = {}
  
      # Flow Setup (from schema_options)
      cfg = schema_flow(cfg, 'default')
  
      # Metric Tracking
      cfg = schema_metrics(cfg, 'goal')
      cfg = schema_metrics(cfg, 'real')    
      
      # Recording design provenance 
      cfg = schema_record(cfg) 
      
      # FPGA Parameters
      cfg = schema_fpga(cfg)
  
      # ASIC Parameters
      cfg = schema_pdk(cfg)
      cfg = schema_asic(cfg) 
      cfg = schema_libs(cfg, 'stdcell')
      cfg = schema_libs(cfg, 'macro')
  
      # Designer's Choice
      cfg = schema_design(cfg)
      cfg = schema_mcmm(cfg)
      
      # Designer Runtime options
      cfg = schema_options(cfg)
  
      # Remote options
      cfg = schema_remote(cfg)
      
      # Run status
      cfg = schema_status(cfg)
      
      return cfg
  
  
  ###############################################################################
  # CHIP LIBRARY 
  ###############################################################################
  def schema_lib():
      pass    
  
  ###############################################################################
  # CHIP LAYOUT
  ###############################################################################
  def schema_layout():
      
      layout = {}
  
      layout = schema_lef(layout)
  
      layout = schema_def(layout)
  
      return layout
  
  ###############################################################################
  # UTILITY FUNCTIONS TIED TO SC SPECIFICATIONS
  ###############################################################################
  
  def schema_path(filename):
      ''' Resolves file paths using SCPATH and resolve environment variables
      starting with $
      '''
  
      #Resolve absolute path usign SCPATH
      #list is read left to right    
      scpaths = str(os.environ['SCPATH']).split(':')
      for searchdir in scpaths:        
          abspath = searchdir + "/" + filename
          if os.path.exists(abspath):
              filename = abspath
              break
      #Replace $ Variables
      varmatch = re.match('^\$(\w+)(.*)', filename)
      if varmatch:
          var = varmatch.group(1)
          varpath = os.getenv(var)
          if varpath is None:
              print("ERROR: Missing environment variable:", var)
              sys.exit()
          relpath = varmatch.group(2)
          filename = varpath + relpath
          
      return filename
              
  def schema_istrue(value):
      ''' Checks schema boolean string and returns Python True/False
      '''
      boolean = value[-1].lower()
      if boolean == "true":
          return True
      else:
          return False
  
  def schema_check(cfg, leafkey, value):
      ''' Checks that leaf cell value agrees with type 
      '''
  
      ok = True
      keyval = "(Key,value) = (" + leafkey +  ",'" + ' '.join(value) + "')"
      if cfg['type'] == 'bool':
          if value[0] not in ('true', 'false'):
              print("ERROR: Value should be boolan.", keyval)
              ok = False
      else:
          for item in value:            
              if cfg['type'] == 'str':
                  ok =  isinstance(item, str)
                  if not ok:
                      print("ERROR: Value should be a string.", keyval)
              elif cfg['type'] == 'num':
                  try:
                      isinstance(float(item), float)
                  except:
                      ok = False
                      print("ERROR: Value should be a number.", keyval)
              elif cfg['type'] == 'file':
                  ok =  os.path.isfile(schema_path(item))
                  if not ok:
                      print("ERROR: File is missing.", keyval)
              elif cfg['type'] == 'dir':
                  ok =  os.path.isdir(schema_path(item))
                  if not ok:
                      print("ERROR: Directory is missing.", keyval)
  
      return ok
  
  
  def schema_reorder_keys(param_help, item):
      ''' Returns a keylist used to access the dictionary based on the 
      cmdline switch argument and the param_help field.
      '''
  
      #Split param help into keys and data based in <>
      m = re.search('(.*?)(<.*)',param_help)
      paramlist = m.group(1).split()
      datalist = m.group(2).split()
      #Split cmdline inputn based on spaces
      itemlist = item.split()
      
      depth = len(paramlist)+1
      args = [None] * depth
  
      #Combine keys from param_help and cmdline field
      j=0
      for i in range(depth-1):
          if paramlist[i].endswith('var'):
              args[i]=itemlist[j]
              j=j+1
          else:
              args[i]=paramlist[i]
  
      #Insert data field as last entry (some are string tuples)
      args[-1] = itemlist[-len(datalist):]
      
      return args
  
      
  ###############################################################################
  # FPGA
  ###############################################################################
  
  def schema_fpga(cfg):
      ''' FPGA Setup
      '''
      cfg['fpga'] = {}
  
      cfg['fpga']['xml'] = {
          'switch' : '-fpga_xml',
          'requirement' : 'fpga',
          'type' : 'file',        
          'lock' : 'false',
          'copy' : 'true',        
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'FPGA Architecture File',
          'param_help' : "fpga xml <file>",
          'example': ["cli: -fpga_xml myfpga.xml",                    
                      "api:  chip.set('fpga', 'xml', 'myfpga.xml')"],
          'help' : """
          Provides an XML-based architecture description for the target FPGA
          architecture to be used in VTR, allowing targeting a large number of 
          virtual and commercial architectures.
          [More information...](https://verilogtorouting.org)
          """
      }
  
      cfg['fpga']['vendor'] = {
          'switch' : '-fpga_vendor',
          'requirement' : '!fpga_xml',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'FPGA Vendor Name',
          'param_help' : "fpga vendor <str>",
          'example': ["cli: -fpga_vendor acme",                    
                      "api:  chip.set('fpga', 'vendor', 'acme')"],
          'help' : """
          Name of the FPGA vendor for non-VTR based compilation
          """
      }
  
      cfg['fpga']['device'] = {
          'switch' : '-fpga_device',
          'requirement' : '!fpga_xml',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'FPGA Device Name',
          'param_help' : "fpga device <str>",
          'example': ["cli: -fpga_device fpga64k",                    
                      "api:  chip.set('fpga', 'device', 'fpga64k')"],
          'help' : """
          Name of the FPGA device for non-VTR based compilation
          """
      }
  
      return cfg
  
  ###############################################################################
  # PDK
  ###############################################################################
  
  def schema_pdk(cfg):
      ''' Process Design Kit Setup
      '''
      cfg['pdk'] = {}
      cfg['pdk']['foundry'] = {
          'switch' : '-pdk_foundry',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Foundry Name',
          'param_help' : "pdk foundry <str>",
          'example': ["cli: -pdk_foundry virtual",                    
                      "api:  chip.set('pdk', 'foundry', 'virtual')"],
          'help' : """
          The name of the foundry. For example: intel, gf, tsmc, "samsung, 
          skywater, virtual. The \'virtual\' keyword is reserved for simulated 
          non-manufacturable processes such as freepdk45 and asap7.              
          """        
      }
  
      cfg['pdk']['process'] = {
          'switch' : '-pdk_process',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Name',
          'param_help' : "pdk process <str>",
          'example': ["cli: -pdk_process asap7",                    
                      "api:  chip.set('pdk', 'process', 'asap7')"],
          'help' : """
          The official public name of the foundry process. The name is case 
          insensitive, but should otherwise match the complete public process 
          name from the foundry. Example process names include 22ffl from Intel,
          12lpplus from Globalfoundries, and 16ffc from TSMC.        
          """
      }
  
      cfg['pdk']['node'] = {
          'switch' : '-pdk_node',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Node',
          'param_help' : "pdk node <num>",
          'example': ["cli: -pdk_node 130",                    
                      "api:  chip.set('pdk', 'node', '130')"],
          'help' : """
          An approximate relative minimum dimension of the process node. A 
          required parameter in some reference flows that leverage the value to 
          drive technology dependent synthesis and APR optimization. Node 
          examples include 180nm, 130nm, 90nm, 65nm, 45nm, 32nm, 22nm, 14nm, 
          10nm, 7nm, 5nm, 3nm. The value entered implies nanometers.
          """
      }
  
      cfg['pdk']['wafersize'] = {
          'switch' : '-pdk_wafersize',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Size',
          'param_help' : "pdk wafersize <num>",
          'example': ["cli: -pdk_wafersize 300",                    
                      "api:  chip.set('pdk', 'wafersize', '300')"],
          'help' : """
          Specifies the wafer diameter for the process in mm.
          """
      }
  
      cfg['pdk']['wafercost'] = {
          'switch' : '-pdk_wafercost',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Cost',
          'param_help' : "pdk wafercost <num>",
          'example': ["cli: -pdk_wafercost 10000",                    
                      "api:  chip.set('pdk', 'wafercost', '10000')"],
          'help' : """
          Specifies the raw cost per wafer purchased in USD, not 
          accounting for yield loss.
          """
      }
  
      cfg['pdk']['d0'] = {
          'switch' : '-pdk_d0',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Defect Density',
          'param_help' : "pdk d0 <num>",
          'example': ["cli: -pdk_d0 0.1",                    
                      "api:  chip.set('pdk', 'd0', '0.1')"],
          'help' : """
          Process defect density (D0) expressed as random defects per cm^2.
          """
      }
      
      cfg['pdk']['hscribe'] = {
          'switch' : '-pdk_hscribe',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Horizontal Scribeline',
          'param_help' : "pdk hscribe <num>",
          'example': ["cli: -pdk_hscribe 0.1",                    
                      "api:  chip.set('pdk', 'hscribe', '0.1')"],
          'help' : """
          Specifies the width of the horizontal scribe line in mm.
          """
      }
  
      cfg['pdk']['vscribe'] = {
          'switch' : '-pdk_vscribe',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Horizontal Scribeline',
          'param_help' : "pdk vscribe <num>",
          'example': ["cli: -pdk_vscribe 0.1",                    
                      "api:  chip.set('pdk', 'vscribe', '0.1')"],
          'help' : """
          Specifies the width of the vertical scribe line in mm.
          """
      }
      
      cfg['pdk']['edgemargin'] = {
          'switch' : '-pdk_edgemargin',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Edge Margin',
          'param_help' : "pdk edgemargin <num>",
          'example': ["cli: -pdk_edgemargin 1",                    
                      "api:  chip.set('pdk', 'edgemargin', '1')"],
          'help' : """
          Specifies keepout distance/margin (in mm) from the wafer edge 
          where no dies can be placed.
          """
      }
      
      cfg['pdk']['density'] = {
          'switch' : '-pdk_density',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Transistor Density',
          'param_help' : "pdk density <num>",
          'example': ["cli: -pdk_density 100e6",                    
                      "api:  chip.set('pdk', 'density', '10e6')"],
          'help' : """
          An approximate logic density expressed as # transistors / mm^2
          calculated as:
          0.6 * (Nand2 Transistor Count) / (Nand2 Cell Area) +
          0.4 * (Register Transistor Count) / (Register Cell Area)
          """
      }
  
      cfg['pdk']['sramsize'] = {
          'switch' : '-pdk_sramsize',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process SRAM Bitcell Size',
          'param_help' : "pdk sramsize <num>",
          'example': ["cli: -pdk_sramsize 0.032",                    
                      "api:  chip.set('pdk', 'sramcell', '0.026')"],
          'help' : """
          The area an SRAM bitcell expressed in um^2. 
          """
      }
  
      cfg['pdk']['rev'] = {
          'switch' : '-pdk_rev',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Revision',
          'param_help' : "pdk rev <str>",
          'example': ["cli: -pdk_rev 1.0",                    
                      "api:  chip.set('pdk', 'rev', '1.0')"],
          'help' : """
          An alphanumeric string specifying the revision  of the current PDK. 
          Verification of correct PDK and IP revisions revisions is an ASIC 
          tapeout requirement in all commercial foundries.
          """
      }
      
      cfg['pdk']['drm'] = {
          'switch' : '-pdk_drm',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],        
          'short_help' : 'PDK Design Rule Manual',
          'param_help' : "pdk drm <file>",
          'example': ["cli: -pdk_drm asap7_drm.pdf",                    
                      "api:  chip.set('pdk', 'drm', 'asap7_drm.pdf')"],
          'help' : """
          A PDK document that includes complete information about physical and 
          electrical design rules to comply with in the design and layout of the 
          chip. In cases where the user guides and design rules are combined into
          a single document, the pdk_doc parameter can be left blank.
          """
      }
  
      cfg['pdk']['doc'] = {
          'switch' : '-pdk_doc',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'PDK Documents',
          'param_help' : "pdk doc <file>",
          'example': ["cli: -pdk_doc asap7_userguide.pdf",                    
                      "api: chip.add('pdk', 'doc', 'asap7_userguide.pdf')"],
          'help' : """
          A list of critical PDK designer documents provided by the foundry 
          entered in order of priority. The first item in the list should be the
          primary PDK user guide. The purpose of the list is to serve as a 
          central record for all must-read PDK documents.
          """
      }
          
      cfg['pdk']['stackup'] = {
          'switch' : '-pdk_stackup',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Metal Stackups',
          'param_help' : "pdk stackup <str>",
          'example': ["cli: -pdk_stackup 2MA4MB2MC",                    
                      "api: chip.add('pdk', 'stackup', '2MA4MB2MC')"],
          'help' : """
          A list of all metal stackups offered in the process node. Older process
          nodes may only offer a single metal stackup, while advanced nodes 
          offer a large but finite list of metal stacks with varying combinations
          of metal line pitches and thicknesses. Stackup naming is unqiue to a 
          foundry, but is generally a long string or code. For example, a 10 
          metal stackup two 1x wide, four 2x wide, and 4x wide metals, might be
          identified as 2MA4MB2MC. Each stackup will come with its own set of 
          routing technology files and parasitic models specified in the 
          pdk_pexmodel and pdk_aprtech parameters.
          """
      }
  
      cfg['pdk']['devicemodel'] = {}
      cfg['pdk']['devicemodel']['default'] = {}
      cfg['pdk']['devicemodel']['default']['default'] = {}
      cfg['pdk']['devicemodel']['default']['default']['default'] = {
          'switch' : '-pdk_devicemodel',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Device Models',
          'param_help' : "pdk devicemodel stackvar typevar toolvar <file>",
          'example': ["""cli: -pdk_devicemodel 'M10 spice xyce asap7.sp'""",
                      """api: chip.add('pdk','devicemodel','M10','spice','xyce',
                      'asap7.sp')"""],
          'help' : """
          Filepaths for all PDK device models. The structure serves as a central 
          access registry for models for different purpose and tools. Examples of
          device model types include spice, aging, electromigration, radiation. 
          An example of a spice tool is xyce.
          """
      }
  
      cfg['pdk']['pexmodel'] = {}
      cfg['pdk']['pexmodel']['default'] = {}
      cfg['pdk']['pexmodel']['default']['default']= {}
      cfg['pdk']['pexmodel']['default']['default']['default'] = {
          'switch' : '-pdk_pexmodel',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Parasitic TCAD Models',
          'param_help' : "pdk pexmodel stackvar cornervar toolvar <file>",
          'example': ["""cli: -pdk_pexmodel 'M10 max fastcap wire.mod'""",
                      """api: chip.add('pdk','pexmodel','M10','max','fastcap'
                      'wire.mod')"""],
          'help' : """
          Filepaths for all PDK wire TCAD models. The structure serves as a 
          central access registry for models for different purpose and tools. 
          Examples of RC extraction corners include: min, max, nominal. An 
          example of an extraction tool is FastCap.
          """
      }
  
      cfg['pdk']['layermap'] = {}
      cfg['pdk']['layermap']['default'] = {}
      cfg['pdk']['layermap']['default']['default'] = {}
      cfg['pdk']['layermap']['default']['default']['default'] = {
          'switch' : '-pdk_layermap',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date' : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Mask Layer Maps',
          'param_help' : "pdk layermap stackvar srcvar dstvar <file>",
          'example': ["""cli: -pdk_layermap 'M10 klayout gds asap7.map'""",
                      """api: chip.add('pdk','layermap','M10','klayout','gds'
                      'asap7.map')"""],
          'help' : """
          Files describing input/output mapping for streaming layout data from 
          one format to another. A foundry PDK will include an official layer 
          list for all user entered and generated layers supported in the GDS 
          accepted by the foundry for processing, but there is no standardized 
          layer definition format that can be read and written by all EDA tools.
          To ensure mask layer matching, key/value type mapping files are needed
          to convert EDA databases to/from GDS and to convert between different
          types of EDA databases.
          """
      }
  
      cfg['pdk']['display'] = {}
      cfg['pdk']['display']['default'] = {}
      cfg['pdk']['display']['default']['default'] = {}
      cfg['pdk']['display']['default']['default']['default'] = {
          'switch' : '-pdk_display',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date' : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Display Configurations',
          'param_help' : "pdk display stackvar toolvar formatvar <file>",
          'example': ["""cli: -pdk_display 'M10 klayout python display.lyt'""",
                      """api: chip.add('pdk', display','M10','klayout','python'
                      'display.cfg')"""],
          'help' : """
          Display configuration files describing colors and pattern schemes for
          all layers in the PDK. The display configuration file is entered on a 
          stackup and per tool basis.
          """
      }
  
      cfg['pdk']['plib'] = {}
      cfg['pdk']['plib']['default'] = {}
      cfg['pdk']['plib']['default']['default'] = {}
      cfg['pdk']['plib']['default']['default']['default']= {
          'switch' : '-pdk_plib',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Primitive Libraries',
          'param_help' : "pdk plib stackvar toolvar formatvar <file>",
          'example': ["""cli: -pdk_plib 'M10 klayout oa /disk/asap7/oa/devlib'""",
                      "api: chip.add('pdk','plib','M10', 'klayout', 'oa',"
                      "'/disk/asap7/oa/devlib')"],
          'help' : """
          Filepaths to all primitive cell libraries supported by the PDK. The 
          filepaths are entered on a per stackup and per format basis.
          """
      }
  
      cfg['pdk']['aprtech'] = {}
      cfg['pdk']['aprtech']['default'] = {}
      cfg['pdk']['aprtech']['default']['default'] = {}
      cfg['pdk']['aprtech']['default']['default']['default'] = {
          'switch' : '-pdk_aprtech',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'APR Technology File',
          'param_help' : "pdk aprtech stackvar libtypevar filetypevar <file>",
          'example': ["""cli: -pdk_aprtech 'M10 12t lef tech.lef'""",
                      "api: chip.add('pdk','aprtech','M10','12t','lef',"
                      "'tech.lef')"],
          'help' : """
          Technology file containing the design rule and setup information needed
          to enable DRC clean automated placement a routing. The file is 
          specified on a per stackup, libtype, and format basis, where libtype 
          generates the library architecture (e.g. library height). For example a
          PDK with support for 9 and 12 track libraries might have libtypes 
          called 9t and 12t.
          """
      }
  
      cfg['pdk']['grid'] = {}
      cfg['pdk']['grid']['default'] = {}
      cfg['pdk']['grid']['default']['default'] = {}    
  
      #Name Map
      cfg['pdk']['grid']['default']['default']['name'] = {
          'switch' : '-pdk_grid_name',
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Name Map',
          'param_help' : "pdk grid stackvar layervar name <str>",
          'example': ["""cli: -pdk_grid_name 'M10 m1 metal1'""",
                      "api: chip.add('pdk', 'grid', 'M10', 'm1', 'name',"
                      "'metal1')"],
          'help' : """
          Defines the hardcoded PDK metal name on a per stackup and per metal 
          basis. Metal layers are ordered from m1 to mn, where m1 is the lowest
          routing layer in the tech.lef.
          """
      }
      # Vertical Grid
      cfg['pdk']['grid']['default']['default']['xpitch'] = {
          'switch' : '-pdk_grid_xpitch',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Horizontal Grid',
          'param_help' : "pdk grid stackvar layervar xpitch <num>",
          'example': ["""cli: -pdk_grid_xpitch 'M10 m1 0.5'""",
                      "api: chip.add('pdk','grid','M10','m1','xpitch',"
                      "'0.5')"],
          'help' : """
          Defines the vertical routing grid on a a per stackup and per metal 
          basis. Values are specified in um. Metal layers are ordered from m1 to 
          mn, where m1 is the lowest routing layer in the tech.lef.        
          """
      }
  
      # Horizontal Grid
      cfg['pdk']['grid']['default']['default']['ypitch'] = {
          'switch' : '-pdk_grid_ypitch',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Vertical Grid',
          'param_help' : "pdk grid stackvar layervar ypitch <num>'",
          'example': ["""cli: -pdk_grid_ypitch 'M10 m2 0.5'""",
                      "api: chip.add('pdk','grid','M10','m2','ypitch',"
                      "'0.5')"],
          'help' : """
          Defines the horizontal routing grid on a a per stackup and per metal 
          basis. Values are specified in um. Metal layers are ordered from m1 to
          mn, where m1 is the lowest routing layer in the tech.lef.
          """
      }
      
      # Vertical Grid Offset
      cfg['pdk']['grid']['default']['default']['xoffset'] = {
          'switch' : '-pdk_grid_xoffset',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Preferred Direction',
          'param_help' : "pdk grid stackvar layervar xoffset <num>",
          'example': ["""cli: -pdk_grid_xoffset 'M10 m2 0.5'""",
                      "api: chip.add('pdk','grid','M10','m2','xoffset',"
                      "'0.5')"],
          'help' : """
          Defines the horizontal grid offset of a metal layer specified on a per 
          stackup and per metal basis. Values are specified in um.
          """
      }
      
      # Horizontal Grid Offset
      cfg['pdk']['grid']['default']['default']['yoffset'] = {
          'switch' : '-pdk_grid_yoffset',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Preferred Direction',
          'param_help' : "pdk grid stackvar layervar yoffset <num>",
          'example': ["""cli: -pdk_grid_yoffset 'M10 m2 0.5'""",
                      "api: chip.add('pdk','grid','M10','m2','yoffset',"
                      "'0.5')"],
          'help' : """
          Defines the horizontal grid offset of a metal layer specified on a per 
          stackup and per metal basis. Values are specified in um.
          """
      }
  
      # Routing Layer Adjustment
      cfg['pdk']['grid']['default']['default']['adj'] = {
          'switch' : '-pdk_grid_adj',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Adjustment',
          'param_help' : "pdk grid stackvar layervar adj <num>",
          'example': ["""cli: -pdk_grid_adj 'M10 m2 0.5'""",
                      "api: chip.set('pdk','grid','M10','m2','adj',"
                      "'0.5')"],
          'help' : """
          Defines the routing resources adjustments for the design on a per layer
          basis. The value is expressed as a fraction from 0 to 1. A value of
          0.5 reduces the routing resources by 50%.
          """
      }
  
      # Routing Layer Capacitance
      cfg['pdk']['grid']['default']['default']['cap'] = {
          'switch' : '-pdk_grid_cap',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Layer Capacitance',
          'param_help' : "pdk grid stackvar layervar cap <num>",
          'example': ["""cli: -pdk_grid_cap 'M10 m2 0.2'""",
                      "api: chip.set('pdk','grid','M10','m2','cap',"
                      "0.2')"],
          'help' : """
          Specifies the unit capacitance of a wire defined by the grid
          width and spacing values in the 'grid' structure.  The
          value is specifed as ff/um. The number is only meant to be used 
          as a sanity check and for coarse design planning. Accurate 
          analysis should use the PEX models.
          """
      }
  
      # Routing Layer Resistance
      cfg['pdk']['grid']['default']['default']['res'] = {
          'switch' : '-pdk_grid_res',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Layer Resistance',
          'param_help' : "pdk grid stackvar layervar res <num>",
          'example': ["""cli: -pdk_grid_res 'M10 m2 0.2'""",
                      "api: chip.set('pdk','grid','M10','m2','res',"
                      "'0.2')"],
          'help' : """
          Specifies the resistance  of a wire defined by the grid
          width and spacing values in the 'grid' structure.  The
          value is specifed as ohms/um. The number is only meant to be 
          used as a sanity check and for coarse design planning. Accurate 
          analysis should use the PEX models.
          """
      }
  
      # Wire Temperature Coefficient
      cfg['pdk']['grid']['default']['default']['tcr'] = {
          'switch' : '-pdk_grid_tcr',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Temperature Coefficent',
          'param_help' : "pdk grid stackvar layervar tcr <num>",
          'example': ["""cli: -pdk_grid_tcr 'M10 m2 0.1'""",
                      "api: chip.set('pdk','grid','M10','m2','tcr',"
                      "'0.1')"],
          'help' : """
          Specifies the temperature coefficient of resistance of the wire 
          defined by the grid width and spacing values in the 'grid' 
          structure. The value is specifed in %/ deg C. The number is only
          meant to be used as a sanity check and for coarse design planning. 
          Accurate analysis should use the PEX models.
          """
      }
  
      cfg['pdk']['tapmax'] = {
          'switch' : '-pdk_tapmax',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [], 
          'short_help' : 'Tap Cell Max Distance Rule',
          'param_help' : "pdk tapmax <num>",
          'example': ["""cli: -pdk_tapmax 100""",
                      """api: chip.set('pdk', 'tapmax','100')"""],
          'help' : """
          Maximum distance allowed between tap cells in the PDK. The value is 
          required for automated place and route and is entered in micrometers.
          """
      }
  
      cfg['pdk']['tapoffset'] = {
          'switch' : '-pdk_tapoffset',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Tap Cell Offset Rule',
          'param_help' : "pdk tapoffset <num>",
          'example': ["""cli: -pdk_tapoffset 100""",
                      """api: chip.set('pdk, 'tapoffset','100')"""],
          'help' : """
          Offset from the edge of the block to the tap cell grid. 
          The value is required for automated place and route and is entered in 
          micrometers.
          """
      }
  
      return cfg
  
  ###############################################################################
  # Library Configuration
  ###############################################################################
  
  def schema_libs(cfg, group):
  
      cfg[group] = {}
  
      cfg[group]['default'] = {}
        
      cfg[group]['default']['rev'] = {
          'switch' : '-'+group+'_rev',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' :  group.capitalize() + ' Release Revision',
          'param_help' : group+" libvar rev <str>",
          'example': ["cli: -"+group+"_rev 'mylib 1.0'",
                      "api: chip.set('"+group+"','mylib','rev','1.0')"],
          'help' : """ 
          String specifying revision on a per library basis. Verification of 
          correct PDK and IP revisions is an ASIC tapeout requirement in all 
          commercial foundries.
          """
      }
  
      cfg[group]['default']['origin'] = {
          'switch' : '-'+group+'_origin',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' :  group.capitalize() + ' Origin',
          'param_help' : group+" libvar origin <str>",
          'example': ["cli: -"+group+"_origin 'mylib US'",
                      "api: chip.set('"+group+"','mylib','origin','US')"],
          'help' : """
          String specifying library country of origin.
          """
      }
  
      cfg[group]['default']['license'] = {
          'switch' : '-'+group+'_license',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' :  group.capitalize() + ' License File',
          'param_help' : group+" libvar license <file>",
          'example': ["cli: -"+group+"_license 'mylib ./LICENSE'",
                      "api: chip.set('"+group+"','mylib','license','./LICENSE')"],
          'help' : """
          Filepath to library license
          """        
      }
      
      cfg[group]['default']['doc'] = {
          'switch' : '-'+group+'_doc',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Documentation',
          'param_help' : group+" libvar doc <file>",
          'example': ["cli: -"+group+"_doc 'lib lib_guide.pdf'",
                      "api: chip.set('"+group+"','lib','doc','lib_guide.pdf"],
          'help' : """
          A list of critical library documents entered in order of importance. 
          The first item in thelist should be the primary library user guide. 
          The  purpose of the list is to serve as a central record for all
          must-read PDK documents
          """
      }
  
      cfg[group]['default']['datasheet'] = {
          'switch' : '-'+group+"_datasheet",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Datasheets',
          'param_help' : group+" libvar datasheet <file>",
          'example': ["cli: -"+group+"_datasheet 'lib lib_ds.pdf'",
                      "api: chip.set('"+group+"','lib','datasheet','lib_ds.pdf/"],
          'help' : """
          A complete collection of library datasheets. The documentation can be
          provied as a PDF or as a filepath to a directory with one HTMl file 
          per cell. This parameter is optional for libraries where the datsheet
          is merged within the library integration document.
          """
      }
  
      cfg[group]['default']['libtype'] = {
          'switch' : '-'+group+'_libtype',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Type',
          'param_help' : group+" libvar libtype <str>",
          'example': ["cli: -"+group+"_libtype 'mylib 12t'",
                      "api: chip.set('"+group+"','mylib','libtype', '12t'"],
          'help' : """
          Libtype is a a unique string that identifies the row height or
          performance class of the library for APR. The libtype must match up
          with the name used in the pdk_aprtech dictionary. Mixing of libtypes
          in a flat place and route block is not allowed.
          """
      }
  
      cfg[group]['default']['width'] = {
          'switch' : '-'+group+'_width',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Width',
          'param_help' : group+" libvar width <num>",
          'example': ["cli: -"+group+"_width 'mylib 0.1'",
                      "api: chip.set('"+group+"','mylib','width', '0.1'"],
          
          'help' : """
          Specifies the width of a unit cell. The value can usually be
          extracted automatically from the layout library but is included in the
          schema to simplify the process of creating parametrized floorplans.
          """
      }
  
      cfg[group]['default']['height'] = {
          'switch' : '-'+group+'_height',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Height',
          'param_help' : group+" libvar height <num>",
          'example': ["cli: -"+group+"_height 'mylib 1.0'",
                      "api: chip.set('"+group+"','mylib','height', '1.0'"],
          'help' : """
          Specifies the height of a unit cell. The value can usually be
          extracted automatically from the layout library but is included in the
          schema to simplify the process of creating parametrized floorplans.
          """
      }
      
      ###############################
      #Models (Timing, Power, Noise)
      ###############################
  
      cfg[group]['default']['model'] = {}
      cfg[group]['default']['model']['default'] = {}
  
      #Operating Conditions (per corner)
      cfg[group]['default']['model']['default']['opcond'] = {
          'switch' : '-'+group+"_opcond",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Operating Condition',
          'param_help' : group+" libvar model cornervar opcond <str>",
          'example':["cli: -"+group+"_opcond 'lib model ss_1.0v_125c WORST'",
                     "api: chip.add('"+group+"','lib','model','ss_1.0v_125c',"
                     "'opcond', 'WORST'"],
          'help' : """
          The default operating condition to use for mcmm optimization and
          signoff on a per corner basis.
          """
      }
          
      #Checks To Do (per corner)
      cfg[group]['default']['model']['default']['check'] = {
          'switch' : '-'+group+"_check",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Corner Checks',
          'param_help' : group+" libvar model cornervar check <str>",
          'example':["cli: -"+group+"_check 'lib model ss_1.0v_125c setup'",
                     "api: chip.add('"+group+"','lib','model','ss_1.0v_125c',"
                     "'check', 'setup'"],
          'help' : """
          Per corner checks to perform during optimization and STA signoff.
          Names used in the 'mcmm' scenarios must align with the 'check' names
          used in this dictionary. The purpose of the dictionary is to serve as 
          a serve as a central record for the PDK/Library recommended corner 
          methodology and all PVT timing corners supported. Standard 'check' 
          values include setup, hold, power, noise, reliability but can be 
          extended based on eda support and methodology.
          """
      }
          
      #NLDM
      cfg[group]['default']['model']['default']['nldm'] = {}
      cfg[group]['default']['model']['default']['nldm']['default'] = {        
          'switch' : '-'+group+"_nldm",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' NLDM Timing Model',
          'param_help' : group+" libvar model cornervar nldm typevar <file>",
          'example':["cli: -"+group+"_nldm 'lib model ss gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss','nldm',"
                     "'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to NLDM models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
      }
  
      #CCS
      cfg[group]['default']['model']['default']['ccs'] = {}
      cfg[group]['default']['model']['default']['ccs']['default'] = {        
          'switch' : '-'+group+"_ccs",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' CCS Timing Model',
          'param_help' : group+" libvar model cornervar ccs typevar <file>",
          'example':["cli: -"+group+"_ccs 'lib model ss lib.gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss','ccs',"
                     "'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to CCS models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
       }
  
      #SCM
      cfg[group]['default']['model']['default']['scm'] = {}
      cfg[group]['default']['model']['default']['scm']['default'] = {        
          'switch' : '-'+group+"_scm",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' SCM Timing Model',
          'param_help' : group+" libvar model cornervar scm typevar <file>",
          'example':["cli: -"+group+"_scm 'lib model ss lib.gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss', 'scm',"
                     "'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to SCM models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
      }
          
      #AOCV
      cfg[group]['default']['model']['default']['aocv'] = {        
          'switch' : '-'+group+"_aocv",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' AOCV Timing Model',
          'param_help' : group+" libvar model cornervar aocv <file>",
          'example':["cli: -"+group+"_aocv 'lib model ss lib.aocv'",
                     "api: chip.add('"+group+"','lib','model','ss', 'aocv',"
                     "'lib_ss.aocv'"],
          'help': """
          Filepaths to AOCV models. Timing files are specified on a per lib,
          per corner basis. 
          """
      }
  
      #APL
      cfg[group]['default']['model']['default']['apl'] = {}
      cfg[group]['default']['model']['default']['apl']['default'] = {        
          'switch' : '-'+group+"_apl",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' APL Power Model',
          'param_help' : group+" libvar model cornervar apl typevar <file>",
          'example':["cli: -"+group+"_apl 'lib model ss cdev lib_tt.cdev'",
                     "api: chip.add('"+group+"','lib','model','ss','apl','cdev',"
                     "'lib_tt.cdev'"],
          'help' : """
          Filepaths to APL power models. Power files are specified on a per
          lib, per corner, and per format basis.
          """
      }
  
      #LEF
      cfg[group]['default']['lef'] = {
          'switch' : '-'+group+"_lef",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' LEF',
          'param_help' : group+" libvar lef <file>",
          'example':["cli: -"+group+"_lef 'mylib mylib.lef'",
                     "api: chip.add('"+group+"','mylib','lef','mylib.lef')"],
          'help' : """
          An abstracted view of library cells that gives a complete description
          of the cell's place and route boundary, pin positions, pin metals, and
          metal routing blockages.
          """
      }
      
      #GDS
      cfg[group]['default']['gds'] = {
          'switch' : '-'+group+"_gds",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' GDS',
          'param_help' : group+" libvar gds <file>",
          'example':["cli: -"+group+"_gds 'mylib mylib.gds'",
                     "api: chip.add('"+group+"','mylib','gds','mylib.gds')"],
          'help' : """
          The complete mask layout of the library cells ready to be merged with
          the rest of the design for tapeout. In some cases, the GDS merge 
          happens at the foundry, so inclusion of CDL files is optional. In all 
          cases, where the CDL are available they should specified here to 
          enable LVS checks pre tapout                                     
          """
      }
  
      cfg[group]['default']['cdl'] = {
          'switch' : '-'+group+"_cdl",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' CDL Netlist',
          'param_help' : group+" libvar cdl <file>",
          'example':["cli: -"+group+"_cdl 'mylib mylib.cdl'",
                     "api: chip.add('"+group+"','mylib','cdl','mylib.cdl')"],
          'help' : """
          Files containing the netlists used for layout versus schematic (LVS)
          checks. In some cases, the GDS merge happens at the foundry, so
          inclusion of a CDL file is optional. In all cases, where the CDL
          files are available they should specified here to enable LVS checks
          pre tapout
          """                                                          
      }
      cfg[group]['default']['spice'] = {}
      cfg[group]['default']['spice']['default'] = {
          'switch' : '-'+group+"_spice",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Spice Netlist',
          'param_help' : group+" libvar spice format <file>",
          'example':["cli: -"+group+"_spice 'mylib pspice mylib.sp'",
                     "api: chip.add('"+group+"','mylib','spice', 'pspice',"
                     "'mylib.sp')"],
          'help' : """
          Files containing library spice netlists used for circuit 
          simulation, specified on a per format basis. 
          """
      }
      cfg[group]['default']['hdl'] = {}
      cfg[group]['default']['hdl']['default'] = {
          'switch' : '-'+group+"_hdl",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' HDL Model',
          'param_help' : group+" libvar hdl formatvar <file>",
          'example':["cli: -"+group+"_hdl 'mylib verilog mylib.v'",
                     "api: chip.add('"+group+"','mylib','hdl', 'verilog',"
                     "'mylib.v')"],
          'help' : """
          Library HDL models, specifed on a per format basis. Examples
          of legal formats include Verilog,  VHDL.
          """
      }
      
      cfg[group]['default']['atpg'] = {
          'switch' : '-'+group+"_atpg",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' ATPG Model',
          'param_help' : group+" libvar atpg <file>",
          'example':["cli: -"+group+"_atpg 'mylib atpg mylib.atpg'",
                     "api: chip.add('"+group+"','mylib','atpg','mylib.atpg')"],
          'help' : """
          Library models used for ATPG based automated faultd based post
          manufacturing testing.                                        
          """
      }
  
      cfg[group]['default']['pgmetal'] = {
          'switch' : '-'+group+"_pgmetal",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Power/Ground Layer',
          'param_help' : group+" libvar pgmetal <str>",
          'example':["cli: -"+group+"_pgmetal 'mylib m1'",
                     "api: chip.add('"+group+"','mylib','pgmetal','m1')"],
          'help' : """
          Specifies the top metal layer used for power and ground routing within
          the library. The parameter can be used to guide cell power grid hookup
          by APR tools.
          """
      }
  
      cfg[group]['default']['tag'] = {
          'switch' : '-'+group+"_tag",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Identifier Tags',
          'param_help' : group+" libvar tag <str>",
          'example':["cli: -"+group+"_tag 'mylib virtual'",
                     "api: chip.add('"+group+"','mylib','tag','virtual')"],
          'help' : """
          Marks a library with a set of tags that can be used by the designer
          and EDA tools for optimization purposes. The tags are meant to cover
          features not currently supported by built in EDA optimization flows,
          but which can be queried through EDA tool TCL commands and lists.
          The example below demonstrates tagging the whole library as virtual.
          """
      }
  
      cfg[group]['default']['driver'] = {
          'switch' : '-'+group+"_driver",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Default Driver Cell',
          'param_help' : group+" libvar driver <str>",
          'example':["cli: -"+group+"_driver 'mylib BUFX1'",
                     "api: chip.add('"+group+"','mylib','driver','BUFX1')"],
          'help' : """
          The name of a library cell to be used as the default driver for
          block timing constraints. The cell should be strong enough to drive
          a block input from another block including wire capacitance.
          In cases where the actual driver is known, the actual driver cell
          should be used.
          """
      }
  
      cfg[group]['default']['site'] = {
          'switch' : '-'+group+"_site",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Site/Tile Name',
          'param_help' : group+" libvar site <str>",
          'example':["cli: -"+group+"_site 'mylib core'",
                     "api: chip.add('"+group+"','mylib','site','core')"],
          'help' : """
          Provides the primary site name to use for placement.
          """
      }
  
      cfg[group]['default']['cells'] = {}
      cfg[group]['default']['cells']['default'] = {
          'switch' : '-'+group+"_cells",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Cell Lists',
          'param_help' : group+" libvar cells groupvar <str>",
          'example':["cli: -"+group+"_cells 'mylib dontuse *eco*'",
                     "api: chip.add('"+group+"','mylib','cells','dontuse',"
                     "'*eco*')"],
          'help' : """
          A named list of cells grouped by a property that can be accessed
          directly by the designer and EDA tools. The example below shows how
          all cells containing the string 'eco' could be marked as dont use
          for the tool.
          """
      }
  
      cfg[group]['default']['layoutdb'] = {}
      cfg[group]['default']['layoutdb']['default'] = {}
      cfg[group]['default']['layoutdb']['default']['default'] = {
          'switch' : '-'+group+"_layoutdb",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Layout Database',
          'param_help' : group+" libvar layoutdb stackvar formatvar <file>",
          'example':["cli: -"+group+"_layoutdb 'mylib M10 oa /disk/mylibdb'",
                     "api: chip.add('"+group+"','mylib','layoutdb','M10',"
                     "'oa', '/disk/mylibdb')"],
          'help' : """
          Filepaths to compiled library layout database specified on a per format
          basis. Example formats include oa, mw, ndm.
          """
      }
  
      return cfg
  
  ###############################################################################
  # Flow Configuration
  ###############################################################################
  
  def schema_flow(cfg, step):
  
      if not 'flow' in cfg:
          cfg['flow'] = {}    
      cfg['flow'][step] = {}
  
      
      # Used to define flow sequence
      cfg['flow'][step]['input'] = {
          'switch' : '-flow_input',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Excution Dependency',
          'param_help' : "flow stepvar input <str>",
          'example': ["cli: -flow_input 'cts place'",                    
                      "api:  chip.set('flow', 'cts', 'input', 'place'"],
          'help' : """
          Specifies the list of inputs dependanices to start 'step' execution.
          """
      }
  
      # exe
      cfg['flow'][step]['exe'] = {
          'switch' : '-flow_exe',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Executable Name',
          'param_help' : "flow stepvar exe <str>",
          'example': ["cli: -flow_exe 'cts openroad'",                    
                      "api:  chip.set('flow', 'cts', 'exe', 'openroad'"],
          'help' : """
          The name of the exuctable step or the full path to the executable 
          specified on a per step basis.
          """
      }
      
      # exe version    
      cfg['flow'][step]['version'] = {
          'switch' : '-flow_version',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Executable Version',
          'param_help' : "flow stepvar version <str>",
          'example': ["cli: -flow_version 'cts 1.0'",                    
                      "api:  chip.set('flow', 'cts', 'version', '1.0'"],
          'help' : """
          The version of the executable step to use in compilation.Mismatch 
          between the step specifed and the step avalable results in an error.
          """
      }
      
      #opt
      cfg['flow'][step]['option'] = {
          'switch' : '-flow_opt',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Executable Options',
          'param_help' : "flow stepvar option <str>",
          'example': ["cli: -flow_opt 'cts -no_init'",                    
                      "api:  chip.set('flow', 'cts', 'opt', '-no_init'"],
          'help' : """
          A list of command line options for the executable. For multiple 
          argument options, enter each argument and value as a one list entry, 
          specified on a per step basis. Command line values must be enclosed in 
          quotes.
          """
      }
      
      #refdir
      cfg['flow'][step]['refdir'] = {
          'switch' : '-flow_refdir',
          'type' : 'dir',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Reference Directory',
          'param_help' : "flow stepvar refdir <file>",
          'example': ["cli: -flow_refdir 'cts ./myrefdir'",                    
                      "api:  chip.set('flow', 'cts', 'refdir', './myrefdir'"],
          'help' : """
          A path to a directory containing compilation scripts used by the 
          executable specified on a per step basis.
          """
      }
      
      #entry point script
      cfg['flow'][step]['script'] = {
          'switch' : '-flow_script',
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],   
          'short_help' : 'Entry Point script',
          'param_help' : "flow stepvar script <file>",
          'example': ["cli: -flow_script 'cts /myrefdir/cts.tcl'",
                      "api: chip.set('flow','cts','script','/myrefdir/cts.tcl'"],
          'help' : """
          Path to the entry point compilation script called by the executable 
          specified on a per step basis.
          """
      }
  
      #copy
      cfg['flow'][step]['copy'] = {
          'switch' : '-flow_copy',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Copy Local Option',
          'param_help' : "flow stepvar copy <bool>",
          'example': ["cli: -flow_copy 'cts true'",
                      "
  
  [... the rest is omitted ...]
files: siliconcompiler/schema.py
files: # Copyright 2020 Silicon Compiler Authors. All Rights Reserved.
  
  import re
  import os
  import textwrap
  import sys
  
  ###############################################################################
  # CHIP CONFIGURATION
  ###############################################################################
  
  def schema_cfg():
      '''Method for defining Chip configuration schema
      All the keys defined in this dictionary are reserved words.
      '''
  
      cfg = {}
  
      # Flow Setup (from schema_options)
      cfg = schema_flow(cfg, 'default')
  
      # Metric Tracking
      cfg = schema_metrics(cfg, 'goal')
      cfg = schema_metrics(cfg, 'real')    
      
      # Recording design provenance 
      cfg = schema_record(cfg) 
      
      # FPGA Parameters
      cfg = schema_fpga(cfg)
  
      # ASIC Parameters
      cfg = schema_pdk(cfg)
      cfg = schema_asic(cfg) 
      cfg = schema_libs(cfg, 'stdcell')
      cfg = schema_libs(cfg, 'macro')
  
      # Designer's Choice
      cfg = schema_design(cfg)
      cfg = schema_mcmm(cfg)
      
      # Designer Runtime options
      cfg = schema_options(cfg)
  
      # Remote options
      cfg = schema_remote(cfg)
      
      # Run status
      cfg = schema_status(cfg)
      
      return cfg
  
  
  ###############################################################################
  # CHIP LIBRARY 
  ###############################################################################
  def schema_lib():
      pass    
  
  ###############################################################################
  # CHIP LAYOUT
  ###############################################################################
  def schema_layout():
      
      layout = {}
  
      layout = schema_lef(layout)
  
      layout = schema_def(layout)
  
      return layout
  
  ###############################################################################
  # UTILITY FUNCTIONS TIED TO SC SPECIFICATIONS
  ###############################################################################
  
  def schema_path(filename):
      ''' Resolves file paths using SCPATH and resolve environment variables
      starting with $
      '''
  
      #Resolve absolute path usign SCPATH
      #list is read left to right    
      scpaths = str(os.environ['SCPATH']).split(':')
      for searchdir in scpaths:        
          abspath = searchdir + "/" + filename
          if os.path.exists(abspath):
              filename = abspath
              break
      #Replace $ Variables
      varmatch = re.match('^\$(\w+)(.*)', filename)
      if varmatch:
          var = varmatch.group(1)
          varpath = os.getenv(var)
          if varpath is None:
              print("ERROR: Missing environment variable:", var)
              sys.exit()
          relpath = varmatch.group(2)
          filename = varpath + relpath
          
      return filename
              
  def schema_istrue(value):
      ''' Checks schema boolean string and returns Python True/False
      '''
      boolean = value[-1].lower()
      if boolean == "true":
          return True
      else:
          return False
  
  def schema_check(cfg, leafkey, value):
      ''' Checks that leaf cell value agrees with type 
      '''
  
      ok = True
      keyval = "(Key,value) = (" + leafkey +  ",'" + ' '.join(value) + "')"
      if cfg['type'] == 'bool':
          if value[0] not in ('true', 'false'):
              print("ERROR: Value should be boolan.", keyval)
              ok = False
      else:
          for item in value:            
              if cfg['type'] == 'str':
                  ok =  isinstance(item, str)
                  if not ok:
                      print("ERROR: Value should be a string.", keyval)
              elif cfg['type'] == 'num':
                  try:
                      isinstance(float(item), float)
                  except:
                      ok = False
                      print("ERROR: Value should be a number.", keyval)
              elif cfg['type'] == 'file':
                  ok =  os.path.isfile(schema_path(item))
                  if not ok:
                      print("ERROR: File is missing.", keyval)
              elif cfg['type'] == 'dir':
                  ok =  os.path.isdir(schema_path(item))
                  if not ok:
                      print("ERROR: Directory is missing.", keyval)
  
      return ok
  
  
  def schema_reorder_keys(param_help, item):
      ''' Returns a keylist used to access the dictionary based on the 
      cmdline switch argument and the param_help field.
      '''
  
      #Split param help into keys and data based in <>
      m = re.search('(.*?)(<.*)',param_help)
      paramlist = m.group(1).split()
      datalist = m.group(2).split()
      #Split cmdline inputn based on spaces
      itemlist = item.split()
      
      depth = len(paramlist)+1
      args = [None] * depth
  
      #Combine keys from param_help and cmdline field
      j=0
      for i in range(depth-1):
          if paramlist[i].endswith('var'):
              args[i]=itemlist[j]
              j=j+1
          else:
              args[i]=paramlist[i]
  
      #Insert data field as last entry (some are string tuples)
      args[-1] = itemlist[-len(datalist):]
      
      return args
  
      
  ###############################################################################
  # FPGA
  ###############################################################################
  
  def schema_fpga(cfg):
      ''' FPGA Setup
      '''
      cfg['fpga'] = {}
  
      cfg['fpga']['xml'] = {
          'switch' : '-fpga_xml',
          'requirement' : 'fpga',
          'type' : 'file',        
          'lock' : 'false',
          'copy' : 'true',        
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'FPGA Architecture File',
          'param_help' : "fpga xml <file>",
          'example': ["cli: -fpga_xml myfpga.xml",                    
                      "api:  chip.set('fpga', 'xml', 'myfpga.xml')"],
          'help' : """
          Provides an XML-based architecture description for the target FPGA
          architecture to be used in VTR, allowing targeting a large number of 
          virtual and commercial architectures.
          [More information...](https://verilogtorouting.org)
          """
      }
  
      cfg['fpga']['vendor'] = {
          'switch' : '-fpga_vendor',
          'requirement' : '!fpga_xml',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'FPGA Vendor Name',
          'param_help' : "fpga vendor <str>",
          'example': ["cli: -fpga_vendor acme",                    
                      "api:  chip.set('fpga', 'vendor', 'acme')"],
          'help' : """
          Name of the FPGA vendor for non-VTR based compilation
          """
      }
  
      cfg['fpga']['device'] = {
          'switch' : '-fpga_device',
          'requirement' : '!fpga_xml',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'FPGA Device Name',
          'param_help' : "fpga device <str>",
          'example': ["cli: -fpga_device fpga64k",                    
                      "api:  chip.set('fpga', 'device', 'fpga64k')"],
          'help' : """
          Name of the FPGA device for non-VTR based compilation
          """
      }
  
      return cfg
  
  ###############################################################################
  # PDK
  ###############################################################################
  
  def schema_pdk(cfg):
      ''' Process Design Kit Setup
      '''
      cfg['pdk'] = {}
      cfg['pdk']['foundry'] = {
          'switch' : '-pdk_foundry',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Foundry Name',
          'param_help' : "pdk foundry <str>",
          'example': ["cli: -pdk_foundry virtual",                    
                      "api:  chip.set('pdk', 'foundry', 'virtual')"],
          'help' : """
          The name of the foundry. For example: intel, gf, tsmc, "samsung, 
          skywater, virtual. The \'virtual\' keyword is reserved for simulated 
          non-manufacturable processes such as freepdk45 and asap7.              
          """        
      }
  
      cfg['pdk']['process'] = {
          'switch' : '-pdk_process',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Name',
          'param_help' : "pdk process <str>",
          'example': ["cli: -pdk_process asap7",                    
                      "api:  chip.set('pdk', 'process', 'asap7')"],
          'help' : """
          The official public name of the foundry process. The name is case 
          insensitive, but should otherwise match the complete public process 
          name from the foundry. Example process names include 22ffl from Intel,
          12lpplus from Globalfoundries, and 16ffc from TSMC.        
          """
      }
  
      cfg['pdk']['node'] = {
          'switch' : '-pdk_node',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Node',
          'param_help' : "pdk node <num>",
          'example': ["cli: -pdk_node 130",                    
                      "api:  chip.set('pdk', 'node', '130')"],
          'help' : """
          An approximate relative minimum dimension of the process node. A 
          required parameter in some reference flows that leverage the value to 
          drive technology dependent synthesis and APR optimization. Node 
          examples include 180nm, 130nm, 90nm, 65nm, 45nm, 32nm, 22nm, 14nm, 
          10nm, 7nm, 5nm, 3nm. The value entered implies nanometers.
          """
      }
  
      cfg['pdk']['wafersize'] = {
          'switch' : '-pdk_wafersize',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Size',
          'param_help' : "pdk wafersize <num>",
          'example': ["cli: -pdk_wafersize 300",                    
                      "api:  chip.set('pdk', 'wafersize', '300')"],
          'help' : """
          Specifies the wafer diameter for the process in mm.
          """
      }
  
      cfg['pdk']['wafercost'] = {
          'switch' : '-pdk_wafercost',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Cost',
          'param_help' : "pdk wafercost <num>",
          'example': ["cli: -pdk_wafercost 10000",                    
                      "api:  chip.set('pdk', 'wafercost', '10000')"],
          'help' : """
          Specifies the raw cost per wafer purchased in USD, not 
          accounting for yield loss.
          """
      }
  
      cfg['pdk']['d0'] = {
          'switch' : '-pdk_d0',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Defect Density',
          'param_help' : "pdk d0 <num>",
          'example': ["cli: -pdk_d0 0.1",                    
                      "api:  chip.set('pdk', 'd0', '0.1')"],
          'help' : """
          Process defect density (D0) expressed as random defects per cm^2.
          """
      }
      
      cfg['pdk']['hscribe'] = {
          'switch' : '-pdk_hscribe',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Horizontal Scribeline',
          'param_help' : "pdk hscribe <num>",
          'example': ["cli: -pdk_hscribe 0.1",                    
                      "api:  chip.set('pdk', 'hscribe', '0.1')"],
          'help' : """
          Specifies the width of the horizontal scribe line in mm.
          """
      }
  
      cfg['pdk']['vscribe'] = {
          'switch' : '-pdk_vscribe',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Horizontal Scribeline',
          'param_help' : "pdk vscribe <num>",
          'example': ["cli: -pdk_vscribe 0.1",                    
                      "api:  chip.set('pdk', 'vscribe', '0.1')"],
          'help' : """
          Specifies the width of the vertical scribe line in mm.
          """
      }
      
      cfg['pdk']['edgemargin'] = {
          'switch' : '-pdk_edgemargin',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Wafer Edge Margin',
          'param_help' : "pdk edgemargin <num>",
          'example': ["cli: -pdk_edgemargin 1",                    
                      "api:  chip.set('pdk', 'edgemargin', '1')"],
          'help' : """
          Specifies keepout distance/margin (in mm) from the wafer edge 
          where no dies can be placed.
          """
      }
      
      cfg['pdk']['density'] = {
          'switch' : '-pdk_density',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Transistor Density',
          'param_help' : "pdk density <num>",
          'example': ["cli: -pdk_density 100e6",                    
                      "api:  chip.set('pdk', 'density', '10e6')"],
          'help' : """
          An approximate logic density expressed as # transistors / mm^2
          calculated as:
          0.6 * (Nand2 Transistor Count) / (Nand2 Cell Area) +
          0.4 * (Register Transistor Count) / (Register Cell Area)
          """
      }
  
      cfg['pdk']['sramsize'] = {
          'switch' : '-pdk_sramsize',
          'requirement' : 'asic',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process SRAM Bitcell Size',
          'param_help' : "pdk sramsize <num>",
          'example': ["cli: -pdk_sramsize 0.032",                    
                      "api:  chip.set('pdk', 'sramcell', '0.026')"],
          'help' : """
          The area an SRAM bitcell expressed in um^2. 
          """
      }
  
      cfg['pdk']['rev'] = {
          'switch' : '-pdk_rev',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Revision',
          'param_help' : "pdk rev <str>",
          'example': ["cli: -pdk_rev 1.0",                    
                      "api:  chip.set('pdk', 'rev', '1.0')"],
          'help' : """
          An alphanumeric string specifying the revision  of the current PDK. 
          Verification of correct PDK and IP revisions revisions is an ASIC 
          tapeout requirement in all commercial foundries.
          """
      }
      
      cfg['pdk']['drm'] = {
          'switch' : '-pdk_drm',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],        
          'short_help' : 'PDK Design Rule Manual',
          'param_help' : "pdk drm <file>",
          'example': ["cli: -pdk_drm asap7_drm.pdf",                    
                      "api:  chip.set('pdk', 'drm', 'asap7_drm.pdf')"],
          'help' : """
          A PDK document that includes complete information about physical and 
          electrical design rules to comply with in the design and layout of the 
          chip. In cases where the user guides and design rules are combined into
          a single document, the pdk_doc parameter can be left blank.
          """
      }
  
      cfg['pdk']['doc'] = {
          'switch' : '-pdk_doc',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'PDK Documents',
          'param_help' : "pdk doc <file>",
          'example': ["cli: -pdk_doc asap7_userguide.pdf",                    
                      "api: chip.add('pdk', 'doc', 'asap7_userguide.pdf')"],
          'help' : """
          A list of critical PDK designer documents provided by the foundry 
          entered in order of priority. The first item in the list should be the
          primary PDK user guide. The purpose of the list is to serve as a 
          central record for all must-read PDK documents.
          """
      }
          
      cfg['pdk']['stackup'] = {
          'switch' : '-pdk_stackup',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Process Metal Stackups',
          'param_help' : "pdk stackup <str>",
          'example': ["cli: -pdk_stackup 2MA4MB2MC",                    
                      "api: chip.add('pdk', 'stackup', '2MA4MB2MC')"],
          'help' : """
          A list of all metal stackups offered in the process node. Older process
          nodes may only offer a single metal stackup, while advanced nodes 
          offer a large but finite list of metal stacks with varying combinations
          of metal line pitches and thicknesses. Stackup naming is unqiue to a 
          foundry, but is generally a long string or code. For example, a 10 
          metal stackup two 1x wide, four 2x wide, and 4x wide metals, might be
          identified as 2MA4MB2MC. Each stackup will come with its own set of 
          routing technology files and parasitic models specified in the 
          pdk_pexmodel and pdk_aprtech parameters.
          """
      }
  
      cfg['pdk']['devicemodel'] = {}
      cfg['pdk']['devicemodel']['default'] = {}
      cfg['pdk']['devicemodel']['default']['default'] = {}
      cfg['pdk']['devicemodel']['default']['default']['default'] = {
          'switch' : '-pdk_devicemodel',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Device Models',
          'param_help' : "pdk devicemodel stackvar typevar toolvar <file>",
          'example': ["""cli: -pdk_devicemodel 'M10 spice xyce asap7.sp'""",
                      """api: chip.add('pdk','devicemodel','M10','spice','xyce',
                      'asap7.sp')"""],
          'help' : """
          Filepaths for all PDK device models. The structure serves as a central 
          access registry for models for different purpose and tools. Examples of
          device model types include spice, aging, electromigration, radiation. 
          An example of a spice tool is xyce.
          """
      }
  
      cfg['pdk']['pexmodel'] = {}
      cfg['pdk']['pexmodel']['default'] = {}
      cfg['pdk']['pexmodel']['default']['default']= {}
      cfg['pdk']['pexmodel']['default']['default']['default'] = {
          'switch' : '-pdk_pexmodel',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Parasitic TCAD Models',
          'param_help' : "pdk pexmodel stackvar cornervar toolvar <file>",
          'example': ["""cli: -pdk_pexmodel 'M10 max fastcap wire.mod'""",
                      """api: chip.add('pdk','pexmodel','M10','max','fastcap'
                      'wire.mod')"""],
          'help' : """
          Filepaths for all PDK wire TCAD models. The structure serves as a 
          central access registry for models for different purpose and tools. 
          Examples of RC extraction corners include: min, max, nominal. An 
          example of an extraction tool is FastCap.
          """
      }
  
      cfg['pdk']['layermap'] = {}
      cfg['pdk']['layermap']['default'] = {}
      cfg['pdk']['layermap']['default']['default'] = {}
      cfg['pdk']['layermap']['default']['default']['default'] = {
          'switch' : '-pdk_layermap',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date' : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Mask Layer Maps',
          'param_help' : "pdk layermap stackvar srcvar dstvar <file>",
          'example': ["""cli: -pdk_layermap 'M10 klayout gds asap7.map'""",
                      """api: chip.add('pdk','layermap','M10','klayout','gds'
                      'asap7.map')"""],
          'help' : """
          Files describing input/output mapping for streaming layout data from 
          one format to another. A foundry PDK will include an official layer 
          list for all user entered and generated layers supported in the GDS 
          accepted by the foundry for processing, but there is no standardized 
          layer definition format that can be read and written by all EDA tools.
          To ensure mask layer matching, key/value type mapping files are needed
          to convert EDA databases to/from GDS and to convert between different
          types of EDA databases.
          """
      }
  
      cfg['pdk']['display'] = {}
      cfg['pdk']['display']['default'] = {}
      cfg['pdk']['display']['default']['default'] = {}
      cfg['pdk']['display']['default']['default']['default'] = {
          'switch' : '-pdk_display',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date' : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Display Configurations',
          'param_help' : "pdk display stackvar toolvar formatvar <file>",
          'example': ["""cli: -pdk_display 'M10 klayout python display.lyt'""",
                      """api: chip.add('pdk', display','M10','klayout','python'
                      'display.cfg')"""],
          'help' : """
          Display configuration files describing colors and pattern schemes for
          all layers in the PDK. The display configuration file is entered on a 
          stackup and per tool basis.
          """
      }
  
      cfg['pdk']['plib'] = {}
      cfg['pdk']['plib']['default'] = {}
      cfg['pdk']['plib']['default']['default'] = {}
      cfg['pdk']['plib']['default']['default']['default']= {
          'switch' : '-pdk_plib',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'Primitive Libraries',
          'param_help' : "pdk plib stackvar toolvar formatvar <file>",
          'example': ["""cli: -pdk_plib 'M10 klayout oa /disk/asap7/oa/devlib'""",
                      """api: chip.add('pdk','plib','M10', 'klayout', 'oa', 
                      '/disk/asap7/oa/devlib')"""],
          'help' : """
          Filepaths to all primitive cell libraries supported by the PDK. The 
          filepaths are entered on a per stackup and per format basis.
          """
      }
  
      cfg['pdk']['aprtech'] = {}
      cfg['pdk']['aprtech']['default'] = {}
      cfg['pdk']['aprtech']['default']['default'] = {}
      cfg['pdk']['aprtech']['default']['default']['default'] = {
          'switch' : '-pdk_aprtech',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : 'APR Technology File',
          'param_help' : "pdk aprtech stackvar libtypevar filetypevar <file>",
          'example': ["""cli: -pdk_aprtech 'M10 12t lef tech.lef'""",
                      """api: chip.add('pdk','aprtech','M10','12t','lef',
                      'tech.lef')"""],
          'help' : """
          Technology file containing the design rule and setup information needed
          to enable DRC clean automated placement a routing. The file is 
          specified on a per stackup, libtype, and format basis, where libtype 
          generates the library architecture (e.g. library height). For example a
          PDK with support for 9 and 12 track libraries might have libtypes 
          called 9t and 12t.
          """
      }
  
      cfg['pdk']['grid'] = {}
      cfg['pdk']['grid']['default'] = {}
      cfg['pdk']['grid']['default']['default'] = {}    
  
      #Name Map
      cfg['pdk']['grid']['default']['default']['name'] = {
          'switch' : '-pdk_grid_name',
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Name Map',
          'param_help' : "pdk grid stackvar layervar name <str>",
          'example': ["""cli: -pdk_grid_name 'M10 m1 metal1'""",
                      """api: chip.add('pdk', 'grid', 'M10', 'm1', 'name',
                      'metal1')"""],
          'help' : """
          Defines the hardcoded PDK metal name on a per stackup and per metal 
          basis. Metal layers are ordered from m1 to mn, where m1 is the lowest
          routing layer in the tech.lef.
          """
      }
      # Vertical Grid
      cfg['pdk']['grid']['default']['default']['xpitch'] = {
          'switch' : '-pdk_grid_xpitch',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Horizontal Grid',
          'param_help' : "pdk grid stackvar layervar xpitch <num>",
          'example': ["""cli: -pdk_grid_xpitch 'M10 m1 0.5'""",
                      """api: chip.add('pdk','grid','M10','m1','xpitch',
                      '0.5')"""],
          'help' : """
          Defines the vertical routing grid on a a per stackup and per metal 
          basis. Values are specified in um. Metal layers are ordered from m1 to 
          mn, where m1 is the lowest routing layer in the tech.lef.        
          """
      }
  
      # Horizontal Grid
      cfg['pdk']['grid']['default']['default']['ypitch'] = {
          'switch' : '-pdk_grid_ypitch',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Vertical Grid',
          'param_help' : "pdk grid stackvar layervar ypitch <num>'",
          'example': ["""cli: -pdk_grid_ypitch 'M10 m2 0.5'""",
                      """api: chip.add('pdk','grid','M10','m2','ypitch',
                      '0.5')"""],
          'help' : """
          Defines the horizontal routing grid on a a per stackup and per metal 
          basis. Values are specified in um. Metal layers are ordered from m1 to
          mn, where m1 is the lowest routing layer in the tech.lef.
          """
      }
      
      # Vertical Grid Offset
      cfg['pdk']['grid']['default']['default']['xoffset'] = {
          'switch' : '-pdk_grid_xoffset',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Preferred Direction',
          'param_help' : "pdk grid stackvar layervar xoffset <num>",
          'example': ["""cli: -pdk_grid_xoffset 'M10 m2 0.5'""",
                      """api: chip.add('pdk','grid','M10','m2','xoffset',
                      '0.5')"""],
          'help' : """
          Defines the horizontal grid offset of a metal layer specified on a per 
          stackup and per metal basis. Values are specified in um.
          """
      }
      
      # Horizontal Grid Offset
      cfg['pdk']['grid']['default']['default']['yoffset'] = {
          'switch' : '-pdk_grid_yoffset',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Preferred Direction',
          'param_help' : "pdk grid stackvar layervar yoffset <num>",
          'example': ["""cli: -pdk_grid_yoffset 'M10 m2 0.5'""",
                      """api: chip.add('pdk','grid','M10','m2','yoffset',
                      '0.5')"""],
          'help' : """
          Defines the horizontal grid offset of a metal layer specified on a per 
          stackup and per metal basis. Values are specified in um.
          """
      }
  
      # Routing Layer Adjustment
      cfg['pdk']['grid']['default']['default']['adj'] = {
          'switch' : '-pdk_grid_adj',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Adjustment',
          'param_help' : "pdk grid stackvar layervar adj <num>",
          'example': ["""cli: -pdk_grid_adj 'M10 m2 0.5'""",
                      """api: chip.set('pdk','grid','M10','m2','adj',
                      '0.5')"""],
          'help' : """
          Defines the routing resources adjustments for the design on a per layer
          basis. The value is expressed as a fraction from 0 to 1. A value of
          0.5 reduces the routing resources by 50%.
          """
      }
  
      # Routing Layer Capacitance
      cfg['pdk']['grid']['default']['default']['cap'] = {
          'switch' : '-pdk_grid_cap',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Layer Capacitance',
          'param_help' : "pdk grid stackvar layervar cap <num>",
          'example': ["""cli: -pdk_grid_cap 'M10 m2 0.2'""",
                      """api: chip.set('pdk','grid','M10','m2','cap',
                      '0.2')"""],
          'help' : """
          Specifies the unit capacitance of a wire defined by the grid
          width and spacing values in the 'grid' structure.  The
          value is specifed as ff/um. The number is only meant to be used 
          as a sanity check and for coarse design planning. Accurate 
          analysis should use the PEX models.
          """
      }
  
      # Routing Layer Resistance
      cfg['pdk']['grid']['default']['default']['res'] = {
          'switch' : '-pdk_grid_res',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Routing Layer Resistance',
          'param_help' : "pdk grid stackvar layervar res <num>",
          'example': ["""cli: -pdk_grid_res 'M10 m2 0.2'""",
                      """api: chip.set('pdk','grid','M10','m2','res',
                      '0.2')"""],
          'help' : """
          Specifies the resistance  of a wire defined by the grid
          width and spacing values in the 'grid' structure.  The
          value is specifed as ohms/um. The number is only meant to be 
          used as a sanity check and for coarse design planning. Accurate 
          analysis should use the PEX models.
          """
      }
  
      # Wire Temperature Coefficient
      cfg['pdk']['grid']['default']['default']['tcr'] = {
          'switch' : '-pdk_grid_tcr',
          'requirement' : 'optional',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Grid Layer Temperature Coefficent',
          'param_help' : "pdk grid stackvar layervar tcr <num>",
          'example': ["""cli: -pdk_grid_tcr 'M10 m2 0.1'""",
                      """api: chip.set('pdk','grid','M10','m2','tcr',
                      '0.1')"""],
          'help' : """
          Specifies the temperature coefficient of resistance of the wire 
          defined by the grid width and spacing values in the 'grid' 
          structure. The value is specifed in %/ deg C. The number is only
          meant to be used as a sanity check and for coarse design planning. 
          Accurate analysis should use the PEX models.
          """
      }
  
      cfg['pdk']['tapmax'] = {
          'switch' : '-pdk_tapmax',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [], 
          'short_help' : 'Tap Cell Max Distance Rule',
          'param_help' : "pdk tapmax <num>",
          'example': ["""cli: -pdk_tapmax 100""",
                      """api: chip.set('pdk', 'tapmax','100')"""],
          'help' : """
          Maximum distance allowed between tap cells in the PDK. The value is 
          required for automated place and route and is entered in micrometers.
          """
      }
  
      cfg['pdk']['tapoffset'] = {
          'switch' : '-pdk_tapoffset',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : 'Tap Cell Offset Rule',
          'param_help' : "pdk tapoffset <num>",
          'example': ["""cli: -pdk_tapoffset 100""",
                      """api: chip.set('pdk, 'tapoffset','100')"""],
          'help' : """
          Offset from the edge of the block to the tap cell grid. 
          The value is required for automated place and route and is entered in 
          micrometers.
          """
      }
  
      return cfg
  
  ###############################################################################
  # Library Configuration
  ###############################################################################
  
  def schema_libs(cfg, group):
  
      cfg[group] = {}
  
      cfg[group]['default'] = {}
        
      cfg[group]['default']['rev'] = {
          'switch' : '-'+group+'_rev',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' :  group.capitalize() + ' Release Revision',
          'param_help' : group+" libvar rev <str>",
          'example': ["cli: -"+group+"_rev 'mylib 1.0'",
                      "api: chip.set('"+group+"','mylib','rev','1.0')"],
          'help' : """ 
          String specifying revision on a per library basis. Verification of 
          correct PDK and IP revisions is an ASIC tapeout requirement in all 
          commercial foundries.
          """
      }
  
      cfg[group]['default']['origin'] = {
          'switch' : '-'+group+'_origin',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' :  group.capitalize() + ' Origin',
          'param_help' : group+" libvar origin <str>",
          'example': ["cli: -"+group+"_origin 'mylib US'",
                      "api: chip.set('"+group+"','mylib','origin','US')"],
          'help' : """
          String specifying library country of origin.
          """
      }
  
      cfg[group]['default']['license'] = {
          'switch' : '-'+group+'_license',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' :  group.capitalize() + ' License File',
          'param_help' : group+" libvar license <file>",
          'example': ["cli: -"+group+"_license 'mylib ./LICENSE'",
                      "api: chip.set('"+group+"','mylib','license','./LICENSE')"],
          'help' : """
          Filepath to library license
          """        
      }
      
      cfg[group]['default']['doc'] = {
          'switch' : '-'+group+'_doc',
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Documentation',
          'param_help' : group+" libvar doc <file>",
          'example': ["cli: -"+group+"_doc 'lib lib_guide.pdf'",
                      "api: chip.set('"+group+"','lib','doc','lib_guide.pdf"],
          'help' : """
          A list of critical library documents entered in order of importance. 
          The first item in thelist should be the primary library user guide. 
          The  purpose of the list is to serve as a central record for all
          must-read PDK documents
          """
      }
  
      cfg[group]['default']['datasheet'] = {
          'switch' : '-'+group+"_datasheet",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Datasheets',
          'param_help' : group+" libvar datasheet <file>",
          'example': ["cli: -"+group+"_datasheet 'lib lib_ds.pdf'",
                      "api: chip.set('"+group+"','lib','datasheet','lib_ds.pdf/"],
          'help' : """
          A complete collection of library datasheets. The documentation can be
          provied as a PDF or as a filepath to a directory with one HTMl file 
          per cell. This parameter is optional for libraries where the datsheet
          is merged within the library integration document.
          """
      }
  
      cfg[group]['default']['libtype'] = {
          'switch' : '-'+group+'_libtype',
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Type',
          'param_help' : group+" libvar libtype <str>",
          'example': ["cli: -"+group+"_libtype 'mylib 12t'",
                      "api: chip.set('"+group+"','mylib','libtype', '12t'"],
          'help' : """
          Libtype is a a unique string that identifies the row height or
          performance class of the library for APR. The libtype must match up
          with the name used in the pdk_aprtech dictionary. Mixing of libtypes
          in a flat place and route block is not allowed.
          """
      }
  
      cfg[group]['default']['width'] = {
          'switch' : '-'+group+'_width',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Width',
          'param_help' : group+" libvar width <num>",
          'example': ["cli: -"+group+"_width 'mylib 0.1'",
                      "api: chip.set('"+group+"','mylib','width', '0.1'"],
          
          'help' : """
          Specifies the width of a unit cell. The value can usually be
          extracted automatically from the layout library but is included in the
          schema to simplify the process of creating parametrized floorplans.
          """
      }
  
      cfg[group]['default']['height'] = {
          'switch' : '-'+group+'_height',
          'requirement' : 'apr',
          'type' : 'num',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Height',
          'param_help' : group+" libvar height <num>",
          'example': ["cli: -"+group+"_height 'mylib 1.0'",
                      "api: chip.set('"+group+"','mylib','height', '1.0'"],
          'help' : """
          Specifies the height of a unit cell. The value can usually be
          extracted automatically from the layout library but is included in the
          schema to simplify the process of creating parametrized floorplans.
          """
      }
      
      ###############################
      #Models (Timing, Power, Noise)
      ###############################
  
      cfg[group]['default']['model'] = {}
      cfg[group]['default']['model']['default'] = {}
  
      #Operating Conditions (per corner)
      cfg[group]['default']['model']['default']['opcond'] = {
          'switch' : '-'+group+"_opcond",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Operating Condition',
          'param_help' : group+" libvar model cornervar opcond <str>",
          'example':["cli: -"+group+"_opcond 'lib model ss_1.0v_125c WORST'",
                     "api: chip.add('"+group+"','lib','model','ss_1.0v_125c', \
                     'opcond', 'WORST'"],
          'help' : """
          The default operating condition to use for mcmm optimization and
          signoff on a per corner basis.
          """
      }
          
      #Checks To Do (per corner)
      cfg[group]['default']['model']['default']['check'] = {
          'switch' : '-'+group+"_check",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Corner Checks',
          'param_help' : group+" libvar model cornervar check <str>",
          'example':["cli: -"+group+"_check 'lib model ss_1.0v_125c setup'",
                     "api: chip.add('"+group+"','lib','model','ss_1.0v_125c', \
                     'check', 'setup'"],
          'help' : """
          Per corner checks to perform during optimization and STA signoff.
          Names used in the 'mcmm' scenarios must align with the 'check' names
          used in this dictionary. The purpose of the dictionary is to serve as 
          a serve as a central record for the PDK/Library recommended corner 
          methodology and all PVT timing corners supported. Standard 'check' 
          values include setup, hold, power, noise, reliability but can be 
          extended based on eda support and methodology.
          """
      }
          
      #NLDM
      cfg[group]['default']['model']['default']['nldm'] = {}
      cfg[group]['default']['model']['default']['nldm']['default'] = {        
          'switch' : '-'+group+"_nldm",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' NLDM Timing Model',
          'param_help' : group+" libvar model cornervar nldm typevar <file>",
          'example':["cli: -"+group+"_nldm 'lib model ss gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss','nldm', \
                     'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to NLDM models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
      }
  
      #CCS
      cfg[group]['default']['model']['default']['ccs'] = {}
      cfg[group]['default']['model']['default']['ccs']['default'] = {        
          'switch' : '-'+group+"_ccs",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' CCS Timing Model',
          'param_help' : group+" libvar model cornervar ccs typevar <file>",
          'example':["cli: -"+group+"_ccs 'lib model ss lib.gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss','ccs', \
                     'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to CCS models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
       }
  
      #SCM
      cfg[group]['default']['model']['default']['scm'] = {}
      cfg[group]['default']['model']['default']['scm']['default'] = {        
          'switch' : '-'+group+"_scm",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' SCM Timing Model',
          'param_help' : group+" libvar model cornervar scm typevar <file>",
          'example':["cli: -"+group+"_scm 'lib model ss lib.gz ss.lib.gz'",
                     "api: chip.add('"+group+"','lib','model','ss', 'scm', \
                     'gz', 'ss.lib.gz'"],
          'help' : """
          Filepaths to SCM models. Timing files are specified on a per lib,
          per corner, and per format basis. The format is driven by EDA tool
          requirements. Examples of legal formats includ: lib, gz, bz2, 
          and ldb.            
          """
      }
          
      #AOCV
      cfg[group]['default']['model']['default']['aocv'] = {        
          'switch' : '-'+group+"_aocv",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' AOCV Timing Model',
          'param_help' : group+" libvar model cornervar aocv <file>",
          'example':["cli: -"+group+"_aocv 'lib model ss lib.aocv'",
                     "api: chip.add('"+group+"','lib','model','ss', 'aocv', \
                     'lib_ss.aocv'"],
          'help': """
          Filepaths to AOCV models. Timing files are specified on a per lib,
          per corner basis. 
          """
      }
  
      #APL
      cfg[group]['default']['model']['default']['apl'] = {}
      cfg[group]['default']['model']['default']['apl']['default'] = {        
          'switch' : '-'+group+"_apl",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' APL Power Model',
          'param_help' : group+" libvar model cornervar apl typevar <file>",
          'example':["cli: -"+group+"_apl 'lib model ss cdev lib_tt.cdev'",
                     "api: chip.add('"+group+"','lib','model','ss','apl','cdev',\
                     'lib_tt.cdev'"],
          'help' : """
          Filepaths to APL power models. Power files are specified on a per
          lib, per corner, and per format basis.
          """
      }
  
      #LEF
      cfg[group]['default']['lef'] = {
          'switch' : '-'+group+"_lef",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' LEF',
          'param_help' : group+" libvar lef <file>",
          'example':["cli: -"+group+"_lef 'mylib mylib.lef'",
                     "api: chip.add('"+group+"','mylib','lef','mylib.lef')"],
          'help' : """
          An abstracted view of library cells that gives a complete description
          of the cell's place and route boundary, pin positions, pin metals, and
          metal routing blockages.
          """
      }
      
      #GDS
      cfg[group]['default']['gds'] = {
          'switch' : '-'+group+"_gds",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' GDS',
          'param_help' : group+" libvar gds <file>",
          'example':["cli: -"+group+"_gds 'mylib mylib.gds'",
                     "api: chip.add('"+group+"','mylib','gds','mylib.gds')"],
          'help' : """
          The complete mask layout of the library cells ready to be merged with
          the rest of the design for tapeout. In some cases, the GDS merge 
          happens at the foundry, so inclusion of CDL files is optional. In all 
          cases, where the CDL are available they should specified here to 
          enable LVS checks pre tapout                                     
          """
      }
  
      cfg[group]['default']['cdl'] = {
          'switch' : '-'+group+"_cdl",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' CDL Netlist',
          'param_help' : group+" libvar cdl <file>",
          'example':["cli: -"+group+"_cdl 'mylib mylib.cdl'",
                     "api: chip.add('"+group+"','mylib','cdl','mylib.cdl')"],
          'help' : """
          Files containing the netlists used for layout versus schematic (LVS)
          checks. In some cases, the GDS merge happens at the foundry, so
          inclusion of a CDL file is optional. In all cases, where the CDL
          files are available they should specified here to enable LVS checks
          pre tapout
          """                                                          
      }
      cfg[group]['default']['spice'] = {}
      cfg[group]['default']['spice']['default'] = {
          'switch' : '-'+group+"_spice",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Spice Netlist',
          'param_help' : group+" libvar spice format <file>",
          'example':["cli: -"+group+"_spice 'mylib pspice mylib.sp'",
                     "api: chip.add('"+group+"','mylib','spice', 'pspice',\
                     'mylib.sp')"],
          'help' : """
          Files containing library spice netlists used for circuit 
          simulation, specified on a per format basis. 
          """
      }
      cfg[group]['default']['hdl'] = {}
      cfg[group]['default']['hdl']['default'] = {
          'switch' : '-'+group+"_hdl",
          'requirement' : 'asic',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' HDL Model',
          'param_help' : group+" libvar hdl formatvar <file>",
          'example':["cli: -"+group+"_hdl 'mylib verilog mylib.v'",
                     "api: chip.add('"+group+"','mylib','hdl', 'verilog',\
                     'mylib.v')"],
          'help' : """
          Library HDL models, specifed on a per format basis. Examples
          of legal formats include Verilog,  VHDL.
          """
      }
      
      cfg[group]['default']['atpg'] = {
          'switch' : '-'+group+"_atpg",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' ATPG Model',
          'param_help' : group+" libvar atpg <file>",
          'example':["cli: -"+group+"_atpg 'mylib atpg mylib.atpg'",
                     "api: chip.add('"+group+"','mylib','atpg','mylib.atpg')"],
          'help' : """
          Library models used for ATPG based automated faultd based post
          manufacturing testing.                                        
          """
      }
  
      cfg[group]['default']['pgmetal'] = {
          'switch' : '-'+group+"_pgmetal",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Power/Ground Layer',
          'param_help' : group+" libvar pgmetal <str>",
          'example':["cli: -"+group+"_pgmetal 'mylib m1'",
                     "api: chip.add('"+group+"','mylib','pgmetal','m1')"],
          'help' : """
          Specifies the top metal layer used for power and ground routing within
          the library. The parameter can be used to guide cell power grid hookup
          by APR tools.
          """
      }
  
      cfg[group]['default']['tag'] = {
          'switch' : '-'+group+"_tag",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Identifier Tags',
          'param_help' : group+" libvar tag <str>",
          'example':["cli: -"+group+"_tag 'mylib virtual'",
                     "api: chip.add('"+group+"','mylib','tag','virtual')"],
          'help' : """
          Marks a library with a set of tags that can be used by the designer
          and EDA tools for optimization purposes. The tags are meant to cover
          features not currently supported by built in EDA optimization flows,
          but which can be queried through EDA tool TCL commands and lists.
          The example below demonstrates tagging the whole library as virtual.
          """
      }
  
      cfg[group]['default']['driver'] = {
          'switch' : '-'+group+"_driver",
          'requirement' : 'asic',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Default Driver Cell',
          'param_help' : group+" libvar driver <str>",
          'example':["cli: -"+group+"_driver 'mylib BUFX1'",
                     "api: chip.add('"+group+"','mylib','driver','BUFX1')"],
          'help' : """
          The name of a library cell to be used as the default driver for
          block timing constraints. The cell should be strong enough to drive
          a block input from another block including wire capacitance.
          In cases where the actual driver is known, the actual driver cell
          should be used.
          """
      }
  
      cfg[group]['default']['site'] = {
          'switch' : '-'+group+"_site",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Site/Tile Name',
          'param_help' : group+" libvar site <str>",
          'example':["cli: -"+group+"_site 'mylib core'",
                     "api: chip.add('"+group+"','mylib','site','core')"],
          'help' : """
          Provides the primary site name to use for placement.
          """
      }
  
      cfg[group]['default']['cells'] = {}
      cfg[group]['default']['cells']['default'] = {
          'switch' : '-'+group+"_cells",
          'requirement' : 'optional',
          'type' : 'str',
          'lock' : 'false',
          'defvalue' : [],
          'short_help' : group.capitalize() + ' Cell Lists',
          'param_help' : group+" libvar cells groupvar <str>",
          'example':["cli: -"+group+"_cells 'mylib dontuse *eco*'",
                     "api: chip.add('"+group+"','mylib','cells','dontuse', \
                     '*eco*')"],
          'help' : """
          A named list of cells grouped by a property that can be accessed
          directly by the designer and EDA tools. The example below shows how
          all cells containing the string 'eco' could be marked as dont use
          for the tool.
          """
      }
  
      cfg[group]['default']['layoutdb'] = {}
      cfg[group]['default']['layoutdb']['default'] = {}
      cfg[group]['default']['layoutdb']['default']['default'] = {
          'switch' : '-'+group+"_layoutdb",
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash'   : [],
          'date'   : [],
          'author' : [],
          'signature' : [],
          'short_help' : group.capitalize() + ' Layout Database',
          'param_help' : group+" libvar layoutdb stackvar formatvar <file>",
          'example':["cli: -"+group+"_layoutdb 'mylib M10 oa /disk/mylibdb'",
                     "api: chip.add('"+group+"','mylib','layoutdb','M10', \
                     'oa', '/disk/mylibdb')"],
          'help' : """
          Filepaths to compiled library layout database specified on a per format
          basis. Example formats include oa, mw, ndm.
          """
      }
  
      return cfg
  
  ###############################################################################
  # Flow Configuration
  ###############################################################################
  
  def schema_flow(cfg, step):
  
      if not 'flow' in cfg:
          cfg['flow'] = {}    
      cfg['flow'][step] = {}
  
      
      # Used to define flow sequence
      cfg['flow'][step]['input'] = {
          'switch' : '-flow_input',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Excution Dependency',
          'param_help' : "flow stepvar input <str>",
          'example': ["cli: -flow_input 'cts place'",                    
                      "api:  chip.set('flow', 'cts', 'input', 'place'"],
          'help' : """
          Specifies the list of inputs dependanices to start 'step' execution.
          """
      }
  
      # exe
      cfg['flow'][step]['exe'] = {
          'switch' : '-flow_exe',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Executable Name',
          'param_help' : "flow stepvar exe <str>",
          'example': ["cli: -flow_exe 'cts openroad'",                    
                      "api:  chip.set('flow', 'cts', 'exe', 'openroad'"],
          'help' : """
          The name of the exuctable step or the full path to the executable 
          specified on a per step basis.
          """
      }
      
      # exe version    
      cfg['flow'][step]['version'] = {
          'switch' : '-flow_version',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'all',
          'defvalue' : [],
          'short_help' : 'Executable Version',
          'param_help' : "flow stepvar version <str>",
          'example': ["cli: -flow_version 'cts 1.0'",                    
                      "api:  chip.set('flow', 'cts', 'version', '1.0'"],
          'help' : """
          The version of the executable step to use in compilation.Mismatch 
          between the step specifed and the step avalable results in an error.
          """
      }
      
      #opt
      cfg['flow'][step]['option'] = {
          'switch' : '-flow_opt',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Executable Options',
          'param_help' : "flow stepvar option <str>",
          'example': ["cli: -flow_opt 'cts -no_init'",                    
                      "api:  chip.set('flow', 'cts', 'opt', '-no_init'"],
          'help' : """
          A list of command line options for the executable. For multiple 
          argument options, enter each argument and value as a one list entry, 
          specified on a per step basis. Command line values must be enclosed in 
          quotes.
          """
      }
      
      #refdir
      cfg['flow'][step]['refdir'] = {
          'switch' : '-flow_refdir',
          'type' : 'dir',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Reference Directory',
          'param_help' : "flow stepvar refdir <file>",
          'example': ["cli: -flow_refdir 'cts ./myrefdir'",                    
                      "api:  chip.set('flow', 'cts', 'refdir', './myrefdir'"],
          'help' : """
          A path to a directory containing compilation scripts used by the 
          executable specified on a per step basis.
          """
      }
      
      #entry point script
      cfg['flow'][step]['script'] = {
          'switch' : '-flow_script',
          'requirement' : 'optional',
          'type' : 'file',
          'lock' : 'false',
          'copy' : 'false',
          'defvalue' : [],
          'hash' : [],
          'date'   : [],
          'author' : [],
          'signature' : [],   
          'short_help' : 'Entry Point script',
          'param_help' : "flow stepvar script <file>",
          'example': ["cli: -flow_script 'cts /myrefdir/cts.tcl'",
                      "api: chip.set('flow','cts','script','/myrefdir/cts.tcl'"],
          'help' : """
          Path to the entry point compilation script called by the executable 
          specified on a per step basis.
          """
      }
  
      #copy
      cfg['flow'][step]['copy'] = {
          'switch' : '-flow_copy',
          'type' : 'str',
          'lock' : 'false',
          'requirement' : 'optional',
          'defvalue' : [],
          'short_help' : 'Copy Local Option',
          'param_help' : "flow stepvar copy <bool>",
          'example': ["cli: -flow_copy 'cts true'",
                      "api
  
  [... the rest is omitted ...]
files: siliconcompiler/schema.py