diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2019-03-16 11:42:28 +0100 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2019-03-16 11:42:28 +0100 |
commit | fa5f10625f102fd0e62e867b8074d4477fb59e04 (patch) | |
tree | 13646a0f5200390eac5f542486fd9c8e88d564ea /scripts | |
parent | 521ec5e010477a8db7b7af93f279b514e7358610 (diff) |
Imported version 1.3.12
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/drc.sh | 2 | ||||
-rwxr-xr-x | scripts/gdsii.sh | 2 | ||||
-rwxr-xr-x | scripts/makesim.sh | 2 | ||||
-rwxr-xr-x | scripts/migrate.sh | 2 | ||||
-rw-r--r-- | scripts/qflow.sh.in | 20 | ||||
-rwxr-xr-x | scripts/qflow_manager.py.in | 112 | ||||
-rwxr-xr-x | scripts/spi2xspice.py.in | 185 | ||||
-rwxr-xr-x | scripts/synthesize.sh | 12 |
8 files changed, 229 insertions, 108 deletions
diff --git a/scripts/drc.sh b/scripts/drc.sh index 2e5bccb..509e2c8 100755 --- a/scripts/drc.sh +++ b/scripts/drc.sh @@ -173,7 +173,7 @@ drc check drc catchup set dcount [drc list count total] puts stdout "drc = \$dcount" -quit -noprompt +quit EOF #------------------------------------------------------------------ diff --git a/scripts/gdsii.sh b/scripts/gdsii.sh index 57899af..d6ea267 100755 --- a/scripts/gdsii.sh +++ b/scripts/gdsii.sh @@ -145,7 +145,7 @@ load $rootname select top cell expand gds write $rootname -quit -noprompt +quit EOF #------------------------------------------------------------------ diff --git a/scripts/makesim.sh b/scripts/makesim.sh index 6bbc91f..db3af36 100755 --- a/scripts/makesim.sh +++ b/scripts/makesim.sh @@ -28,7 +28,7 @@ box 0 0 0 0 load ${cellname} extract all ext2sim -quit -noprompt +quit EOF exit 0 ;# Return normal exit status diff --git a/scripts/migrate.sh b/scripts/migrate.sh index 40ee6fa..9924a85 100755 --- a/scripts/migrate.sh +++ b/scripts/migrate.sh @@ -237,7 +237,7 @@ ext2spice blackbox on ext2spice subcircuit top auto ext2spice global off ext2spice -quit -noprompt +quit EOF #------------------------------------------------------------------ diff --git a/scripts/qflow.sh.in b/scripts/qflow.sh.in index a7e1370..8bbdbfb 100644 --- a/scripts/qflow.sh.in +++ b/scripts/qflow.sh.in @@ -56,6 +56,7 @@ set dodisplay=0 while ($#argv > 0) switch($argv[1]:q) + case -t: case -T: case --tech: shift @@ -64,17 +65,20 @@ while ($#argv > 0) shift breaksw case -p: + case -P: case --project: shift set project=$argv[1] shift breaksw case -h: + case -H: case --help: set dohelp=1 shift breaksw case -v: + case -V: case --version: set doversion=1 shift @@ -188,11 +192,17 @@ while ($#argv > 0) shift breaksw default: - if ($modulename != "") then + if (`echo $argv[1] | cut -c1` == "-") then + echo "Unknown option $argv[1]" + set dohelp=1 break - else + else if ($modulename == "") then set modulename=$argv[1] shift + else + echo "Argument $argv[1] after module name $modulename" + set dohelp=1 + break endif breaksw endsw @@ -468,6 +478,12 @@ if ( ! -f ${userfile} ) then echo \# set postproc_options = >> ${userfile} endif + if ( ${?xspice_options} ) then + echo \# set xspice_options = \"${xspice_options}\" >> ${userfile} + else + echo \# set xspice_options = >> ${userfile} + endif + if ( ${?fill_ratios} ) then echo \# set fill_ratios = \"${fill_ratios}\" >> ${userfile} else diff --git a/scripts/qflow_manager.py.in b/scripts/qflow_manager.py.in index d169f39..6860871 100755 --- a/scripts/qflow_manager.py.in +++ b/scripts/qflow_manager.py.in @@ -1166,8 +1166,8 @@ class QflowManager(ttk.Frame): if not self.magicgtype: mproc = subprocess.Popen([qflow_bin_dir + '/magic', '-d', '0', '-noconsole'], - stdout = subprocess.PIPE, stderr = subprocess.PIPE, - universal_newlines = True) + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, universal_newlines = True) magicpair = mproc.communicate(timeout=1) if 'graphics' in self.prefs: self.magicgtype = self.prefs['graphics'] @@ -1185,8 +1185,8 @@ class QflowManager(ttk.Frame): if not self.magicversion: mproc = subprocess.Popen([qflow_bin_dir + '/magic', '-dnull', '-noconsole', '--version'], - stdout = subprocess.PIPE, stderr = subprocess.PIPE, - universal_newlines = True) + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, universal_newlines = True) magicpair = mproc.communicate(timeout=1) self.magicversion = magicpair[0].splitlines()[0] self.print('Magic version is ' + self.magicversion) @@ -1697,7 +1697,7 @@ class QflowManager(ttk.Frame): # for output from vesta. sta_ok = False is_not_vesta = False - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Design meets minimum' in line: sta_ok = True @@ -1707,7 +1707,7 @@ class QflowManager(ttk.Frame): break if is_not_vesta: sta_ok = True - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'VIOLATED' in line: sta_ok = False @@ -1743,7 +1743,7 @@ class QflowManager(ttk.Frame): # DEF file exists, but did all routes get completed? logfile = self.logdir + '/route.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Final: Failed net routes:' in line: self.print('Status: log file reports unrouted nets.') @@ -1778,7 +1778,7 @@ class QflowManager(ttk.Frame): # for vesta or MET or VIOLATED for OpenSTA and OpenTimer is_not_vesta = False sta_ok = False - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Design meets minimum' in line: sta_ok = True @@ -1788,7 +1788,7 @@ class QflowManager(ttk.Frame): break if is_not_vesta: sta_ok = True - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'VIOLATED' in line: sta_ok = False @@ -1844,7 +1844,7 @@ class QflowManager(ttk.Frame): if os.path.exists(logfile): statbuf = os.stat(logfile) if statbuf.st_mtime >= stime: - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'No DRC errors' in line: stime = statbuf.st_mtime @@ -1926,7 +1926,7 @@ class QflowManager(ttk.Frame): if os.path.exists(logfile): statbuf = os.stat(logfile) if statbuf.st_mtime >= stime: - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'No DRC errors' in line: stime = statbuf.st_mtime @@ -2541,12 +2541,13 @@ class QflowManager(ttk.Frame): self.toppane.checklist.synth_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.synth_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' synthesize') + self.print('Running: qflow synthsize ' + self.project) self.update_idletasks() failed = False - self.qflowproc = subprocess.Popen(['qflow', self.project, 'synthesize'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'synthesize', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) synthdir = self.synthdir filename = synthdir + '/' + self.project + '.spc' try: @@ -2579,7 +2580,7 @@ class QflowManager(ttk.Frame): self.toppane.checklist.place_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.place_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' place') + self.print('Running: qflow place ' + self.project) self.update_idletasks() failed = False @@ -2596,8 +2597,9 @@ class QflowManager(ttk.Frame): self.pinmanager.writepads(cel2file) # Run the qflow placement script - self.qflowproc = subprocess.Popen(['qflow', self.project, 'place'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'place', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = layoutdir + '/' + self.project + '.def' try: statbuf = os.stat(filename) @@ -2629,14 +2631,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.timing_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.timing_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' sta') + self.print('Running: qflow sta ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'sta'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'sta', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.logdir + '/sta.log' try: statbuf = os.stat(filename) @@ -2670,7 +2673,7 @@ class QflowManager(ttk.Frame): self.toppane.checklist.route_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.route_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' route') + self.print('Running: qflow route ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh @@ -2684,8 +2687,9 @@ class QflowManager(ttk.Frame): if os.path.exists(unroute): shutil.copy(unroute, filename) - self.qflowproc = subprocess.Popen(['qflow', self.project, 'route'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'route', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) try: statbuf = os.stat(filename) except: @@ -2716,14 +2720,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.backanno_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.backanno_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' backanno') + self.print('Running: qflow backanno ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'backanno'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'backanno', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.logdir + '/post_sta.log' try: statbuf = os.stat(filename) @@ -2757,14 +2762,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.migrate_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.migrate_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' migrate') + self.print('Running: qflow migrate ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'migrate'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'migrate', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.layoutdir + '/' + self.project + '.spice' try: statbuf = os.stat(filename) @@ -2803,14 +2809,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.drc_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.drc_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' drc') + self.print('Running: qflow drc ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'drc'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'drc', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.logdir + '/drc.log' try: statbuf = os.stat(filename) @@ -2849,14 +2856,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.lvs_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.lvs_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' lvs') + self.print('Running: qflow lvs ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'lvs'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'lvs', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.logdir + '/lvs.log' try: statbuf = os.stat(filename) @@ -2895,14 +2903,15 @@ class QflowManager(ttk.Frame): self.toppane.checklist.gds_result.configure(text="In progress", style='normal.TButton') self.toppane.checklist.gds_run.configure(text="Stop", style='normal.TButton') - self.print('Running: qflow ' + self.project + ' gdsii') + self.print('Running: qflow gdsii ' + self.project) self.update_idletasks() # Check for long format option and update project_vars.sh self.update_project_vars() - self.qflowproc = subprocess.Popen(['qflow', self.project, 'gdsii'], - stdout = subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 0, cwd = self.rootpath) + self.qflowproc = subprocess.Popen(['qflow', 'gdsii', self.project], + stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, bufsize = 0, cwd = self.rootpath) filename = self.logdir + '/gdsii.log' try: statbuf = os.stat(filename) @@ -3173,7 +3182,7 @@ class QflowManager(ttk.Frame): # Check if yosys reported an error logfile = self.logdir + '/synth.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Errors detected in verilog' in line: self.print("Failure to synthesize the verilog.") @@ -3208,7 +3217,7 @@ class QflowManager(ttk.Frame): # Check if placement errors stopped the synthesis flow. logfile = self.logdir + '/place.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("Place script failed with error condition (see log file).") @@ -3233,7 +3242,7 @@ class QflowManager(ttk.Frame): # Check if log/sta.log shows an error occurring logfile = self.logdir + '/sta.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("STA failed with error condition (see log file).") @@ -3265,7 +3274,7 @@ class QflowManager(ttk.Frame): # Check if qrouter reported failed routes logfile = self.logdir + '/route.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Final: Failed net routes:' in line: self.print("Route attempt resulted in failed routes.") @@ -3294,7 +3303,7 @@ class QflowManager(ttk.Frame): # Check if log/post_sta.log shows an error occurring logfile = self.logdir + '/post_sta.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("Post-route STA failed with error condition (see log file).") @@ -3326,7 +3335,7 @@ class QflowManager(ttk.Frame): # Check if log/migrate.log shows an error occurring logfile = self.logdir + '/migrate.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("Migration failed with error condition (see log file).") @@ -3358,7 +3367,7 @@ class QflowManager(ttk.Frame): # Check if log/drc.log shows an error occurring logfile = self.logdir + '/drc.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("DRC failed with error condition (see log file).") @@ -3390,7 +3399,7 @@ class QflowManager(ttk.Frame): # Check if log/lvs.log shows an error occurring logfile = self.logdir + '/lvs.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("LVS failed with error condition (see log file).") @@ -3422,7 +3431,7 @@ class QflowManager(ttk.Frame): # Check if log/gdsii.log shows an error occurring logfile = self.logdir + '/gdsii.log' if os.path.exists(logfile): - with open(logfile, 'r') as ifile: + with open(logfile, 'r', encoding='utf-8') as ifile: for line in ifile: if 'Synthesis flow stopped' in line: self.print("GDS generation failed with error condition (see log file).") @@ -3563,7 +3572,7 @@ class QflowManager(ttk.Frame): realpdkdir = os.path.realpath(pdkdir) else: realpdkdir = pdkdir - if testdir != pdkdir: + if testdir != realpdkdir: if self.status != 'begin' and self.status != 'prep': self.print('Error: Tech directory mismatch for technology ' + pdkrootname + ': ' + pdkdir + ' vs. ' + testdir, file=sys.stderr) self.check_reset(args=None) @@ -3765,16 +3774,17 @@ class QflowManager(ttk.Frame): sresult = select.select([self.qflowproc.stdout, self.qflowproc.stderr], [], [], 0)[0] + if not self.qflowproc.stdout in sresult and not self.qflowproc.stderr in sresult: + break + if self.qflowproc.stdout in sresult: outstring = self.qflowproc.stdout.readline().decode().strip() self.logprint(outstring, doflush=True) self.print(outstring) - elif self.qflowproc.stderr in sresult: + if self.qflowproc.stderr in sresult: errstring = self.qflowproc.stderr.readline().decode().strip() self.logprint(errstring, doflush = True) self.print(errstring, file=sys.stderr) - else: - break # If filename file is modified, then call the callback function; otherwise, restart the clock. try: diff --git a/scripts/spi2xspice.py.in b/scripts/spi2xspice.py.in index 92a3bf9..ac46f37 100755 --- a/scripts/spi2xspice.py.in +++ b/scripts/spi2xspice.py.in @@ -84,9 +84,15 @@ def read_spice_lib(filein, celldefs, debug): # Read to the ".ends" statement. insub = True -def write_models(cellsused, celldefs, ofile): +def write_models(cellsused, celldefs, ofile, timing): # Write the .model statement for all cells used + io_time = timing[0] + time = timing[1] + idelay = timing[2] + odelay = timing[3] + cload = timing[4] + imprex = re.compile('([10\)])[ \t]+([10\(])') primerex = re.compile('([10\)])[ \t]*\'') for cellname in cellsused: @@ -159,15 +165,15 @@ def write_models(cellsused, celldefs, ofile): if tabstr != '': if nout == 1: # General n-input LUT model - print('.model d_lut_' + cellname + ' d_lut (rise_delay=1n fall_delay=1n input_load=10f', file=ofile) + print('.model d_lut_' + cellname + ' d_lut (rise_delay=' + time + ' fall_delay=' + time + ' input_load=' + cload, file=ofile) print('+ table_values "' + tabstr + '")', file=ofile) if debug: print('Cell ' + cellname + ' has table ' + tabstr) else: # Even more general n-input, m-output LUT model - idelstr = ('2n ' * nin).strip() - ilodstr = ('1.0p ' * nin).strip() - odelstr = ('50n ' * nout).strip() + idelstr = ((idelay + ' ') * nin).strip() + ilodstr = ((cload + ' ') * nin).strip() + odelstr = ((odelay + ' ') * nout).strip() print('.model d_genlut_' + cellname + ' d_genlut (', file=ofile) print('+ rise_delay=[' + odelstr + ']', file=ofile) @@ -178,7 +184,7 @@ def write_models(cellsused, celldefs, ofile): else: print('No output for ' + cellname) -def read_spice(filein, fileout, celldefs, debug, modelfile): +def read_spice(filein, fileout, celldefs, debug, modelfile, timing): global vdd vddname = '{:g}'.format(vdd).replace('.', 'v') @@ -203,6 +209,7 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+)(.*)$', re.IGNORECASE) xrex = re.compile('^[ \t]*X([^ \t]+)(.*)$', re.IGNORECASE) comrex = re.compile('^[\*]+.*$', re.IGNORECASE) + specrex = re.compile('^[\*]+This file may contain array delimiters', re.IGNORECASE) endsrex = re.compile('^[^\*]*[ \t]*.ends.*$', re.IGNORECASE) endrex = re.compile('^[^\*]*[ \t]*.end.*$', re.IGNORECASE) @@ -240,13 +247,18 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): for line in spilines: lineno += 1 - # Substitute for all characters "<" and ">" - line = line.replace('<', '_').replace('>', '_') + # Substitute for all characters "[" and "]", to avoid nesting brackets. + line = line.replace('[', '_').replace(']', '_') + + # All comment lines go to the output, except catch the line generated + # by qflow scripts that says "This file may contain array delimiters", + # since we just scrubbed them, above. - # All comment lines go to the output cmatch = comrex.match(line) if cmatch: - print(line, file=ofile) + smatch = specrex.match(line) + if not smatch: + print(line, file=ofile) continue # If there is an include line, parse it and read the @@ -285,6 +297,18 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): print('Cell record is: ' + str(cellrec)) continue + if not 'type' in cellrec: + print('Cell ' + cellname + ' does not have a type defined!') + if debug: + print('Cell record is: ' + str(cellrec)) + # Provide defaults for the cell so that it doesn't cause failures + cellrec['type'] = 'unknown' + cellrec['function'] = [] + cellrec['inputs'] = [] + cellrec['outputs'] = [] + cellrec['nin'] = 0 + cellrec['nout'] = 0 + # Print the record. Special handling for flops and latches. if cellrec['type'] == 'flop': @@ -455,21 +479,25 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): else: inlist = [] outlist = [] - for subpin in cellrec['inputs']: - if subpin in cellrec['spicepins']: - i = cellrec['spicepins'].index(subpin) - # "pins[i]" is the name of the connecting net on the top level - inlist.append(pins[i]) - if pins[i] in pindefs: - pindefs[pins[i]] = 'input' - - for subpin in cellrec['outputs']: - if subpin in cellrec['spicepins']: - i = cellrec['spicepins'].index(subpin) - # "pins[i]" is the name of the connecting net on the top level - outlist.append(pins[i]) - if pins[i] in pindefs: - pindefs[pins[i]] = 'output' + if 'inputs' in cellrec: + for subpin in cellrec['inputs']: + if subpin in cellrec['spicepins']: + i = cellrec['spicepins'].index(subpin) + # "pins[i]" is the name of the connecting net + # on the top level + inlist.append(pins[i]) + if pins[i] in pindefs: + pindefs[pins[i]] = 'input' + + if 'outputs' in cellrec: + for subpin in cellrec['outputs']: + if subpin in cellrec['spicepins']: + i = cellrec['spicepins'].index(subpin) + # "pins[i]" is the name of the connecting net + # on the top level + outlist.append(pins[i]) + if pins[i] in pindefs: + pindefs[pins[i]] = 'output' intext = ' '.join(inlist) outtext = ' '.join(outlist) @@ -477,7 +505,10 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): if debug: print("Instance = " + instname + "; inputs = " + intext + "; outputs = " + outtext) - if len(inlist) == 0: + # Note: Cells with output but no input are tie-high or tie-low, + # and do not map to LUTs. Cells with no output are non-functional + # (e.g., antenna tie-downs). + if len(inlist) == 0 and len(outlist) == 1: if cellrec['function'][0] == '1': print('A' + instname + ' ' + outtext + ' done', file=ofile) elif cellrec['function'][0] == '0': @@ -486,7 +517,7 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): print("Cell " + cellname + " has no inputs and no constant function.") elif len(outlist) == 1: print('A' + instname + ' [' + intext + '] ' + outtext + ' d_lut_' + cellname, file=ofile) - else: + elif len(outlist) != 0: print('A' + instname + ' [' + intext + '] [' + outtext + '] d_genlut_' + cellname, file=ofile) continue @@ -537,26 +568,28 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): if modelfile != '': print(".include " + modelfile, file=ofile) else: - print(".model todig_" + vddname + " adc_bridge(in_high=" + vddthigh + " in_low=" + vddtlow + " rise_delay=10n fall_delay=10n)", file=ofile) + print(".model todig_" + vddname + " adc_bridge(in_high=" + vddthigh + " in_low=" + vddtlow + " rise_delay=" + io_time + " fall_delay=" + io_time + ")", file=ofile) print(".model toana_" + vddname + " dac_bridge(out_high=" + vddhigh + " out_low=0)", file=ofile) print("", file=ofile) # Write d_dff, d_dlatch, d_pullup, and d_pulldown models - print(".model ddflop d_dff(ic=0 rise_delay=1n fall_delay=1n)", file=ofile) - print(".model dzero d_pulldown(load=1p)", file=ofile) - print(".model done d_pullup(load=1p)", file=ofile) + print(".model ddflop d_dff(ic=0 rise_delay=" + time + " fall_delay=" + time + ")", file=ofile) + print(".model dzero d_pulldown(load=" + cload + ")", file=ofile) + print(".model done d_pullup(load=" + cload + ")", file=ofile) print("", file=ofile) # Write A-to-D and D-to-A bridges inum = 0 onum = 0 for pinname in pindefs: - if pindefs[pinname] == 'input': - inum += 1 - print("AA2D" + str(inum) + " [a_" + pinname + "] [" + pinname + "] todig_" + vddname, file=ofile) - elif pindefs[pinname] == 'output': + if pindefs[pinname] == 'output': onum += 1 print("AD2A" + str(onum) + " [" + pinname + "] [a_" + pinname + "] toana_" + vddname, file=ofile) + # (Previously 'input': this makes sure that even unused + # power and ground nets are not left floating.) + else: + inum += 1 + print("AA2D" + str(inum) + " [a_" + pinname + "] [" + pinname + "] todig_" + vddname, file=ofile) print("", file=ofile) echoout = True @@ -572,11 +605,11 @@ def read_spice(filein, fileout, celldefs, debug, modelfile): # At the end, write all of the LUT-based digital models. if modelfile == '': print("", file=ofile) - write_models(cellsused, celldefs, ofile) + write_models(cellsused, celldefs, ofile, timing) print(".end", file=ofile) -def write_lib(fileout, celldefs, debug): +def write_lib(fileout, celldefs, debug, timing): global vdd vddname = '{:g}'.format(vdd).replace('.', 'v') @@ -587,6 +620,16 @@ def write_lib(fileout, celldefs, debug): vddtlow = str(vdd / 3) vddhigh = str(vdd) + # 'timing' is a list of five values: I/O rise/falltime, cell rise/ + # falltime, cell input delay, cell output delay, and cell load cap. + # These are all rough averages for the process. + + io_time = timing[0] + time = timing[1] + idelay = timing[2] + odelay = timing[3] + cload = timing[4] + # Write a library file containing the models of all of the cells in the # liberty file, which can then be included in other xspice simulatable # netlists. @@ -597,14 +640,14 @@ def write_lib(fileout, celldefs, debug): echoout = False print("", file=ofile) - print(".model todig_" + vddname + " adc_bridge(in_high=" + vddthigh + " in_low=" + vddtlow + " rise_delay=10n fall_delay=10n)", file=ofile) + print(".model todig_" + vddname + " adc_bridge(in_high=" + vddthigh + " in_low=" + vddtlow + " rise_delay=" + io_time + " fall_delay=" + io_time + ")", file=ofile) print(".model toana_" + vddname + " dac_bridge(out_high=" + vddhigh + " out_low=0)", file=ofile) print("", file=ofile) # Write d_dff, d_dlatch, d_pullup, and d_pulldown models - print(".model ddflop d_dff(ic=0 rise_delay=1n fall_delay=1n)", file=ofile) - print(".model dzero d_pulldown(load=1p)", file=ofile) - print(".model done d_pullup(load=1p)", file=ofile) + print(".model ddflop d_dff(ic=0 rise_delay=" + time + " fall_delay=" + time + ")", file=ofile) + print(".model dzero d_pulldown(load=" + cload + ")", file=ofile) + print(".model done d_pullup(load=" + cload + ")", file=ofile) cellsused = [] for cell in celldefs: @@ -612,7 +655,7 @@ def write_lib(fileout, celldefs, debug): # At the end, write all of the LUT-based digital models. print("", file=ofile) - write_models(cellsused, celldefs, ofile) + write_models(cellsused, celldefs, ofile, timing) print(".end", file=ofile) def parse_pin(function): @@ -813,6 +856,60 @@ if __name__ == '__main__': else: debug = False + # Timing options: Pass timing and load values as the following: + # + # -io_time=<value> Rise and fall time for signals in and out of the digital block + # -time=<value> Rise and fall time of gate outputs + # -idelay=<value> Input delay at gate inputs + # -odelay=<value> Throughput delay of the gate + # -cload=<value> Gate output load capacitance + # + # Note that these are just average numbers for the process. If not + # specified, the defaults are as assigned below. + + io_time = '10n' + time = '1n' + idelay = '1n' + odelay = '50n' + cload = '1p' + + try: + iotimeopt = next(item for item in options if item.startswith('-io_time=')) + except: + pass + else: + io_time = iotimeopt.split('=')[1] + + try: + timeopt = next(item for item in options if item.startswith('-time=')) + except: + pass + else: + time = timeopt.split('=')[1] + + try: + idelayopt = next(item for item in options if item.startswith('-idelay=')) + except: + pass + else: + idelay = idelayopt.split('=')[1] + + try: + odelayopt = next(item for item in options if item.startswith('-odelay=')) + except: + pass + else: + odelay = odelayopt.split('=')[1] + + try: + cloadopt = next(item for item in options if item.startswith('-cload=')) + except: + pass + else: + cload = cloadopt.split('=')[1] + + timing = [io_time, time, idelay, odelay, cload] + vdd = 3.0 celldefs = {} if len(arguments) >= 3: @@ -825,7 +922,7 @@ if __name__ == '__main__': modelfile = arguments[3] else: modelfile = '' - read_spice(arguments[1], arguments[2], celldefs, debug, modelfile) + read_spice(arguments[1], arguments[2], celldefs, debug, modelfile, timing) print("Done.") elif len(arguments) == 2: # Library-only option @@ -833,7 +930,7 @@ if __name__ == '__main__': print("Writing xspice model library " + arguments[1]) for libfile in arguments[0].split(): celldefs.update(read_liberty(libfile, debug)) - write_lib(arguments[1], celldefs, debug) + write_lib(arguments[1], celldefs, debug, timing) print("Done.") else: print("Usage:") diff --git a/scripts/synthesize.sh b/scripts/synthesize.sh index 5ce42ac..fe187ab 100755 --- a/scripts/synthesize.sh +++ b/scripts/synthesize.sh @@ -927,10 +927,8 @@ else set test=`which python3` if ( $status == 0 ) then echo "Running spi2xspice.py" |& tee -a ${synthlog} - if ("x${spicefile}" == "x") then - set spiceopt="" - else - set spiceopt="-l ${spicepath}" + if (!( ${?xspice_options} )) then + set xspice_options="" endif # Add paths to liberty files for any hard macros @@ -945,11 +943,11 @@ else end endif - echo spi2xspice.py '"'${libertyoption}'"' ${modulename}.spc ${modulename}.xspice |& tee -a ${synthlog} + echo spi2xspice.py '"'${libertyoption}'"' ${xspice_options} ${modulename}.spc ${modulename}.xspice |& tee -a ${synthlog} echo "" >> ${synthlog} - ${scriptdir}/spi2xspice.py "${libertyoption}" ${modulename}.spc \ - ${modulename}.xspice + ${scriptdir}/spi2xspice.py "${libertyoption}" ${xspice_options} \ + ${modulename}.spc ${modulename}.xspice if ( !( -f ${modulename}.xspice || \ ( -M ${modulename}.xspice < -M ${modulename}.spc ))) then |