summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2019-03-16 11:42:28 +0100
committerRuben Undheim <ruben.undheim@gmail.com>2019-03-16 11:42:28 +0100
commitfa5f10625f102fd0e62e867b8074d4477fb59e04 (patch)
tree13646a0f5200390eac5f542486fd9c8e88d564ea /scripts
parent521ec5e010477a8db7b7af93f279b514e7358610 (diff)
Imported version 1.3.12
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/drc.sh2
-rwxr-xr-xscripts/gdsii.sh2
-rwxr-xr-xscripts/makesim.sh2
-rwxr-xr-xscripts/migrate.sh2
-rw-r--r--scripts/qflow.sh.in20
-rwxr-xr-xscripts/qflow_manager.py.in112
-rwxr-xr-xscripts/spi2xspice.py.in185
-rwxr-xr-xscripts/synthesize.sh12
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