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')"],
          '
  
  [... 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')"""],
          '
  
  [... the rest is omitted ...]
files: siliconcompiler/schema.py