First pass at incorporating the efabless LVS manager GUI into the
netgen distribution. It sort of works, but not quite there yet.
This commit is contained in:
parent
02a77b61f9
commit
25ac57d103
4
Makefile
4
Makefile
|
|
@ -3,7 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
NETGENDIR = .
|
NETGENDIR = .
|
||||||
PROGRAMS = netgen
|
PROGRAMS = netgen python
|
||||||
MODULES = base
|
MODULES = base
|
||||||
|
|
||||||
MAKEFLAGS =
|
MAKEFLAGS =
|
||||||
|
|
@ -61,7 +61,7 @@ install-real: install-dirs
|
||||||
|
|
||||||
install-tcl-dirs:
|
install-tcl-dirs:
|
||||||
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
|
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
|
||||||
$(DESTDIR)${TCLDIR}
|
$(DESTDIR)${TCLDIR} $(DESTDIR)${PYDIR}
|
||||||
|
|
||||||
install-dirs:
|
install-dirs:
|
||||||
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR}
|
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR}
|
||||||
|
|
|
||||||
2
README
2
README
|
|
@ -78,7 +78,7 @@ of CVS check-in notes on http://opencircuitdesign.com/netgen/.
|
||||||
|
|
||||||
BUILDING NETGEN:
|
BUILDING NETGEN:
|
||||||
----------------
|
----------------
|
||||||
NETGEN version 1.4 uses the same "make" procedure as Magic version 7.5
|
NETGEN version 1.5 uses the same "make" procedure as Magic version 8.1
|
||||||
and IRSIM version 9.7:
|
and IRSIM version 9.7:
|
||||||
|
|
||||||
./configure
|
./configure
|
||||||
|
|
|
||||||
25
TO_DO
25
TO_DO
|
|
@ -6,33 +6,24 @@ TO_DO list for version 1.5
|
||||||
Possible useful additions (not critical)
|
Possible useful additions (not critical)
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
1) Add new output style allowing netlists to be described by Tcl scripts
|
1) Add automatic file format guessing from file extension for "write" command
|
||||||
(similar to the C-Code format, but does not require compiling) (this
|
2) Incorporate into Tcl-based xcircuit
|
||||||
was done in 1.5.72, but now needs some scripts to make use of it.)
|
3) Extend 2-terminal device handling (namely R and C) to more formats
|
||||||
2) Add automatic file format guessing from file extension for "write" command
|
|
||||||
3) Add Tk GUI to match (and improve upon!) the original X11 GUI.
|
|
||||||
4) Incorporate into Tcl-based xcircuit
|
|
||||||
5) Extend 2-terminal device handling (namely R and C) to more formats
|
|
||||||
(where appropriate).
|
(where appropriate).
|
||||||
6) Generate feedback in the form of a .mag file to facilitate interactive
|
4) Generate feedback in the form of a .mag file to facilitate interactive
|
||||||
netlist comparison in conjunction with magic. This may be an error
|
netlist comparison in conjunction with magic. This may be an error
|
||||||
file, but it may also make use of magic 7.2's "element" command to
|
file, but it may also make use of magic 7.2's "element" command to
|
||||||
build rat's nests or outline areas of interest or anything else that
|
build rat's nests or outline areas of interest or anything else that
|
||||||
might be helpful to interactive comparison.
|
might be helpful to interactive comparison.
|
||||||
7) Improve upon the readability of the netlist comparator output.
|
5) Handle the hierarchy of ".ext" files automatically.
|
||||||
In particular, pinpoint situations in which an error does not show
|
6) Retain position information from ".ext" files for the purpose of writing
|
||||||
up in an obvious way in either the element or node lists.
|
|
||||||
8) Handle the hierarchy of ".ext" files automatically.
|
|
||||||
9) Retain position information from ".ext" files for the purpose of writing
|
|
||||||
feedback information into magic and for matching devices in the element
|
feedback information into magic and for matching devices in the element
|
||||||
list to their counterparts in the original layout [note---done for .sim
|
list to their counterparts in the original layout [note---done for .sim
|
||||||
format, which contains position information. Usefulness of improving
|
format, which contains position information. Usefulness of improving
|
||||||
the .ext parsing is questionable. Ditto for item 8].
|
the .ext parsing is questionable. Ditto for item 8].
|
||||||
10) Expand upon the details of format-to-format translation, (especially
|
7) Expand upon the details of format-to-format translation, (especially
|
||||||
ntk and ext formats, SPICE format writing, and sim format reading).
|
ntk and ext formats, SPICE format writing, and sim format reading).
|
||||||
11) Add a "property" command to add/remove properties to check, and change
|
8) Add a "subcircuit" command to mimic a SPICE ".SUBCKT ... .ENDS" card
|
||||||
the slop values (done).
|
|
||||||
12) Add a "subcircuit" command to mimic a SPICE ".SUBCKT ... .ENDS" card
|
|
||||||
(i.e., the ability to add subcircuit "stub" definitions from the
|
(i.e., the ability to add subcircuit "stub" definitions from the
|
||||||
command line or from a setup file).
|
command line or from a setup file).
|
||||||
|
|
||||||
|
|
|
||||||
5
defs.mak
5
defs.mak
|
|
@ -33,6 +33,7 @@ MANDIR = ${mandir}
|
||||||
LIBDIR = ${libdir}
|
LIBDIR = ${libdir}
|
||||||
DOCDIR = ${libdir}/netgen/doc
|
DOCDIR = ${libdir}/netgen/doc
|
||||||
TCLDIR = ${libdir}/netgen/tcl
|
TCLDIR = ${libdir}/netgen/tcl
|
||||||
|
PYDIR = ${libdir}/netgen/python
|
||||||
|
|
||||||
MAIN_EXTRA_LIBS = ${NETGENDIR}/tcltk/libtcltk.o
|
MAIN_EXTRA_LIBS = ${NETGENDIR}/tcltk/libtcltk.o
|
||||||
LD_EXTRA_LIBS =
|
LD_EXTRA_LIBS =
|
||||||
|
|
@ -66,8 +67,8 @@ CPP = gcc -E -x c
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
|
|
||||||
CPPFLAGS = -I. -I${NETGENDIR}
|
CPPFLAGS = -I. -I${NETGENDIR}
|
||||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"90\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"98\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||||
DFLAGS_NOSTUB = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"90\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
DFLAGS_NOSTUB = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"98\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||||
CFLAGS = -g -m64 -fPIC -fPIC
|
CFLAGS = -g -m64 -fPIC -fPIC
|
||||||
|
|
||||||
DEPEND_FILE = Depend
|
DEPEND_FILE = Depend
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
MODULE = python
|
||||||
|
NETGENDIR = ..
|
||||||
|
SRCS =
|
||||||
|
SCRIPTS = consoletext.py helpwindow.py lvs_manager.py treeviewsplit.py
|
||||||
|
SCRIPTS += tksimpledialog.py tooltip.py lvs_help.txt
|
||||||
|
|
||||||
|
SCRIPTINSTALL = $(DESTDIR)${PYDIR}
|
||||||
|
|
||||||
|
include ${NETGENDIR}/defs.mak
|
||||||
|
|
||||||
|
main: lvs_manager.py
|
||||||
|
|
||||||
|
tcl-main: lvs_manager.py
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/consoletext.py:
|
||||||
|
${RM} $@
|
||||||
|
${CP} consoletext.py $@
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/helpwindow.py:
|
||||||
|
${RM} $@
|
||||||
|
${CP} helpwindow.py $@
|
||||||
|
|
||||||
|
lvs_manager.py: lvs_manager.py.in
|
||||||
|
sed -e '/SUBST_SCRIPT_DIR/s#SUBST_SCRIPT_DIR#$(SCRIPTINSTALL)#' \
|
||||||
|
lvs_manager.py.in > lvs_manager.py
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/lvs_manager.py: lvs_manager.py
|
||||||
|
${RM} $@
|
||||||
|
${CP} lvs_manager.py $@
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/treeviewsplit.py: treeviewsplit.py
|
||||||
|
${RM} $@
|
||||||
|
${CP} treeviewsplit.py $@
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/tksimpledialog.py: tksimpledialog.py
|
||||||
|
${RM} $@
|
||||||
|
${CP} tksimpledialog.py $@
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/tooltip.py: tooltip.py
|
||||||
|
${RM} $@
|
||||||
|
${CP} tooltip.py $@
|
||||||
|
|
||||||
|
$(DESTDIR)${PYDIR}/lvs_help.txt: lvs_help.txt
|
||||||
|
${RM} $@
|
||||||
|
${CP} lvs_help.txt $@
|
||||||
|
|
||||||
|
install: install-tcl
|
||||||
|
|
||||||
|
install-tcl: $(DESTDIR)${PYDIR} $(DESTDIR)${PYDIR}/consoletext.py \
|
||||||
|
$(DESTDIR)${PYDIR}/helpwindow.py $(DESTDIR)${PYDIR}/lvs_manager.py \
|
||||||
|
$(DESTDIR)${PYDIR}/treeviewsplit.py $(DESTDIR)${PYDIR}/tksimpledialog.py \
|
||||||
|
$(DESTDIR)${PYDIR}/tooltip.py $(DESTDIR)${PYDIR}/lvs_help.txt
|
||||||
|
|
||||||
|
include ${NETGENDIR}/rules.mak
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
"""
|
||||||
|
consoletext --- extends tkinter class Text
|
||||||
|
with stdout and stderr redirection.
|
||||||
|
"""
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Written by Tim Edwards
|
||||||
|
# efabless, inc.
|
||||||
|
# September 11, 2016
|
||||||
|
# Version 0.1
|
||||||
|
#--------------------------------------------------------
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import tkinter
|
||||||
|
|
||||||
|
class ConsoleText(tkinter.Text):
|
||||||
|
linelimit = 500
|
||||||
|
class IORedirector(object):
|
||||||
|
'''A general class for redirecting I/O to this Text widget.'''
|
||||||
|
def __init__(self,text_area):
|
||||||
|
self.text_area = text_area
|
||||||
|
|
||||||
|
class StdoutRedirector(IORedirector):
|
||||||
|
'''A class for redirecting stdout to this Text widget.'''
|
||||||
|
def write(self,str):
|
||||||
|
self.text_area.write(str,False)
|
||||||
|
|
||||||
|
class StderrRedirector(IORedirector):
|
||||||
|
'''A class for redirecting stderr to this Text widget.'''
|
||||||
|
def write(self,str):
|
||||||
|
self.text_area.write(str,True)
|
||||||
|
|
||||||
|
def __init__(self, master=None, cnf={}, **kw):
|
||||||
|
'''See the __init__ for Tkinter.Text.'''
|
||||||
|
|
||||||
|
tkinter.Text.__init__(self, master, cnf, **kw)
|
||||||
|
|
||||||
|
self.tag_configure('stdout',background='white',foreground='black')
|
||||||
|
self.tag_configure('stderr',background='white',foreground='red')
|
||||||
|
# None of these works! Cannot change selected text background!
|
||||||
|
self.config(selectbackground='blue', selectforeground='white')
|
||||||
|
self.tag_configure('sel',background='blue',foreground='white')
|
||||||
|
|
||||||
|
def write(self, val, is_stderr=False):
|
||||||
|
lines = int(self.index('end-1c').split('.')[0])
|
||||||
|
if lines > self.linelimit:
|
||||||
|
self.delete('1.0', str(lines - self.linelimit) + '.0')
|
||||||
|
self.insert('end',val,'stderr' if is_stderr else 'stdout')
|
||||||
|
self.see('end')
|
||||||
|
|
||||||
|
def limit(self, val):
|
||||||
|
self.linelimit = val
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Help Window for the Open Galaxy project manager
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Written by Tim Edwards
|
||||||
|
# efabless, inc.
|
||||||
|
# September 12, 2016
|
||||||
|
# Version 0.1
|
||||||
|
#--------------------------------------------------------
|
||||||
|
|
||||||
|
import re
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
|
class HelpWindow(tkinter.Toplevel):
|
||||||
|
"""Open Galaxy help window."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None, fontsize = 11, *args, **kwargs):
|
||||||
|
'''See the __init__ for Tkinter.Toplevel.'''
|
||||||
|
tkinter.Toplevel.__init__(self, parent, *args, **kwargs)
|
||||||
|
|
||||||
|
s = ttk.Style()
|
||||||
|
s.configure('normal.TButton', font=('Helvetica', fontsize), border = 3, relief = 'raised')
|
||||||
|
|
||||||
|
self.withdraw()
|
||||||
|
self.title('Open Galaxy Help')
|
||||||
|
|
||||||
|
self.helptitle = ttk.Label(self, style='title.TLabel', text = '(no text)')
|
||||||
|
self.helptitle.grid(column = 0, row = 0, sticky = "news")
|
||||||
|
self.helpbar = ttk.Separator(self, orient='horizontal')
|
||||||
|
self.helpbar.grid(column = 0, row = 1, sticky = "news")
|
||||||
|
|
||||||
|
self.hframe = tkinter.Frame(self)
|
||||||
|
self.hframe.grid(column = 0, row = 2, sticky = "news")
|
||||||
|
self.hframe.helpdisplay = ttk.Frame(self.hframe)
|
||||||
|
self.hframe.helpdisplay.pack(side = 'left', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
self.hframe.helpdisplay.helptext = tkinter.Text(self.hframe.helpdisplay, wrap='word')
|
||||||
|
self.hframe.helpdisplay.helptext.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
# Add scrollbar to help window
|
||||||
|
self.hframe.scrollbar = ttk.Scrollbar(self.hframe)
|
||||||
|
self.hframe.scrollbar.pack(side='right', fill='y')
|
||||||
|
# attach help window to scrollbar
|
||||||
|
self.hframe.helpdisplay.helptext.config(yscrollcommand = self.hframe.scrollbar.set)
|
||||||
|
self.hframe.scrollbar.config(command = self.hframe.helpdisplay.helptext.yview)
|
||||||
|
|
||||||
|
self.hframe.toc = ttk.Treeview(self.hframe, selectmode='browse')
|
||||||
|
self.hframe.toc.bind('<<TreeviewSelect>>', self.toc_to_page)
|
||||||
|
self.hframe.toc.bind('<<TreeviewOpen>>', self.toc_toggle)
|
||||||
|
self.hframe.toc.bind('<<TreeviewClose>>', self.toc_toggle)
|
||||||
|
self.hframe.toc.tag_configure('title', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'brown', anchor = 'center')
|
||||||
|
self.hframe.toc.heading('#0', text = "Table of Contents")
|
||||||
|
|
||||||
|
self.bbar = ttk.Frame(self)
|
||||||
|
self.bbar.grid(column = 0, row = 3, sticky = "news")
|
||||||
|
self.bbar.close_button = ttk.Button(self.bbar, text='Close',
|
||||||
|
command=self.close, style = 'normal.TButton')
|
||||||
|
self.bbar.close_button.grid(column=0, row=0, padx = 5)
|
||||||
|
|
||||||
|
self.bbar.prev_button = ttk.Button(self.bbar, text='Prev',
|
||||||
|
command=self.prevpage, style = 'normal.TButton')
|
||||||
|
self.bbar.prev_button.grid(column=1, row=0, padx = 5)
|
||||||
|
|
||||||
|
self.bbar.next_button = ttk.Button(self.bbar, text='Next',
|
||||||
|
command=self.nextpage, style = 'normal.TButton')
|
||||||
|
self.bbar.next_button.grid(column=2, row=0, padx = 5)
|
||||||
|
|
||||||
|
self.bbar.contents_button = ttk.Button(self.bbar, text='Table of Contents',
|
||||||
|
command=self.page_to_toc, style = 'normal.TButton')
|
||||||
|
self.bbar.contents_button.grid(column=3, row=0, padx = 5)
|
||||||
|
|
||||||
|
self.rowconfigure(0, weight=0)
|
||||||
|
self.rowconfigure(1, weight=0)
|
||||||
|
self.rowconfigure(2, weight=1)
|
||||||
|
self.rowconfigure(3, weight=0)
|
||||||
|
self.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# Help pages
|
||||||
|
self.pages = []
|
||||||
|
self.pageno = -1 # No page
|
||||||
|
self.toggle = False
|
||||||
|
|
||||||
|
def grid_configure(self, padx, pady):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def redisplay(self):
|
||||||
|
# remove contents
|
||||||
|
if self.pageno >= 0 and self.pageno < len(self.pages):
|
||||||
|
self.hframe.helpdisplay.helptext.delete('1.0', 'end')
|
||||||
|
self.hframe.helpdisplay.helptext.insert('end', self.pages[self.pageno]['text'])
|
||||||
|
self.helptitle.configure(text = self.pages[self.pageno]['title'])
|
||||||
|
|
||||||
|
def toc_toggle(self, event):
|
||||||
|
self.toggle = True
|
||||||
|
|
||||||
|
def toc_to_page(self, event):
|
||||||
|
treeview = event.widget
|
||||||
|
selection = treeview.item(treeview.selection())
|
||||||
|
|
||||||
|
# Make sure any open/close callback is handled first!
|
||||||
|
self.update_idletasks()
|
||||||
|
if self.toggle:
|
||||||
|
# Item was opened or closed, so consider this a 'false select' and
|
||||||
|
# do not go to the page.
|
||||||
|
self.toggle = False
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'values' in selection:
|
||||||
|
pagenum = selection['values'][0]
|
||||||
|
else:
|
||||||
|
print('Unknown page selected.')
|
||||||
|
pagenum = 0
|
||||||
|
|
||||||
|
# Display a page after displaying the table of contents
|
||||||
|
self.hframe.toc.pack_forget()
|
||||||
|
self.hframe.scrollbar.pack_forget()
|
||||||
|
self.hframe.helpdisplay.pack(side='left', fill='both', expand = 'true')
|
||||||
|
self.hframe.scrollbar.pack(side='right', fill='y')
|
||||||
|
self.hframe.scrollbar.config(command = self.hframe.helpdisplay.helptext.yview)
|
||||||
|
# Enable Prev and Next buttons
|
||||||
|
self.bbar.prev_button.configure(state='enabled')
|
||||||
|
self.bbar.next_button.configure(state='enabled')
|
||||||
|
# Redisplay
|
||||||
|
self.page(pagenum)
|
||||||
|
|
||||||
|
def page_to_toc(self):
|
||||||
|
# Display the table of contents after displaying a page
|
||||||
|
self.hframe.scrollbar.pack_forget()
|
||||||
|
self.hframe.helpdisplay.pack_forget()
|
||||||
|
self.hframe.toc.pack(side='left', fill='both', expand = 'true')
|
||||||
|
self.hframe.scrollbar.pack(side='right', fill='y')
|
||||||
|
self.hframe.scrollbar.config(command = self.hframe.toc.yview)
|
||||||
|
# Disable Prev and Next buttons
|
||||||
|
self.bbar.prev_button.configure(state='disabled')
|
||||||
|
self.bbar.next_button.configure(state='disabled')
|
||||||
|
|
||||||
|
# Simple add page with a single block of plain text
|
||||||
|
def add_page(self, toc_text, text_block):
|
||||||
|
newdict = {}
|
||||||
|
newdict['text'] = text_block
|
||||||
|
newdict['title'] = toc_text
|
||||||
|
self.pages.append(newdict)
|
||||||
|
newpageno = len(self.pages)
|
||||||
|
self.hframe.toc.insert('', 'end', text=str(newpageno) + '. ' + toc_text,
|
||||||
|
tag='title', value = newpageno - 1)
|
||||||
|
if self.pageno < 0:
|
||||||
|
self.pageno = 0 # First page
|
||||||
|
|
||||||
|
# Fill the help text from a file. The format of the file is:
|
||||||
|
# <page_num>
|
||||||
|
# <title>
|
||||||
|
# <text>
|
||||||
|
# '.'
|
||||||
|
# Text is multi-line and ends when '.' is encountered by itself
|
||||||
|
|
||||||
|
def add_pages_from_file(self, filename):
|
||||||
|
endpagerex = re.compile('^\.$')
|
||||||
|
newpagerex = re.compile('^[0-9\.]+$')
|
||||||
|
commentrex = re.compile('^[\-]+$')
|
||||||
|
hierarchy = ''
|
||||||
|
print('Loading help text from file ' + filename)
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
toc_text = []
|
||||||
|
page_text = []
|
||||||
|
for line in f:
|
||||||
|
if newpagerex.match(line) or endpagerex.match(line):
|
||||||
|
if toc_text and page_text:
|
||||||
|
newdict = {}
|
||||||
|
self.pages.append(newdict)
|
||||||
|
newpageno = len(self.pages)
|
||||||
|
if '.' in hierarchy:
|
||||||
|
pageinfo = hierarchy.rsplit('.', 1)
|
||||||
|
if pageinfo[1] == '':
|
||||||
|
parentid = ''
|
||||||
|
pageid = pageinfo[0]
|
||||||
|
else:
|
||||||
|
parentid = pageinfo[0]
|
||||||
|
pageid = pageinfo[1]
|
||||||
|
else:
|
||||||
|
parentid = ''
|
||||||
|
pageid = hierarchy
|
||||||
|
if parentid:
|
||||||
|
pageid = parentid + '.' + pageid
|
||||||
|
newdict['text'] = page_text
|
||||||
|
newdict['title'] = pageid + '. ' + toc_text
|
||||||
|
self.hframe.toc.insert(parentid, 'end',
|
||||||
|
text=newdict['title'], tag='title',
|
||||||
|
value = newpageno - 1, iid = pageid)
|
||||||
|
if newpagerex.match(line):
|
||||||
|
hierarchy = line.rstrip()
|
||||||
|
toc_text = []
|
||||||
|
elif not toc_text:
|
||||||
|
toc_text = line.rstrip()
|
||||||
|
page_text = []
|
||||||
|
elif not commentrex.match(line):
|
||||||
|
if not page_text:
|
||||||
|
page_text = line
|
||||||
|
else:
|
||||||
|
page_text += line
|
||||||
|
|
||||||
|
def nextpage(self):
|
||||||
|
# Go to next page
|
||||||
|
if self.pageno < len(self.pages) - 1:
|
||||||
|
self.pageno += 1
|
||||||
|
self.redisplay()
|
||||||
|
|
||||||
|
def prevpage(self):
|
||||||
|
# Go to previous page
|
||||||
|
if self.pageno > 0:
|
||||||
|
self.pageno -= 1
|
||||||
|
self.redisplay()
|
||||||
|
|
||||||
|
def page(self, pagenum):
|
||||||
|
# Go to indicated page
|
||||||
|
if pagenum >= 0 and pagenum < len(self.pages):
|
||||||
|
self.pageno = pagenum
|
||||||
|
self.redisplay()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
# pop down help window
|
||||||
|
self.withdraw()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
# pop up help window
|
||||||
|
self.deiconify()
|
||||||
|
self.lift()
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
1.
|
||||||
|
Selecting a project
|
||||||
|
-------
|
||||||
|
Start by selecting a project. This step is only necessary if the application is started from the command line. If started from the project manager, then it can only be run if a project was selected.
|
||||||
|
.
|
||||||
|
|
@ -0,0 +1,819 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# LVS Manager GUI.
|
||||||
|
#
|
||||||
|
# This is a Python tkinter script that handles the
|
||||||
|
# process of running LVS and interpreting results.
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Written by Tim Edwards
|
||||||
|
# efabless, inc.
|
||||||
|
# Version 1. November 30, 2016
|
||||||
|
# Version 2. March 6, 2017. Reads JSON format output
|
||||||
|
# Version 3. April 25, 2018. Handles layout vs. verilog
|
||||||
|
#--------------------------------------------------------
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import datetime
|
||||||
|
import contextlib
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
import tksimpledialog
|
||||||
|
import tooltip
|
||||||
|
from consoletext import ConsoleText
|
||||||
|
from helpwindow import HelpWindow
|
||||||
|
from treeviewsplit import TreeViewSplit
|
||||||
|
|
||||||
|
# User preferences file (if it exists)
|
||||||
|
prefsfile = '~/.profile/prefs.json'
|
||||||
|
|
||||||
|
netgen_script_dir = '/usr/local/lib/netgen/python'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Simple dialog for confirming quit
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class ConfirmDialog(tksimpledialog.Dialog):
|
||||||
|
def body(self, master, warning, seed):
|
||||||
|
if warning:
|
||||||
|
ttk.Label(master, text=warning, wraplength=500).grid(row = 0, columnspan = 2, sticky = 'wns')
|
||||||
|
return self
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
return 'okay'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Main class for this application
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class LVSManager(ttk.Frame):
|
||||||
|
"""LVS Manager GUI."""
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
ttk.Frame.__init__(self, parent, *args, **kwargs)
|
||||||
|
self.root = parent
|
||||||
|
self.init_gui()
|
||||||
|
parent.protocol("WM_DELETE_WINDOW", self.on_quit)
|
||||||
|
|
||||||
|
def on_quit(self):
|
||||||
|
"""Exits program."""
|
||||||
|
if self.msock:
|
||||||
|
self.msock.close()
|
||||||
|
quit()
|
||||||
|
|
||||||
|
def init_gui(self):
|
||||||
|
"""Builds GUI."""
|
||||||
|
global prefsfile
|
||||||
|
|
||||||
|
message = []
|
||||||
|
fontsize = 11
|
||||||
|
|
||||||
|
# Read user preferences file, get default font size from it.
|
||||||
|
prefspath = os.path.expanduser(prefsfile)
|
||||||
|
if os.path.exists(prefspath):
|
||||||
|
with open(prefspath, 'r') as f:
|
||||||
|
self.prefs = json.load(f)
|
||||||
|
if 'fontsize' in self.prefs:
|
||||||
|
fontsize = self.prefs['fontsize']
|
||||||
|
else:
|
||||||
|
self.prefs = {}
|
||||||
|
|
||||||
|
s = ttk.Style()
|
||||||
|
|
||||||
|
available_themes = s.theme_names()
|
||||||
|
s.theme_use(available_themes[0])
|
||||||
|
|
||||||
|
s.configure('bg.TFrame', background='gray40')
|
||||||
|
s.configure('italic.TLabel', font=('Helvetica', fontsize, 'italic'))
|
||||||
|
s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'brown', anchor = 'center')
|
||||||
|
s.configure('normal.TLabel', font=('Helvetica', fontsize))
|
||||||
|
s.configure('red.TLabel', font=('Helvetica', fontsize), foreground = 'red')
|
||||||
|
s.configure('green.TLabel', font=('Helvetica', fontsize), foreground = 'green3')
|
||||||
|
s.configure('blue.TLabel', font=('Helvetica', fontsize), foreground = 'blue')
|
||||||
|
s.configure('normal.TButton', font=('Helvetica', fontsize),
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('red.TButton', font=('Helvetica', fontsize), foreground = 'red',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('green.TButton', font=('Helvetica', fontsize), foreground = 'green3',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('blue.TButton', font=('Helvetica', fontsize), foreground = 'blue',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('redtitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'red', border = 3, relief = 'raised')
|
||||||
|
s.configure('bluetitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'blue', border = 3, relief = 'raised')
|
||||||
|
|
||||||
|
# These values to be overridden from arguments
|
||||||
|
self.rootpath = None
|
||||||
|
self.project = None
|
||||||
|
self.logfile = None
|
||||||
|
self.msock = None
|
||||||
|
self.help = None
|
||||||
|
|
||||||
|
# Create the help window
|
||||||
|
if os.path.exists(netgen_script_dir + '/netgen_help.txt'):
|
||||||
|
self.help = HelpWindow(self, fontsize = fontsize)
|
||||||
|
with io.StringIO() as buf, contextlib.redirect_stdout(buf):
|
||||||
|
self.help.add_pages_from_file('lvs_help.txt')
|
||||||
|
message = buf.getvalue()
|
||||||
|
|
||||||
|
# Set the help display to the first page
|
||||||
|
self.help.page(0)
|
||||||
|
|
||||||
|
# Variables used by option menus and other stuff
|
||||||
|
self.project = "(no selection)"
|
||||||
|
self.layout = "(default)"
|
||||||
|
self.schematic = "(default)"
|
||||||
|
self.tech = "(none)"
|
||||||
|
self.lvs_setup = ''
|
||||||
|
self.lvsdata = {}
|
||||||
|
|
||||||
|
# Root window title
|
||||||
|
self.root.title('LVS Manager')
|
||||||
|
self.root.option_add('*tearOff', 'FALSE')
|
||||||
|
self.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
pane = tkinter.PanedWindow(self, orient = 'vertical', sashrelief='groove', sashwidth=6)
|
||||||
|
pane.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
self.toppane = ttk.Frame(pane)
|
||||||
|
self.botpane = ttk.Frame(pane)
|
||||||
|
|
||||||
|
# Get username
|
||||||
|
if 'username' in self.prefs:
|
||||||
|
username = self.prefs['username']
|
||||||
|
else:
|
||||||
|
username = os.environ['USER']
|
||||||
|
|
||||||
|
# Label with the user
|
||||||
|
self.toppane.title_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title_frame.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title = ttk.Label(self.toppane.title_frame, text='User:', style = 'red.TLabel')
|
||||||
|
self.toppane.title_frame.user = ttk.Label(self.toppane.title_frame, text=username, style = 'blue.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title.grid(column=0, row=0, ipadx = 5)
|
||||||
|
self.toppane.title_frame.user.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
self.toppane.title2_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title2_frame.pack(side = 'top', fill = 'x')
|
||||||
|
self.toppane.title2_frame.project_label = ttk.Label(self.toppane.title2_frame, text="Project:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.project_label.grid(column=0, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
# New project select button
|
||||||
|
self.toppane.title2_frame.project_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.project, style='normal.TButton', command=self.choose_project)
|
||||||
|
self.toppane.title2_frame.project_select.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
|
||||||
|
# Show path to project
|
||||||
|
self.toppane.title2_frame.path_label = ttk.Label(self.toppane.title2_frame, text=self.project,
|
||||||
|
style = 'normal.TLabel')
|
||||||
|
self.toppane.title2_frame.path_label.grid(column=2, row=0, ipadx = 5, padx = 10)
|
||||||
|
|
||||||
|
# Show top-level layout cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.tech_label = ttk.Label(self.toppane.title2_frame, text="Technology setup:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title2_frame.tech_label.grid(column=3, row=0, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.tech_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.tech, style='normal.TButton', command=self.choose_tech)
|
||||||
|
self.toppane.title2_frame.tech_select.grid(column=4, row=0, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
self.toppane.title2_frame.layout_label = ttk.Label(self.toppane.title2_frame, text="Layout:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.layout_label.grid(column=0, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.layout_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.layout, style='normal.TButton', command=self.choose_layout)
|
||||||
|
self.toppane.title2_frame.layout_select.grid(column=1, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
# Show top-level schematic cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.schem_label = ttk.Label(self.toppane.title2_frame, text="Schematic:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.schem_label.grid(column=3, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.schem_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.schematic, style='normal.TButton', command=self.choose_netlist)
|
||||||
|
self.toppane.title2_frame.schem_select.grid(column=4, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.layout_select,
|
||||||
|
text = "Select a layout subcirucit to compare")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.schem_select,
|
||||||
|
text = "Select a schematic subcirucit to compare")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
ttk.Separator(self.toppane, orient='horizontal').pack(side = 'top', fill = 'x')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Create listbox of Circuit1 vs. Circuit2 results
|
||||||
|
height = 10
|
||||||
|
self.toppane.lvsreport = TreeViewSplit(self.toppane, fontsize = fontsize)
|
||||||
|
self.toppane.lvsreport.populate("Layout:", [], "Schematic:", [],
|
||||||
|
[["Run", True, self.run_lvs],
|
||||||
|
# ["Find", True, self.findrecord]
|
||||||
|
], height = height)
|
||||||
|
self.toppane.lvsreport.set_title("Line")
|
||||||
|
self.toppane.lvsreport.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.lvsreport.get_button(0), text="Run LVS")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
# ttk.Separator(self, orient='horizontal').grid(column=0, row=3, sticky='ew')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Add a text window below the project name to capture output. Redirect
|
||||||
|
# print statements to it.
|
||||||
|
|
||||||
|
self.botpane.console = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.console.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
self.text_box = ConsoleText(self.botpane.console, wrap='word', height = 4)
|
||||||
|
self.text_box.pack(side='left', fill='both', expand='true')
|
||||||
|
console_scrollbar = ttk.Scrollbar(self.botpane.console)
|
||||||
|
console_scrollbar.pack(side='right', fill='y')
|
||||||
|
# attach console to scrollbar
|
||||||
|
self.text_box.config(yscrollcommand = console_scrollbar.set)
|
||||||
|
console_scrollbar.config(command = self.text_box.yview)
|
||||||
|
|
||||||
|
# Add button bar at the bottom of the window
|
||||||
|
self.botpane.bbar = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.bbar.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
# Define the "quit" button and action
|
||||||
|
self.botpane.bbar.quit_button = ttk.Button(self.botpane.bbar, text='Quit', command=self.on_quit,
|
||||||
|
style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.quit_button.grid(column=0, row=0, padx = 5)
|
||||||
|
|
||||||
|
# Define help button
|
||||||
|
if self.help:
|
||||||
|
self.botpane.bbar.help_button = ttk.Button(self.botpane.bbar, text='Help',
|
||||||
|
command=self.help.open, style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.help_button.grid(column = 2, row = 0, padx = 5)
|
||||||
|
tooltip.ToolTip(self.botpane.bbar.help_button, text = "Show help window")
|
||||||
|
|
||||||
|
# Add the panes once the internal geometry is known.
|
||||||
|
pane.add(self.toppane)
|
||||||
|
pane.add(self.botpane)
|
||||||
|
pane.paneconfig(self.toppane, stretch='first')
|
||||||
|
|
||||||
|
# Redirect stdout and stderr to the console as the last thing to do. . .
|
||||||
|
# Otherwise errors in the GUI get sucked into the void.
|
||||||
|
|
||||||
|
self.stdout = sys.stdout
|
||||||
|
self.stderr = sys.stderr
|
||||||
|
sys.stdout = ConsoleText.StdoutRedirector(self.text_box)
|
||||||
|
sys.stderr = ConsoleText.StderrRedirector(self.text_box)
|
||||||
|
|
||||||
|
if message:
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def logprint(self, message, doflush=False):
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.buffer.write(message.encode('utf-8'))
|
||||||
|
self.logfile.buffer.write('\n'.encode('utf-8'))
|
||||||
|
if doflush:
|
||||||
|
self.logfile.flush()
|
||||||
|
|
||||||
|
def printout(self, output):
|
||||||
|
# Generate output
|
||||||
|
if not output:
|
||||||
|
return
|
||||||
|
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
print(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
pritn(line)
|
||||||
|
|
||||||
|
def printwarn(self, output):
|
||||||
|
# Check output for warning or error
|
||||||
|
if not output:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
warnrex = re.compile('.*warning', re.IGNORECASE)
|
||||||
|
errrex = re.compile('.*error', re.IGNORECASE)
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
ematch = errrex.match(line)
|
||||||
|
if ematch:
|
||||||
|
errors += 1
|
||||||
|
if ematch or wmatch:
|
||||||
|
print(line)
|
||||||
|
return errors
|
||||||
|
|
||||||
|
def choose_tech(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/tech',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
techname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Tcl script", "*.tcl"),("All Files","*.*")),
|
||||||
|
title = "Choose a netgen technology setup script.")
|
||||||
|
if techname != '':
|
||||||
|
print("Selected technology setup script " + techname)
|
||||||
|
techbase = os.path.split(techname)[1]
|
||||||
|
self.tech = os.path.splitext(techbase)[0]
|
||||||
|
self.lvs_setup = techname
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||||
|
|
||||||
|
def choose_layout(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/layout',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Magic layout", "*.mag"),("All Files","*.*")),
|
||||||
|
title = "Choose a layout cell to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.layout = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
|
||||||
|
def choose_netlist(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||||
|
title = "Choose a netlist to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.schematic = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
fileext = os.path.splitext(cellbase)[1]
|
||||||
|
if fileext == '.v':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||||
|
elif fileext == '.cdl':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Unknown netlist:')
|
||||||
|
|
||||||
|
def choose_project(self):
|
||||||
|
project = filedialog.askdirectory(initialdir = os.getcwd(),
|
||||||
|
title = "Find a project.")
|
||||||
|
if project != '':
|
||||||
|
print("Selected project " + str(project))
|
||||||
|
result = self.set_project(project)
|
||||||
|
|
||||||
|
def set_project(self, rootpath, project_name=None):
|
||||||
|
|
||||||
|
# Check if rootpath is valid. For LVS, there should be subdirectories
|
||||||
|
# "layout/" and "netlist/" or "verilog/".
|
||||||
|
|
||||||
|
haslay = os.path.isdir(rootpath + '/layout')
|
||||||
|
hasvlog = os.path.isdir(rootpath + '/verilog')
|
||||||
|
hasnet = os.path.isdir(rootpath + '/netlist')
|
||||||
|
if not haslay or not (hasvlog or hasnet):
|
||||||
|
if not haslay:
|
||||||
|
print("Project path has no layout (/layout) subdirectory.")
|
||||||
|
if not (hasvlog or hasnet):
|
||||||
|
print("Project path has no verilog (/verilog), or netlist (/netlist) subdirectory.")
|
||||||
|
# Continue anyway; assume that netlists will be selected manually
|
||||||
|
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
if not project_name:
|
||||||
|
project = os.path.split(rootpath)[1]
|
||||||
|
else:
|
||||||
|
project = project_name
|
||||||
|
|
||||||
|
if self.project != project:
|
||||||
|
|
||||||
|
self.rootpath = rootpath
|
||||||
|
self.project = project
|
||||||
|
|
||||||
|
# Clear out old project data
|
||||||
|
self.toppane.lvsreport.repopulate([], [])
|
||||||
|
|
||||||
|
# Close any open logfile.
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||||
|
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||||
|
# Print some initial information to the logfile.
|
||||||
|
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||||
|
doflush=True)
|
||||||
|
|
||||||
|
# Update project button
|
||||||
|
self.toppane.title2_frame.project_select.config(text = self.project)
|
||||||
|
self.toppane.title2_frame.path_label.config(text = self.rootpath)
|
||||||
|
# Cell name is the same as project name initially
|
||||||
|
self.layout = self.project
|
||||||
|
self.schematic = self.project
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
|
||||||
|
# Update schematic button
|
||||||
|
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||||
|
|
||||||
|
# If there is a comparison file that post-dates both netlists, load it.
|
||||||
|
self.check_lvs()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_layout_out_of_date(self, spipath, layoutpath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the layouts
|
||||||
|
# (layoutpath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(layoutpath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
lay_statbuf = os.stat(layoutpath)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-layout is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
layoutdir = os.path.split(layoutpath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
sublayout = layoutdir + '/' + subname + '.mag'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(sublayout):
|
||||||
|
sub_statbuf = os.stat(sublayout)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_schematic_out_of_date(self, spipath, schempath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the schematics
|
||||||
|
# (schempath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(schempath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
sch_statbuf = os.stat(schempath)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-schematic is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
schemdir = os.path.split(schempath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
# NOTE: Electric uses library:cell internally to track libraries,
|
||||||
|
# and maps the ":" to "__" in the netlist. Not entirely certain that
|
||||||
|
# the double-underscore uniquely identifies the library:cell. . .
|
||||||
|
librex = re.compile('(.*)__(.*)', re.IGNORECASE)
|
||||||
|
lmatch = librex.match(subname)
|
||||||
|
if lmatch:
|
||||||
|
elecpath = os.path.split(os.path.split(schempath)[0])[0]
|
||||||
|
libname = lmatch.group(1)
|
||||||
|
subschem = elecpath + '/' + libname + '.delib/' + lmatch.group(2) + '.sch'
|
||||||
|
else:
|
||||||
|
libname = {}
|
||||||
|
subschem = schemdir + '/' + subname + '.sch'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(subschem):
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sub_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
# mapping of characters to what's allowed in SPICE makes finding
|
||||||
|
# the associated schematic file a bit difficult. Requires wild-card
|
||||||
|
# searching.
|
||||||
|
elif libname:
|
||||||
|
restr = lmatch.group(2) + '.sch'
|
||||||
|
restr = restr.replace('.', '\.')
|
||||||
|
restr = restr.replace('_', '.')
|
||||||
|
schrex = re.compile(restr, re.IGNORECASE)
|
||||||
|
libpath = elecpath + '/' + libname + '.delib'
|
||||||
|
if os.path.exists(libpath):
|
||||||
|
liblist = os.listdir(libpath)
|
||||||
|
for file in liblist:
|
||||||
|
lmatch = schrex.match(file)
|
||||||
|
if lmatch:
|
||||||
|
subschem = libpath + '/' + file
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_lvs(self):
|
||||||
|
# If both netlists exist, and comp.json is more recent than both, then
|
||||||
|
# load LVS results from comp.json
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||||
|
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
|
||||||
|
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||||
|
magtime = os.stat(layout_path).st_mtime
|
||||||
|
schemtime = os.stat(net_path).st_mtime
|
||||||
|
comptime = os.stat(comp_path).st_mtime
|
||||||
|
if comptime > magtime and comptime > schemtime:
|
||||||
|
print("Loading LVS results from file.")
|
||||||
|
self.generate(comp_path)
|
||||||
|
|
||||||
|
def generate_layout_netlist(self, layout_path, layout_src, project_path):
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if self.check_layout_out_of_date(layout_path, layout_src):
|
||||||
|
print('Generating layout netlist.')
|
||||||
|
self.update_idletasks()
|
||||||
|
mproc = subprocess.Popen(['magic', '-dnull', '-noconsole',
|
||||||
|
self.layout], stdin = subprocess.PIPE, stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE, cwd = project_path + '/layout',
|
||||||
|
universal_newlines = True)
|
||||||
|
mproc.stdin.write("select top cell\n")
|
||||||
|
mproc.stdin.write("expand\n")
|
||||||
|
mproc.stdin.write("extract all\n")
|
||||||
|
mproc.stdin.write("ext2spice hierarchy on\n")
|
||||||
|
mproc.stdin.write("ext2spice format ngspice\n")
|
||||||
|
mproc.stdin.write("ext2spice scale off\n")
|
||||||
|
mproc.stdin.write("ext2spice renumber off\n")
|
||||||
|
mproc.stdin.write("ext2spice subcircuit top auto\n")
|
||||||
|
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice blackbox on\n")
|
||||||
|
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||||
|
mproc.stdin.write("quit -noprompt\n")
|
||||||
|
magicout = mproc.communicate()[0]
|
||||||
|
self.printwarn(magicout)
|
||||||
|
if mproc.returncode != 0:
|
||||||
|
print('Failure to generate new layout netlist.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Move .spi netlist to project_dir/netlist/lvs/
|
||||||
|
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||||
|
# Remove extraction files
|
||||||
|
for file in os.listdir(project_path + '/layout'):
|
||||||
|
if os.path.splitext(file)[1] == '.ext':
|
||||||
|
os.remove(project_path + '/layout/' + file)
|
||||||
|
else:
|
||||||
|
print('Layout netlist is up-to-date, not regenerating.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run_lvs(self, value):
|
||||||
|
# "value" is ignored (?)
|
||||||
|
|
||||||
|
# Check if netlists exist and are current; otherwise create them.
|
||||||
|
# Then run LVS.
|
||||||
|
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
has_vlog = False
|
||||||
|
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||||
|
|
||||||
|
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||||
|
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||||
|
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||||
|
|
||||||
|
# Does the setup file exist (this is optional)?
|
||||||
|
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||||
|
print('No technology setup file selected.')
|
||||||
|
|
||||||
|
# Does schematic netlist exist?
|
||||||
|
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||||
|
print('Error: No schematic netlist or verilog netlist.')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Does LVS netlist subdirectory exist?
|
||||||
|
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||||
|
os.makedirs(project_path + '/netlist/lvs')
|
||||||
|
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Final check
|
||||||
|
if not os.path.isfile(layout_path):
|
||||||
|
print('Error: No netlist generated from magic.')
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Read in netlist and convert commas from [X,Y] arrays to vertical bars
|
||||||
|
# as something that can be converted back as necessary. ngspice treats
|
||||||
|
# commas as special characters for some reason.
|
||||||
|
with open(layout_path) as ifile:
|
||||||
|
spitext = ifile.read()
|
||||||
|
|
||||||
|
# spilines = spitext.replace(',', '|')
|
||||||
|
# with open(layout_path, 'w') as ofile:
|
||||||
|
# ofile.write(spilines)
|
||||||
|
|
||||||
|
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||||
|
# not, then assume it is the top level.
|
||||||
|
|
||||||
|
is_subckt = False
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
if subname == self.layout:
|
||||||
|
is_subckt = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if is_subckt:
|
||||||
|
layout_arg = layout_path + ' ' + self.layout
|
||||||
|
layout_text = '"' + layout_arg + '"'
|
||||||
|
else:
|
||||||
|
layout_arg = layout_path
|
||||||
|
layout_text = layout_arg
|
||||||
|
|
||||||
|
if has_vlog:
|
||||||
|
schem_arg = vlog_path + ' ' + self.schematic
|
||||||
|
else:
|
||||||
|
schem_arg = net_path + ' ' + self.schematic
|
||||||
|
schem_text = '"' + schem_arg + '"'
|
||||||
|
|
||||||
|
# Remove any previous comparison output file
|
||||||
|
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||||
|
if os.path.exists(comp_out_path):
|
||||||
|
os.remove(comp_out_path)
|
||||||
|
|
||||||
|
# Run netgen as subprocess
|
||||||
|
print('Running: netgen -batch lvs ' + layout_text +
|
||||||
|
' ' + schem_text + ' ' + self.lvs_setup + ' ' + comp_out_path +
|
||||||
|
' -json -blackbox')
|
||||||
|
# Note: Because arguments to subprocess are list items, the {filename cell}
|
||||||
|
# pair does *not* have to be quoted or braced. Doing so causes a parse
|
||||||
|
# error.
|
||||||
|
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||||
|
layout_arg, schem_arg,
|
||||||
|
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||||
|
cwd=project_path + '/layout',
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||||
|
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||||
|
self.watchclock(comp_path)
|
||||||
|
|
||||||
|
def watchclock(self, filename):
|
||||||
|
if self.lvsproc == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
lvs_status = self.lvsproc.poll()
|
||||||
|
sresult = select.select([self.lvsproc.stdout, self.lvsproc.stderr], [], [], 0)[0]
|
||||||
|
if self.lvsproc.stdout in sresult:
|
||||||
|
outstring = self.lvsproc.stdout.readline().decode().strip()
|
||||||
|
self.logprint(outstring, doflush=True)
|
||||||
|
print(outstring)
|
||||||
|
elif self.lvsproc.stderr in sresult:
|
||||||
|
errstring = self.lvsproc.stderr.readline().decode().strip()
|
||||||
|
self.logprint(errstring, doflush = True)
|
||||||
|
print(errstring, file=sys.stderr)
|
||||||
|
|
||||||
|
if lvs_status != None:
|
||||||
|
print("netgen LVS exited with status " + str(lvs_status))
|
||||||
|
self.lvsproc = None
|
||||||
|
if lvs_status != 0:
|
||||||
|
print('Errors encountered in LVS.')
|
||||||
|
self.logprint('Errors in LVS, lvs status = ' + str(lvs_status), doflush=True)
|
||||||
|
# Done; now read comp.json and fill the treeview listbox.
|
||||||
|
self.generate(filename)
|
||||||
|
else:
|
||||||
|
self.after(500, lambda: self.watchclock(filename))
|
||||||
|
|
||||||
|
# Generate display from "comp.out" file (json file now preferred)
|
||||||
|
|
||||||
|
def generate_orig(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
lvslines = ifile.read().splitlines()
|
||||||
|
for line in lvslines:
|
||||||
|
if '|' in line:
|
||||||
|
# parts = line.split('|')
|
||||||
|
# lefttext.append(parts[0])
|
||||||
|
# righttext.append(parts[1])
|
||||||
|
lefttext.append(line[0:42].strip())
|
||||||
|
righttext.append(line[44:].strip())
|
||||||
|
else:
|
||||||
|
lefttext.append(line)
|
||||||
|
righttext.append('')
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.repopulate(lefttext, righttext)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
# Generate output from LVS report JSON file comp.json
|
||||||
|
|
||||||
|
def generate(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
self.lvsdata = json.load(ifile)
|
||||||
|
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.json_repopulate(self.lvsdata)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
def findrecord(self, value):
|
||||||
|
print("Unimplemented function")
|
||||||
|
|
||||||
|
def findrecord_test(self, value):
|
||||||
|
# Check if socket is defined; if not, attempt to open one
|
||||||
|
if not self.msock:
|
||||||
|
try:
|
||||||
|
self.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
except:
|
||||||
|
print("No response from layout tool.")
|
||||||
|
|
||||||
|
if self.msock:
|
||||||
|
self.msock.connect(("0.0.0.0", 12946))
|
||||||
|
self.msock.setblocking(False)
|
||||||
|
if self.msock:
|
||||||
|
# Pull name of net or device from 'value'
|
||||||
|
# This is a test:
|
||||||
|
self.msock.sendall(b'box 0 0 100 100\r\n')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
options = []
|
||||||
|
arguments = []
|
||||||
|
for item in sys.argv[1:]:
|
||||||
|
if item.find('-', 0) == 0:
|
||||||
|
options.append(item)
|
||||||
|
else:
|
||||||
|
arguments.append(item)
|
||||||
|
|
||||||
|
root = tkinter.Tk()
|
||||||
|
app = LVSManager(root)
|
||||||
|
if arguments:
|
||||||
|
if len(arguments) >= 2:
|
||||||
|
app.set_project(arguments[0], project_name=arguments[1])
|
||||||
|
else:
|
||||||
|
app.set_project(arguments[0])
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
@ -0,0 +1,819 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# LVS Manager GUI.
|
||||||
|
#
|
||||||
|
# This is a Python tkinter script that handles the
|
||||||
|
# process of running LVS and interpreting results.
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Written by Tim Edwards
|
||||||
|
# efabless, inc.
|
||||||
|
# Version 1. November 30, 2016
|
||||||
|
# Version 2. March 6, 2017. Reads JSON format output
|
||||||
|
# Version 3. April 25, 2018. Handles layout vs. verilog
|
||||||
|
#--------------------------------------------------------
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import datetime
|
||||||
|
import contextlib
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
import tksimpledialog
|
||||||
|
import tooltip
|
||||||
|
from consoletext import ConsoleText
|
||||||
|
from helpwindow import HelpWindow
|
||||||
|
from treeviewsplit import TreeViewSplit
|
||||||
|
|
||||||
|
# User preferences file (if it exists)
|
||||||
|
prefsfile = '~/.profile/prefs.json'
|
||||||
|
|
||||||
|
netgen_script_dir = 'SUBST_SCRIPT_DIR'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Simple dialog for confirming quit
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class ConfirmDialog(tksimpledialog.Dialog):
|
||||||
|
def body(self, master, warning, seed):
|
||||||
|
if warning:
|
||||||
|
ttk.Label(master, text=warning, wraplength=500).grid(row = 0, columnspan = 2, sticky = 'wns')
|
||||||
|
return self
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
return 'okay'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Main class for this application
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class LVSManager(ttk.Frame):
|
||||||
|
"""LVS Manager GUI."""
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
ttk.Frame.__init__(self, parent, *args, **kwargs)
|
||||||
|
self.root = parent
|
||||||
|
self.init_gui()
|
||||||
|
parent.protocol("WM_DELETE_WINDOW", self.on_quit)
|
||||||
|
|
||||||
|
def on_quit(self):
|
||||||
|
"""Exits program."""
|
||||||
|
if self.msock:
|
||||||
|
self.msock.close()
|
||||||
|
quit()
|
||||||
|
|
||||||
|
def init_gui(self):
|
||||||
|
"""Builds GUI."""
|
||||||
|
global prefsfile
|
||||||
|
|
||||||
|
message = []
|
||||||
|
fontsize = 11
|
||||||
|
|
||||||
|
# Read user preferences file, get default font size from it.
|
||||||
|
prefspath = os.path.expanduser(prefsfile)
|
||||||
|
if os.path.exists(prefspath):
|
||||||
|
with open(prefspath, 'r') as f:
|
||||||
|
self.prefs = json.load(f)
|
||||||
|
if 'fontsize' in self.prefs:
|
||||||
|
fontsize = self.prefs['fontsize']
|
||||||
|
else:
|
||||||
|
self.prefs = {}
|
||||||
|
|
||||||
|
s = ttk.Style()
|
||||||
|
|
||||||
|
available_themes = s.theme_names()
|
||||||
|
s.theme_use(available_themes[0])
|
||||||
|
|
||||||
|
s.configure('bg.TFrame', background='gray40')
|
||||||
|
s.configure('italic.TLabel', font=('Helvetica', fontsize, 'italic'))
|
||||||
|
s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'brown', anchor = 'center')
|
||||||
|
s.configure('normal.TLabel', font=('Helvetica', fontsize))
|
||||||
|
s.configure('red.TLabel', font=('Helvetica', fontsize), foreground = 'red')
|
||||||
|
s.configure('green.TLabel', font=('Helvetica', fontsize), foreground = 'green3')
|
||||||
|
s.configure('blue.TLabel', font=('Helvetica', fontsize), foreground = 'blue')
|
||||||
|
s.configure('normal.TButton', font=('Helvetica', fontsize),
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('red.TButton', font=('Helvetica', fontsize), foreground = 'red',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('green.TButton', font=('Helvetica', fontsize), foreground = 'green3',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('blue.TButton', font=('Helvetica', fontsize), foreground = 'blue',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('redtitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'red', border = 3, relief = 'raised')
|
||||||
|
s.configure('bluetitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'blue', border = 3, relief = 'raised')
|
||||||
|
|
||||||
|
# These values to be overridden from arguments
|
||||||
|
self.rootpath = None
|
||||||
|
self.project = None
|
||||||
|
self.logfile = None
|
||||||
|
self.msock = None
|
||||||
|
self.help = None
|
||||||
|
|
||||||
|
# Create the help window
|
||||||
|
if os.path.exists(netgen_script_dir + '/netgen_help.txt'):
|
||||||
|
self.help = HelpWindow(self, fontsize = fontsize)
|
||||||
|
with io.StringIO() as buf, contextlib.redirect_stdout(buf):
|
||||||
|
self.help.add_pages_from_file('lvs_help.txt')
|
||||||
|
message = buf.getvalue()
|
||||||
|
|
||||||
|
# Set the help display to the first page
|
||||||
|
self.help.page(0)
|
||||||
|
|
||||||
|
# Variables used by option menus and other stuff
|
||||||
|
self.project = "(no selection)"
|
||||||
|
self.layout = "(default)"
|
||||||
|
self.schematic = "(default)"
|
||||||
|
self.tech = "(none)"
|
||||||
|
self.lvs_setup = ''
|
||||||
|
self.lvsdata = {}
|
||||||
|
|
||||||
|
# Root window title
|
||||||
|
self.root.title('LVS Manager')
|
||||||
|
self.root.option_add('*tearOff', 'FALSE')
|
||||||
|
self.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
pane = tkinter.PanedWindow(self, orient = 'vertical', sashrelief='groove', sashwidth=6)
|
||||||
|
pane.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
self.toppane = ttk.Frame(pane)
|
||||||
|
self.botpane = ttk.Frame(pane)
|
||||||
|
|
||||||
|
# Get username
|
||||||
|
if 'username' in self.prefs:
|
||||||
|
username = self.prefs['username']
|
||||||
|
else:
|
||||||
|
username = os.environ['USER']
|
||||||
|
|
||||||
|
# Label with the user
|
||||||
|
self.toppane.title_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title_frame.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title = ttk.Label(self.toppane.title_frame, text='User:', style = 'red.TLabel')
|
||||||
|
self.toppane.title_frame.user = ttk.Label(self.toppane.title_frame, text=username, style = 'blue.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title.grid(column=0, row=0, ipadx = 5)
|
||||||
|
self.toppane.title_frame.user.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
self.toppane.title2_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title2_frame.pack(side = 'top', fill = 'x')
|
||||||
|
self.toppane.title2_frame.project_label = ttk.Label(self.toppane.title2_frame, text="Project:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.project_label.grid(column=0, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
# New project select button
|
||||||
|
self.toppane.title2_frame.project_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.project, style='normal.TButton', command=self.choose_project)
|
||||||
|
self.toppane.title2_frame.project_select.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
|
||||||
|
# Show path to project
|
||||||
|
self.toppane.title2_frame.path_label = ttk.Label(self.toppane.title2_frame, text=self.project,
|
||||||
|
style = 'normal.TLabel')
|
||||||
|
self.toppane.title2_frame.path_label.grid(column=2, row=0, ipadx = 5, padx = 10)
|
||||||
|
|
||||||
|
# Show top-level layout cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.tech_label = ttk.Label(self.toppane.title2_frame, text="Technology setup:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title2_frame.tech_label.grid(column=3, row=0, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.tech_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.tech, style='normal.TButton', command=self.choose_tech)
|
||||||
|
self.toppane.title2_frame.tech_select.grid(column=4, row=0, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
self.toppane.title2_frame.layout_label = ttk.Label(self.toppane.title2_frame, text="Layout:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.layout_label.grid(column=0, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.layout_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.layout, style='normal.TButton', command=self.choose_layout)
|
||||||
|
self.toppane.title2_frame.layout_select.grid(column=1, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
# Show top-level schematic cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.schem_label = ttk.Label(self.toppane.title2_frame, text="Schematic:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.schem_label.grid(column=3, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.schem_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.schematic, style='normal.TButton', command=self.choose_netlist)
|
||||||
|
self.toppane.title2_frame.schem_select.grid(column=4, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.layout_select,
|
||||||
|
text = "Select a layout subcirucit to compare")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.schem_select,
|
||||||
|
text = "Select a schematic subcirucit to compare")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
ttk.Separator(self.toppane, orient='horizontal').pack(side = 'top', fill = 'x')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Create listbox of Circuit1 vs. Circuit2 results
|
||||||
|
height = 10
|
||||||
|
self.toppane.lvsreport = TreeViewSplit(self.toppane, fontsize = fontsize)
|
||||||
|
self.toppane.lvsreport.populate("Layout:", [], "Schematic:", [],
|
||||||
|
[["Run", True, self.run_lvs],
|
||||||
|
# ["Find", True, self.findrecord]
|
||||||
|
], height = height)
|
||||||
|
self.toppane.lvsreport.set_title("Line")
|
||||||
|
self.toppane.lvsreport.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.lvsreport.get_button(0), text="Run LVS")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
# ttk.Separator(self, orient='horizontal').grid(column=0, row=3, sticky='ew')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Add a text window below the project name to capture output. Redirect
|
||||||
|
# print statements to it.
|
||||||
|
|
||||||
|
self.botpane.console = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.console.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
self.text_box = ConsoleText(self.botpane.console, wrap='word', height = 4)
|
||||||
|
self.text_box.pack(side='left', fill='both', expand='true')
|
||||||
|
console_scrollbar = ttk.Scrollbar(self.botpane.console)
|
||||||
|
console_scrollbar.pack(side='right', fill='y')
|
||||||
|
# attach console to scrollbar
|
||||||
|
self.text_box.config(yscrollcommand = console_scrollbar.set)
|
||||||
|
console_scrollbar.config(command = self.text_box.yview)
|
||||||
|
|
||||||
|
# Add button bar at the bottom of the window
|
||||||
|
self.botpane.bbar = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.bbar.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
# Define the "quit" button and action
|
||||||
|
self.botpane.bbar.quit_button = ttk.Button(self.botpane.bbar, text='Quit', command=self.on_quit,
|
||||||
|
style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.quit_button.grid(column=0, row=0, padx = 5)
|
||||||
|
|
||||||
|
# Define help button
|
||||||
|
if self.help:
|
||||||
|
self.botpane.bbar.help_button = ttk.Button(self.botpane.bbar, text='Help',
|
||||||
|
command=self.help.open, style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.help_button.grid(column = 2, row = 0, padx = 5)
|
||||||
|
tooltip.ToolTip(self.botpane.bbar.help_button, text = "Show help window")
|
||||||
|
|
||||||
|
# Add the panes once the internal geometry is known.
|
||||||
|
pane.add(self.toppane)
|
||||||
|
pane.add(self.botpane)
|
||||||
|
pane.paneconfig(self.toppane, stretch='first')
|
||||||
|
|
||||||
|
# Redirect stdout and stderr to the console as the last thing to do. . .
|
||||||
|
# Otherwise errors in the GUI get sucked into the void.
|
||||||
|
|
||||||
|
self.stdout = sys.stdout
|
||||||
|
self.stderr = sys.stderr
|
||||||
|
sys.stdout = ConsoleText.StdoutRedirector(self.text_box)
|
||||||
|
sys.stderr = ConsoleText.StderrRedirector(self.text_box)
|
||||||
|
|
||||||
|
if message:
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def logprint(self, message, doflush=False):
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.buffer.write(message.encode('utf-8'))
|
||||||
|
self.logfile.buffer.write('\n'.encode('utf-8'))
|
||||||
|
if doflush:
|
||||||
|
self.logfile.flush()
|
||||||
|
|
||||||
|
def printout(self, output):
|
||||||
|
# Generate output
|
||||||
|
if not output:
|
||||||
|
return
|
||||||
|
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
print(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
pritn(line)
|
||||||
|
|
||||||
|
def printwarn(self, output):
|
||||||
|
# Check output for warning or error
|
||||||
|
if not output:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
warnrex = re.compile('.*warning', re.IGNORECASE)
|
||||||
|
errrex = re.compile('.*error', re.IGNORECASE)
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
ematch = errrex.match(line)
|
||||||
|
if ematch:
|
||||||
|
errors += 1
|
||||||
|
if ematch or wmatch:
|
||||||
|
print(line)
|
||||||
|
return errors
|
||||||
|
|
||||||
|
def choose_tech(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/tech',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
techname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Tcl script", "*.tcl"),("All Files","*.*")),
|
||||||
|
title = "Choose a netgen technology setup script.")
|
||||||
|
if techname != '':
|
||||||
|
print("Selected technology setup script " + techname)
|
||||||
|
techbase = os.path.split(techname)[1]
|
||||||
|
self.tech = os.path.splitext(techbase)[0]
|
||||||
|
self.lvs_setup = techname
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||||
|
|
||||||
|
def choose_layout(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/layout',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Magic layout", "*.mag"),("All Files","*.*")),
|
||||||
|
title = "Choose a layout cell to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.layout = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
|
||||||
|
def choose_netlist(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||||
|
title = "Choose a netlist to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.schematic = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
fileext = os.path.splitext(cellbase)[1]
|
||||||
|
if fileext == '.v':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||||
|
elif fileext == '.cdl':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Unknown netlist:')
|
||||||
|
|
||||||
|
def choose_project(self):
|
||||||
|
project = filedialog.askdirectory(initialdir = os.getcwd(),
|
||||||
|
title = "Find a project.")
|
||||||
|
if project != '':
|
||||||
|
print("Selected project " + str(project))
|
||||||
|
result = self.set_project(project)
|
||||||
|
|
||||||
|
def set_project(self, rootpath, project_name=None):
|
||||||
|
|
||||||
|
# Check if rootpath is valid. For LVS, there should be subdirectories
|
||||||
|
# "layout/" and "netlist/" or "verilog/".
|
||||||
|
|
||||||
|
haslay = os.path.isdir(rootpath + '/layout')
|
||||||
|
hasvlog = os.path.isdir(rootpath + '/verilog')
|
||||||
|
hasnet = os.path.isdir(rootpath + '/netlist')
|
||||||
|
if not haslay or not (hasvlog or hasnet):
|
||||||
|
if not haslay:
|
||||||
|
print("Project path has no layout (/layout) subdirectory.")
|
||||||
|
if not (hasvlog or hasnet):
|
||||||
|
print("Project path has no verilog (/verilog), or netlist (/netlist) subdirectory.")
|
||||||
|
# Continue anyway; assume that netlists will be selected manually
|
||||||
|
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
if not project_name:
|
||||||
|
project = os.path.split(rootpath)[1]
|
||||||
|
else:
|
||||||
|
project = project_name
|
||||||
|
|
||||||
|
if self.project != project:
|
||||||
|
|
||||||
|
self.rootpath = rootpath
|
||||||
|
self.project = project
|
||||||
|
|
||||||
|
# Clear out old project data
|
||||||
|
self.toppane.lvsreport.repopulate([], [])
|
||||||
|
|
||||||
|
# Close any open logfile.
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||||
|
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||||
|
# Print some initial information to the logfile.
|
||||||
|
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||||
|
doflush=True)
|
||||||
|
|
||||||
|
# Update project button
|
||||||
|
self.toppane.title2_frame.project_select.config(text = self.project)
|
||||||
|
self.toppane.title2_frame.path_label.config(text = self.rootpath)
|
||||||
|
# Cell name is the same as project name initially
|
||||||
|
self.layout = self.project
|
||||||
|
self.schematic = self.project
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
|
||||||
|
# Update schematic button
|
||||||
|
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||||
|
|
||||||
|
# If there is a comparison file that post-dates both netlists, load it.
|
||||||
|
self.check_lvs()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_layout_out_of_date(self, spipath, layoutpath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the layouts
|
||||||
|
# (layoutpath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(layoutpath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
lay_statbuf = os.stat(layoutpath)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-layout is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
layoutdir = os.path.split(layoutpath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
sublayout = layoutdir + '/' + subname + '.mag'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(sublayout):
|
||||||
|
sub_statbuf = os.stat(sublayout)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_schematic_out_of_date(self, spipath, schempath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the schematics
|
||||||
|
# (schempath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(schempath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
sch_statbuf = os.stat(schempath)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-schematic is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
schemdir = os.path.split(schempath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
# NOTE: Electric uses library:cell internally to track libraries,
|
||||||
|
# and maps the ":" to "__" in the netlist. Not entirely certain that
|
||||||
|
# the double-underscore uniquely identifies the library:cell. . .
|
||||||
|
librex = re.compile('(.*)__(.*)', re.IGNORECASE)
|
||||||
|
lmatch = librex.match(subname)
|
||||||
|
if lmatch:
|
||||||
|
elecpath = os.path.split(os.path.split(schempath)[0])[0]
|
||||||
|
libname = lmatch.group(1)
|
||||||
|
subschem = elecpath + '/' + libname + '.delib/' + lmatch.group(2) + '.sch'
|
||||||
|
else:
|
||||||
|
libname = {}
|
||||||
|
subschem = schemdir + '/' + subname + '.sch'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(subschem):
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sub_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
# mapping of characters to what's allowed in SPICE makes finding
|
||||||
|
# the associated schematic file a bit difficult. Requires wild-card
|
||||||
|
# searching.
|
||||||
|
elif libname:
|
||||||
|
restr = lmatch.group(2) + '.sch'
|
||||||
|
restr = restr.replace('.', '\.')
|
||||||
|
restr = restr.replace('_', '.')
|
||||||
|
schrex = re.compile(restr, re.IGNORECASE)
|
||||||
|
libpath = elecpath + '/' + libname + '.delib'
|
||||||
|
if os.path.exists(libpath):
|
||||||
|
liblist = os.listdir(libpath)
|
||||||
|
for file in liblist:
|
||||||
|
lmatch = schrex.match(file)
|
||||||
|
if lmatch:
|
||||||
|
subschem = libpath + '/' + file
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_lvs(self):
|
||||||
|
# If both netlists exist, and comp.json is more recent than both, then
|
||||||
|
# load LVS results from comp.json
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||||
|
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
|
||||||
|
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||||
|
magtime = os.stat(layout_path).st_mtime
|
||||||
|
schemtime = os.stat(net_path).st_mtime
|
||||||
|
comptime = os.stat(comp_path).st_mtime
|
||||||
|
if comptime > magtime and comptime > schemtime:
|
||||||
|
print("Loading LVS results from file.")
|
||||||
|
self.generate(comp_path)
|
||||||
|
|
||||||
|
def generate_layout_netlist(self, layout_path, layout_src, project_path):
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if self.check_layout_out_of_date(layout_path, layout_src):
|
||||||
|
print('Generating layout netlist.')
|
||||||
|
self.update_idletasks()
|
||||||
|
mproc = subprocess.Popen(['magic', '-dnull', '-noconsole',
|
||||||
|
self.layout], stdin = subprocess.PIPE, stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE, cwd = project_path + '/layout',
|
||||||
|
universal_newlines = True)
|
||||||
|
mproc.stdin.write("select top cell\n")
|
||||||
|
mproc.stdin.write("expand\n")
|
||||||
|
mproc.stdin.write("extract all\n")
|
||||||
|
mproc.stdin.write("ext2spice hierarchy on\n")
|
||||||
|
mproc.stdin.write("ext2spice format ngspice\n")
|
||||||
|
mproc.stdin.write("ext2spice scale off\n")
|
||||||
|
mproc.stdin.write("ext2spice renumber off\n")
|
||||||
|
mproc.stdin.write("ext2spice subcircuit top auto\n")
|
||||||
|
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice blackbox on\n")
|
||||||
|
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||||
|
mproc.stdin.write("quit -noprompt\n")
|
||||||
|
magicout = mproc.communicate()[0]
|
||||||
|
self.printwarn(magicout)
|
||||||
|
if mproc.returncode != 0:
|
||||||
|
print('Failure to generate new layout netlist.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Move .spi netlist to project_dir/netlist/lvs/
|
||||||
|
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||||
|
# Remove extraction files
|
||||||
|
for file in os.listdir(project_path + '/layout'):
|
||||||
|
if os.path.splitext(file)[1] == '.ext':
|
||||||
|
os.remove(project_path + '/layout/' + file)
|
||||||
|
else:
|
||||||
|
print('Layout netlist is up-to-date, not regenerating.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run_lvs(self, value):
|
||||||
|
# "value" is ignored (?)
|
||||||
|
|
||||||
|
# Check if netlists exist and are current; otherwise create them.
|
||||||
|
# Then run LVS.
|
||||||
|
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
has_vlog = False
|
||||||
|
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||||
|
|
||||||
|
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||||
|
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||||
|
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||||
|
|
||||||
|
# Does the setup file exist (this is optional)?
|
||||||
|
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||||
|
print('No technology setup file selected.')
|
||||||
|
|
||||||
|
# Does schematic netlist exist?
|
||||||
|
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||||
|
print('Error: No schematic netlist or verilog netlist.')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Does LVS netlist subdirectory exist?
|
||||||
|
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||||
|
os.makedirs(project_path + '/netlist/lvs')
|
||||||
|
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Final check
|
||||||
|
if not os.path.isfile(layout_path):
|
||||||
|
print('Error: No netlist generated from magic.')
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Read in netlist and convert commas from [X,Y] arrays to vertical bars
|
||||||
|
# as something that can be converted back as necessary. ngspice treats
|
||||||
|
# commas as special characters for some reason.
|
||||||
|
with open(layout_path) as ifile:
|
||||||
|
spitext = ifile.read()
|
||||||
|
|
||||||
|
# spilines = spitext.replace(',', '|')
|
||||||
|
# with open(layout_path, 'w') as ofile:
|
||||||
|
# ofile.write(spilines)
|
||||||
|
|
||||||
|
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||||
|
# not, then assume it is the top level.
|
||||||
|
|
||||||
|
is_subckt = False
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
if subname == self.layout:
|
||||||
|
is_subckt = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if is_subckt:
|
||||||
|
layout_arg = layout_path + ' ' + self.layout
|
||||||
|
layout_text = '"' + layout_arg + '"'
|
||||||
|
else:
|
||||||
|
layout_arg = layout_path
|
||||||
|
layout_text = layout_arg
|
||||||
|
|
||||||
|
if has_vlog:
|
||||||
|
schem_arg = vlog_path + ' ' + self.schematic
|
||||||
|
else:
|
||||||
|
schem_arg = net_path + ' ' + self.schematic
|
||||||
|
schem_text = '"' + schem_arg + '"'
|
||||||
|
|
||||||
|
# Remove any previous comparison output file
|
||||||
|
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||||
|
if os.path.exists(comp_out_path):
|
||||||
|
os.remove(comp_out_path)
|
||||||
|
|
||||||
|
# Run netgen as subprocess
|
||||||
|
print('Running: netgen -batch lvs ' + layout_text +
|
||||||
|
' ' + schem_text + ' ' + self.lvs_setup + ' ' + comp_out_path +
|
||||||
|
' -json -blackbox')
|
||||||
|
# Note: Because arguments to subprocess are list items, the {filename cell}
|
||||||
|
# pair does *not* have to be quoted or braced. Doing so causes a parse
|
||||||
|
# error.
|
||||||
|
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||||
|
layout_arg, schem_arg,
|
||||||
|
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||||
|
cwd=project_path + '/layout',
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||||
|
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||||
|
self.watchclock(comp_path)
|
||||||
|
|
||||||
|
def watchclock(self, filename):
|
||||||
|
if self.lvsproc == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
lvs_status = self.lvsproc.poll()
|
||||||
|
sresult = select.select([self.lvsproc.stdout, self.lvsproc.stderr], [], [], 0)[0]
|
||||||
|
if self.lvsproc.stdout in sresult:
|
||||||
|
outstring = self.lvsproc.stdout.readline().decode().strip()
|
||||||
|
self.logprint(outstring, doflush=True)
|
||||||
|
print(outstring)
|
||||||
|
elif self.lvsproc.stderr in sresult:
|
||||||
|
errstring = self.lvsproc.stderr.readline().decode().strip()
|
||||||
|
self.logprint(errstring, doflush = True)
|
||||||
|
print(errstring, file=sys.stderr)
|
||||||
|
|
||||||
|
if lvs_status != None:
|
||||||
|
print("netgen LVS exited with status " + str(lvs_status))
|
||||||
|
self.lvsproc = None
|
||||||
|
if lvs_status != 0:
|
||||||
|
print('Errors encountered in LVS.')
|
||||||
|
self.logprint('Errors in LVS, lvs status = ' + str(lvs_status), doflush=True)
|
||||||
|
# Done; now read comp.json and fill the treeview listbox.
|
||||||
|
self.generate(filename)
|
||||||
|
else:
|
||||||
|
self.after(500, lambda: self.watchclock(filename))
|
||||||
|
|
||||||
|
# Generate display from "comp.out" file (json file now preferred)
|
||||||
|
|
||||||
|
def generate_orig(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
lvslines = ifile.read().splitlines()
|
||||||
|
for line in lvslines:
|
||||||
|
if '|' in line:
|
||||||
|
# parts = line.split('|')
|
||||||
|
# lefttext.append(parts[0])
|
||||||
|
# righttext.append(parts[1])
|
||||||
|
lefttext.append(line[0:42].strip())
|
||||||
|
righttext.append(line[44:].strip())
|
||||||
|
else:
|
||||||
|
lefttext.append(line)
|
||||||
|
righttext.append('')
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.repopulate(lefttext, righttext)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
# Generate output from LVS report JSON file comp.json
|
||||||
|
|
||||||
|
def generate(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
self.lvsdata = json.load(ifile)
|
||||||
|
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.json_repopulate(self.lvsdata)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
def findrecord(self, value):
|
||||||
|
print("Unimplemented function")
|
||||||
|
|
||||||
|
def findrecord_test(self, value):
|
||||||
|
# Check if socket is defined; if not, attempt to open one
|
||||||
|
if not self.msock:
|
||||||
|
try:
|
||||||
|
self.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
except:
|
||||||
|
print("No response from layout tool.")
|
||||||
|
|
||||||
|
if self.msock:
|
||||||
|
self.msock.connect(("0.0.0.0", 12946))
|
||||||
|
self.msock.setblocking(False)
|
||||||
|
if self.msock:
|
||||||
|
# Pull name of net or device from 'value'
|
||||||
|
# This is a test:
|
||||||
|
self.msock.sendall(b'box 0 0 100 100\r\n')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
options = []
|
||||||
|
arguments = []
|
||||||
|
for item in sys.argv[1:]:
|
||||||
|
if item.find('-', 0) == 0:
|
||||||
|
options.append(item)
|
||||||
|
else:
|
||||||
|
arguments.append(item)
|
||||||
|
|
||||||
|
root = tkinter.Tk()
|
||||||
|
app = LVSManager(root)
|
||||||
|
if arguments:
|
||||||
|
if len(arguments) >= 2:
|
||||||
|
app.set_project(arguments[0], project_name=arguments[1])
|
||||||
|
else:
|
||||||
|
app.set_project(arguments[0])
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
# Dialog class for tkinter
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
|
class Dialog(tkinter.Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, message = None, title = None, seed = None, border = 'blue', **kwargs):
|
||||||
|
|
||||||
|
tkinter.Toplevel.__init__(self, parent)
|
||||||
|
self.transient(parent)
|
||||||
|
|
||||||
|
if title:
|
||||||
|
self.title(title)
|
||||||
|
|
||||||
|
self.configure(background=border, padx=2, pady=2)
|
||||||
|
self.obox = ttk.Frame(self)
|
||||||
|
self.obox.pack(side = 'left', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
self.parent = parent
|
||||||
|
self.result = None
|
||||||
|
body = ttk.Frame(self.obox)
|
||||||
|
self.initial_focus = self.body(body, message, seed, **kwargs)
|
||||||
|
body.pack(padx = 5, pady = 5)
|
||||||
|
self.buttonbox()
|
||||||
|
self.grab_set()
|
||||||
|
|
||||||
|
if not self.initial_focus:
|
||||||
|
self.initial_focus = self
|
||||||
|
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.cancel)
|
||||||
|
self.geometry("+%d+%d" % (parent.winfo_rootx() + 50,
|
||||||
|
parent.winfo_rooty() + 50))
|
||||||
|
|
||||||
|
self.initial_focus.focus_set()
|
||||||
|
self.wait_window(self)
|
||||||
|
|
||||||
|
# Construction hooks
|
||||||
|
|
||||||
|
def body(self, master, **kwargs):
|
||||||
|
# Create dialog body. Return widget that should have
|
||||||
|
# initial focus. This method should be overridden
|
||||||
|
pass
|
||||||
|
|
||||||
|
def buttonbox(self):
|
||||||
|
# Add standard button box. Override if you don't want the
|
||||||
|
# standard buttons
|
||||||
|
|
||||||
|
box = ttk.Frame(self.obox)
|
||||||
|
|
||||||
|
self.okb = ttk.Button(box, text="OK", width=10, command=self.ok, default='active')
|
||||||
|
self.okb.pack(side='left', padx=5, pady=5)
|
||||||
|
w = ttk.Button(box, text="Cancel", width=10, command=self.cancel)
|
||||||
|
w.pack(side='left', padx=5, pady=5)
|
||||||
|
|
||||||
|
self.bind("<Return>", self.ok)
|
||||||
|
self.bind("<Escape>", self.cancel)
|
||||||
|
box.pack(fill='x', expand='true')
|
||||||
|
|
||||||
|
# Standard button semantics
|
||||||
|
|
||||||
|
def ok(self, event=None):
|
||||||
|
|
||||||
|
if not self.validate():
|
||||||
|
self.initial_focus.focus_set() # put focus back
|
||||||
|
return
|
||||||
|
|
||||||
|
self.withdraw()
|
||||||
|
self.update_idletasks()
|
||||||
|
self.result = self.apply()
|
||||||
|
self.cancel()
|
||||||
|
|
||||||
|
def cancel(self, event=None):
|
||||||
|
|
||||||
|
# Put focus back to the parent window
|
||||||
|
self.parent.focus_set()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
return 1 # Override this
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
return None # Override this
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
'''Michael Lange <klappnase (at) freakmail (dot) de>
|
||||||
|
The ToolTip class provides a flexible tooltip widget for tkinter; it is based on IDLE's ToolTip
|
||||||
|
module which unfortunately seems to be broken (at least the version I saw).
|
||||||
|
INITIALIZATION OPTIONS:
|
||||||
|
anchor : where the text should be positioned inside the widget, must be on of "n", "s", "e", "w", "nw" and so on;
|
||||||
|
default is "center"
|
||||||
|
bd : borderwidth of the widget; default is 1 (NOTE: don't use "borderwidth" here)
|
||||||
|
bg : background color to use for the widget; default is "lightyellow" (NOTE: don't use "background")
|
||||||
|
delay : time in ms that it takes for the widget to appear on the screen when the mouse pointer has
|
||||||
|
entered the parent widget; default is 1500
|
||||||
|
fg : foreground (i.e. text) color to use; default is "black" (NOTE: don't use "foreground")
|
||||||
|
follow_mouse : if set to 1 the tooltip will follow the mouse pointer instead of being displayed
|
||||||
|
outside of the parent widget; this may be useful if you want to use tooltips for
|
||||||
|
large widgets like listboxes or canvases; default is 0
|
||||||
|
font : font to use for the widget; default is system specific
|
||||||
|
justify : how multiple lines of text will be aligned, must be "left", "right" or "center"; default is "left"
|
||||||
|
padx : extra space added to the left and right within the widget; default is 4
|
||||||
|
pady : extra space above and below the text; default is 2
|
||||||
|
relief : one of "flat", "ridge", "groove", "raised", "sunken" or "solid"; default is "solid"
|
||||||
|
state : must be "normal" or "disabled"; if set to "disabled" the tooltip will not appear; default is "normal"
|
||||||
|
text : the text that is displayed inside the widget
|
||||||
|
textvariable : if set to an instance of tkinter.StringVar() the variable's value will be used as text for the widget
|
||||||
|
width : width of the widget; the default is 0, which means that "wraplength" will be used to limit the widgets width
|
||||||
|
wraplength : limits the number of characters in each line; default is 150
|
||||||
|
|
||||||
|
WIDGET METHODS:
|
||||||
|
configure(**opts) : change one or more of the widget's options as described above; the changes will take effect the
|
||||||
|
next time the tooltip shows up; NOTE: follow_mouse cannot be changed after widget initialization
|
||||||
|
|
||||||
|
Other widget methods that might be useful if you want to subclass ToolTip:
|
||||||
|
enter() : callback when the mouse pointer enters the parent widget
|
||||||
|
leave() : called when the mouse pointer leaves the parent widget
|
||||||
|
motion() : is called when the mouse pointer moves inside the parent widget if follow_mouse is set to 1 and the
|
||||||
|
tooltip has shown up to continually update the coordinates of the tooltip window
|
||||||
|
coords() : calculates the screen coordinates of the tooltip window
|
||||||
|
create_contents() : creates the contents of the tooltip window (by default a tkinter.Label)
|
||||||
|
'''
|
||||||
|
# Ideas gleaned from PySol
|
||||||
|
|
||||||
|
import tkinter
|
||||||
|
|
||||||
|
class ToolTip:
|
||||||
|
def __init__(self, master, text='Your text here', delay=1500, **opts):
|
||||||
|
self.master = master
|
||||||
|
self._opts = {'anchor':'center', 'bd':1, 'bg':'lightyellow', 'delay':delay, 'fg':'black',\
|
||||||
|
'follow_mouse':0, 'font':None, 'justify':'left', 'padx':4, 'pady':2,\
|
||||||
|
'relief':'solid', 'state':'normal', 'text':text, 'textvariable':None,\
|
||||||
|
'width':0, 'wraplength':150}
|
||||||
|
self.configure(**opts)
|
||||||
|
self._tipwindow = None
|
||||||
|
self._id = None
|
||||||
|
self._id1 = self.master.bind("<Enter>", self.enter, '+')
|
||||||
|
self._id2 = self.master.bind("<Leave>", self.leave, '+')
|
||||||
|
self._id3 = self.master.bind("<ButtonPress>", self.leave, '+')
|
||||||
|
self._follow_mouse = 0
|
||||||
|
if self._opts['follow_mouse']:
|
||||||
|
self._id4 = self.master.bind("<Motion>", self.motion, '+')
|
||||||
|
self._follow_mouse = 1
|
||||||
|
|
||||||
|
def configure(self, **opts):
|
||||||
|
for key in opts:
|
||||||
|
if key in self._opts:
|
||||||
|
self._opts[key] = opts[key]
|
||||||
|
else:
|
||||||
|
KeyError = 'KeyError: Unknown option: "%s"' %key
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
|
##----these methods handle the callbacks on "<Enter>", "<Leave>" and "<Motion>"---------------##
|
||||||
|
##----events on the parent widget; override them if you want to change the widget's behavior--##
|
||||||
|
|
||||||
|
def enter(self, event=None):
|
||||||
|
self._schedule()
|
||||||
|
|
||||||
|
def leave(self, event=None):
|
||||||
|
self._unschedule()
|
||||||
|
self._hide()
|
||||||
|
|
||||||
|
def motion(self, event=None):
|
||||||
|
if self._tipwindow and self._follow_mouse:
|
||||||
|
x, y = self.coords()
|
||||||
|
self._tipwindow.wm_geometry("+%d+%d" % (x, y))
|
||||||
|
|
||||||
|
##------the methods that do the work:---------------------------------------------------------##
|
||||||
|
|
||||||
|
def _schedule(self):
|
||||||
|
self._unschedule()
|
||||||
|
if self._opts['state'] == 'disabled':
|
||||||
|
return
|
||||||
|
self._id = self.master.after(self._opts['delay'], self._show)
|
||||||
|
|
||||||
|
def _unschedule(self):
|
||||||
|
id = self._id
|
||||||
|
self._id = None
|
||||||
|
if id:
|
||||||
|
self.master.after_cancel(id)
|
||||||
|
|
||||||
|
def _show(self):
|
||||||
|
if self._opts['state'] == 'disabled':
|
||||||
|
self._unschedule()
|
||||||
|
return
|
||||||
|
if not self._tipwindow:
|
||||||
|
self._tipwindow = tw = tkinter.Toplevel(self.master)
|
||||||
|
# hide the window until we know the geometry
|
||||||
|
tw.withdraw()
|
||||||
|
tw.wm_overrideredirect(1)
|
||||||
|
|
||||||
|
if tw.tk.call("tk", "windowingsystem") == 'aqua':
|
||||||
|
tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w, "help", "none")
|
||||||
|
|
||||||
|
self.create_contents()
|
||||||
|
tw.update_idletasks()
|
||||||
|
x, y = self.coords()
|
||||||
|
tw.wm_geometry("+%d+%d" % (x, y))
|
||||||
|
tw.deiconify()
|
||||||
|
tw.lift()
|
||||||
|
|
||||||
|
def _hide(self):
|
||||||
|
tw = self._tipwindow
|
||||||
|
self._tipwindow = None
|
||||||
|
if tw:
|
||||||
|
tw.destroy()
|
||||||
|
|
||||||
|
##----these methods might be overridden in derived classes:----------------------------------##
|
||||||
|
|
||||||
|
def coords(self):
|
||||||
|
# The tip window must be completely outside the master widget;
|
||||||
|
# otherwise when the mouse enters the tip window we get
|
||||||
|
# a leave event and it disappears, and then we get an enter
|
||||||
|
# event and it reappears, and so on forever :-(
|
||||||
|
# or we take care that the mouse pointer is always outside the tipwindow :-)
|
||||||
|
tw = self._tipwindow
|
||||||
|
twx, twy = tw.winfo_reqwidth(), tw.winfo_reqheight()
|
||||||
|
w, h = tw.winfo_screenwidth(), tw.winfo_screenheight()
|
||||||
|
# calculate the y coordinate:
|
||||||
|
if self._follow_mouse:
|
||||||
|
y = tw.winfo_pointery() + 20
|
||||||
|
# make sure the tipwindow is never outside the screen:
|
||||||
|
if y + twy > h:
|
||||||
|
y = y - twy - 30
|
||||||
|
else:
|
||||||
|
y = self.master.winfo_rooty() + self.master.winfo_height() + 3
|
||||||
|
if y + twy > h:
|
||||||
|
y = self.master.winfo_rooty() - twy - 3
|
||||||
|
# we can use the same x coord in both cases:
|
||||||
|
x = tw.winfo_pointerx() - twx / 2
|
||||||
|
if x < 0:
|
||||||
|
x = 0
|
||||||
|
elif x + twx > w:
|
||||||
|
x = w - twx
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
def create_contents(self):
|
||||||
|
opts = self._opts.copy()
|
||||||
|
for opt in ('delay', 'follow_mouse', 'state'):
|
||||||
|
del opts[opt]
|
||||||
|
label = tkinter.Label(self._tipwindow, **opts)
|
||||||
|
label.pack()
|
||||||
|
|
@ -0,0 +1,653 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
# Simple ttk treeview with split view, scrollbar, and
|
||||||
|
# row of callback buttons
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Tree view used as a multi-column list box
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class TreeViewSplit(ttk.Frame):
|
||||||
|
def __init__(self, parent, fontsize=11, *args, **kwargs):
|
||||||
|
ttk.Frame.__init__(self, parent, *args, **kwargs)
|
||||||
|
s = ttk.Style()
|
||||||
|
s.configure('normal.TLabel', font=('Helvetica', fontsize))
|
||||||
|
s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold'))
|
||||||
|
s.configure('normal.TButton', font=('Helvetica', fontsize),
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('Treeview.Heading', font=('Helvetica', fontsize, 'bold'))
|
||||||
|
s.configure('Treeview.Column', font=('Helvetica', fontsize))
|
||||||
|
self.fontsize = fontsize
|
||||||
|
|
||||||
|
# Last item is a list of 2-item lists, each containing the name of a button
|
||||||
|
# to place along the button bar at the bottom, and a callback function to
|
||||||
|
# run when the button is pressed.
|
||||||
|
|
||||||
|
def populate(self, title1="", item1list=[], title2="", item2list=[], buttons=[], height=10):
|
||||||
|
self.item1list = item1list[:]
|
||||||
|
self.item2list = item2list[:]
|
||||||
|
columns = [0, 1]
|
||||||
|
|
||||||
|
treeFrame = ttk.Frame(self)
|
||||||
|
treeFrame.pack(side='top', padx=5, pady=5, fill='both', expand='true')
|
||||||
|
|
||||||
|
scrollBar = ttk.Scrollbar(treeFrame)
|
||||||
|
scrollBar.pack(side='right', fill='y')
|
||||||
|
self.treeView = ttk.Treeview(treeFrame, selectmode='browse', columns=columns, height=height)
|
||||||
|
self.treeView.pack(side='left', fill='both', expand='true')
|
||||||
|
scrollBar.config(command=self.treeView.yview)
|
||||||
|
self.treeView.config(yscrollcommand=scrollBar.set)
|
||||||
|
self.treeView.column('#0', width=120, stretch='false')
|
||||||
|
self.treeView.heading(0, text=title1, anchor='w')
|
||||||
|
self.treeView.heading(1, text=title2, anchor='w')
|
||||||
|
buttonFrame = ttk.Frame(self)
|
||||||
|
buttonFrame.pack(side='bottom', fill='x')
|
||||||
|
|
||||||
|
self.treeView.tag_configure('select',background='darkslategray',foreground='white')
|
||||||
|
|
||||||
|
# Test type tags
|
||||||
|
self.treeView.tag_configure('error', font=('Helvetica', self.fontsize - 1), foreground = 'red')
|
||||||
|
self.treeView.tag_configure('clean', font=('Helvetica', self.fontsize - 1), foreground = 'green3')
|
||||||
|
self.treeView.tag_configure('normal', font=('Helvetica', self.fontsize - 1), foreground = 'black')
|
||||||
|
self.treeView.tag_configure('prep', font=('Helvetica', self.fontsize, 'bold italic'),
|
||||||
|
foreground = 'black', anchor = 'center')
|
||||||
|
self.treeView.tag_configure('header1', font=('Helvetica', self.fontsize, 'bold italic'),
|
||||||
|
foreground = 'brown', anchor = 'center')
|
||||||
|
self.treeView.tag_configure('header2', font=('Helvetica', self.fontsize - 1, 'bold'),
|
||||||
|
foreground = 'blue', anchor = 'center')
|
||||||
|
self.treeView.tag_configure('header3', font=('Helvetica', self.fontsize - 1, 'italic'),
|
||||||
|
foreground = 'green4', anchor = 'center')
|
||||||
|
self.treeView.tag_configure('header4', font=('Helvetica', self.fontsize - 1),
|
||||||
|
foreground = 'purple', anchor = 'center')
|
||||||
|
|
||||||
|
|
||||||
|
self.func_buttons = []
|
||||||
|
for button in buttons:
|
||||||
|
func = button[2]
|
||||||
|
# Each func_buttons entry is a list of two items; first is the
|
||||||
|
# button widget, and the second is a boolean that is True if the
|
||||||
|
# button is to be present always, False if the button is only
|
||||||
|
# present when there are entries in the itemlists.
|
||||||
|
self.func_buttons.append([ttk.Button(buttonFrame, text=button[0],
|
||||||
|
style = 'normal.TButton',
|
||||||
|
command = lambda func=func: self.func_callback(func)),
|
||||||
|
button[1]])
|
||||||
|
|
||||||
|
self.selectcallback = None
|
||||||
|
self.lastselected = None
|
||||||
|
self.lasttag = None
|
||||||
|
self.repopulate(item1list, item2list)
|
||||||
|
|
||||||
|
def get_button(self, index):
|
||||||
|
if index >= 0 and index < len(self.func_buttons):
|
||||||
|
return self.func_buttons[index][0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_title(self, title):
|
||||||
|
self.treeView.heading('#0', text=title, anchor='w')
|
||||||
|
|
||||||
|
def repopulate(self, item1list=[], item2list=[]):
|
||||||
|
|
||||||
|
# Remove all children of treeview
|
||||||
|
self.treeView.delete(*self.treeView.get_children())
|
||||||
|
|
||||||
|
self.item1list = item1list[:]
|
||||||
|
self.item2list = item2list[:]
|
||||||
|
lines = max(len(self.item1list), len(self.item2list))
|
||||||
|
|
||||||
|
# Parse the information coming from comp.out. This is preferably
|
||||||
|
# handled from inside netgen, but that requires development in netgen.
|
||||||
|
# Note: A top-level group is denoted by an empty string.
|
||||||
|
|
||||||
|
nested = ['']
|
||||||
|
if lines > 0:
|
||||||
|
# print("Create item ID 0 parent = ''")
|
||||||
|
self.treeView.insert(nested[-1], 'end', text='-', iid='0',
|
||||||
|
value=['Initialize', 'Initialize'], tags=['prep'])
|
||||||
|
nested.append('0')
|
||||||
|
tagstyle = 'header1'
|
||||||
|
|
||||||
|
emptyrec = re.compile('^[\t ]*$')
|
||||||
|
subrex = re.compile('Subcircuit summary')
|
||||||
|
cktrex = re.compile('Circuit[\t ]+[12]:[\t ]+([^ \t]+)')
|
||||||
|
netrex = re.compile('NET mismatches')
|
||||||
|
devrex = re.compile('DEVICE mismatches')
|
||||||
|
seprex = re.compile('-----')
|
||||||
|
sumrex = re.compile('Netlists ')
|
||||||
|
matchrex = re.compile('.*\*\*Mismatch\*\*')
|
||||||
|
incircuit = False
|
||||||
|
watchgroup = False
|
||||||
|
groupnum = 0
|
||||||
|
|
||||||
|
for item1, item2, index in zip(self.item1list, self.item2list, range(lines)):
|
||||||
|
cname1 = 'Layout' # Placeholder
|
||||||
|
cname2 = 'Schematic' # Placeholder
|
||||||
|
|
||||||
|
# Remove blank lines from the display
|
||||||
|
lmatch = emptyrec.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
lmatch = emptyrec.match(item2)
|
||||||
|
if lmatch:
|
||||||
|
continue
|
||||||
|
index = str(index + 1)
|
||||||
|
# Parse text to determine how to structure and display it.
|
||||||
|
tagstyle = 'normal'
|
||||||
|
nextnest = None
|
||||||
|
lmatch = subrex.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
nested = [''] # pop back to topmost level
|
||||||
|
nextnest = index
|
||||||
|
tagstyle = 'header1'
|
||||||
|
incircuit = False
|
||||||
|
watchgroup = False
|
||||||
|
groupnum = 0
|
||||||
|
item1 = 'Layout compare'
|
||||||
|
item2 = 'Schematic compare'
|
||||||
|
else:
|
||||||
|
lmatch = cktrex.match(item1)
|
||||||
|
if lmatch and not incircuit:
|
||||||
|
# Pick up circuit names and replace them in the title, then use them
|
||||||
|
# for all following titles.
|
||||||
|
cname1 = lmatch.group(1)
|
||||||
|
lmatch = cktrex.match(item2)
|
||||||
|
cname2 = lmatch.group(1)
|
||||||
|
print("Circuit names " + cname1 + " " + cname2)
|
||||||
|
# Rewrite title
|
||||||
|
cktitem = self.treeView.item(nested[-1], values=[cname1 + ' compare',
|
||||||
|
cname2 + ' compare'])
|
||||||
|
nextnest = index
|
||||||
|
tagstyle = 'header2'
|
||||||
|
incircuit = True
|
||||||
|
item1 = cname1 + ' Summary'
|
||||||
|
item2 = cname2 + ' Summary'
|
||||||
|
elif lmatch:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
lmatch = netrex.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
if watchgroup:
|
||||||
|
nested = nested[0:-1]
|
||||||
|
nested = nested[0:-1]
|
||||||
|
nextnest = index
|
||||||
|
tagstyle = 'header2'
|
||||||
|
groupnum = 1
|
||||||
|
watchgroup = True
|
||||||
|
item1 = cname1 + ' Net mismatches'
|
||||||
|
item2 = cname2 + ' Net mismatches'
|
||||||
|
else:
|
||||||
|
lmatch = devrex.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
if watchgroup:
|
||||||
|
nested = nested[0:-1]
|
||||||
|
nested = nested[0:-1]
|
||||||
|
nextnest = index
|
||||||
|
tagstyle = 'header2'
|
||||||
|
groupnum = 1
|
||||||
|
watchgroup = True
|
||||||
|
item1 = cname1 + ' Device mismatches'
|
||||||
|
item2 = cname2 + ' Device mismatches'
|
||||||
|
else:
|
||||||
|
lmatch = seprex.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
if watchgroup:
|
||||||
|
tagstyle = 'header3'
|
||||||
|
item1 = 'Group ' + str(groupnum)
|
||||||
|
item2 = 'Group ' + str(groupnum)
|
||||||
|
if groupnum > 1:
|
||||||
|
nested = nested[0:-1]
|
||||||
|
groupnum += 1
|
||||||
|
nextnest = index
|
||||||
|
watchgroup = False
|
||||||
|
else:
|
||||||
|
if groupnum > 0:
|
||||||
|
watchgroup = True
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
lmatch = sumrex.match(item1)
|
||||||
|
if lmatch:
|
||||||
|
if watchgroup:
|
||||||
|
nested = nested[0:-1]
|
||||||
|
nested = nested[0:-1]
|
||||||
|
watchgroup = False
|
||||||
|
tagstyle = 'header2'
|
||||||
|
groupnum = 0
|
||||||
|
|
||||||
|
lmatch1 = matchrex.match(item1)
|
||||||
|
lmatch2 = matchrex.match(item2)
|
||||||
|
if lmatch1 or lmatch2:
|
||||||
|
tagstyle='error'
|
||||||
|
|
||||||
|
# print("Create item ID " + str(index) + " parent = " + str(nested[-1]))
|
||||||
|
self.treeView.insert(nested[-1], 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
if nextnest:
|
||||||
|
nested.append(nextnest)
|
||||||
|
|
||||||
|
for button in self.func_buttons:
|
||||||
|
button[0].pack_forget()
|
||||||
|
|
||||||
|
if lines == 0:
|
||||||
|
self.treeView.insert('', 'end', text='-', value=['(no items)', '(no items)'])
|
||||||
|
for button in self.func_buttons:
|
||||||
|
if button[1]:
|
||||||
|
button[0].pack(side='left', padx = 5)
|
||||||
|
else:
|
||||||
|
for button in self.func_buttons:
|
||||||
|
button[0].pack(side='left', padx = 5)
|
||||||
|
|
||||||
|
# Special routine to pull in the JSON file data produced by netgen-1.5.72
|
||||||
|
def json_repopulate(self, lvsdata):
|
||||||
|
|
||||||
|
# Remove all children of treeview
|
||||||
|
self.treeView.delete(*self.treeView.get_children())
|
||||||
|
|
||||||
|
# Parse the information coming from comp.out. This is preferably
|
||||||
|
# handled from inside netgen, but that requires development in netgen.
|
||||||
|
# Note: A top-level group is denoted by an empty string.
|
||||||
|
|
||||||
|
index = 0
|
||||||
|
errtotal = {}
|
||||||
|
errtotal['net'] = 0
|
||||||
|
errtotal['netmatch'] = 0
|
||||||
|
errtotal['device'] = 0
|
||||||
|
errtotal['devmatch'] = 0
|
||||||
|
errtotal['property'] = 0
|
||||||
|
errtotal['pin'] = 0
|
||||||
|
ncells = len(lvsdata)
|
||||||
|
for c in range(0, ncells):
|
||||||
|
cellrec = lvsdata[c]
|
||||||
|
if c == ncells - 1:
|
||||||
|
topcell = True
|
||||||
|
else:
|
||||||
|
topcell = False
|
||||||
|
|
||||||
|
errcell = {}
|
||||||
|
errcell['net'] = 0
|
||||||
|
errcell['netmatch'] = 0
|
||||||
|
errcell['device'] = 0
|
||||||
|
errcell['devmatch'] = 0
|
||||||
|
errcell['property'] = 0
|
||||||
|
errcell['pin'] = 0;
|
||||||
|
|
||||||
|
cname1 = 'Layout'
|
||||||
|
cname2 = 'Schematic'
|
||||||
|
|
||||||
|
# cellrec is a dictionary. Parse the cell summary, then failing nets,
|
||||||
|
# devices, and properties, and finally pins.
|
||||||
|
|
||||||
|
if 'name' in cellrec:
|
||||||
|
names = cellrec['name']
|
||||||
|
cname1 = names[0]
|
||||||
|
cname2 = names[1]
|
||||||
|
else:
|
||||||
|
# This is an error but don't halt the program because of it.
|
||||||
|
cname1 = '(unknown layout)'
|
||||||
|
cname2 = '(unknown schematic)'
|
||||||
|
|
||||||
|
item1 = cname1
|
||||||
|
item2 = cname2
|
||||||
|
tagstyle = 'header1'
|
||||||
|
index += 1
|
||||||
|
nest0 = index
|
||||||
|
self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'devices' in cellrec or 'nets' in cellrec:
|
||||||
|
item1 = cname1 + " Summary"
|
||||||
|
item2 = cname2 + " Summary"
|
||||||
|
tagstyle = 'header2'
|
||||||
|
index += 1
|
||||||
|
nest1 = index
|
||||||
|
self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'devices' in cellrec:
|
||||||
|
item1 = cname1 + " Devices"
|
||||||
|
item2 = cname2 + " Devices"
|
||||||
|
tagstyle = 'header3'
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
devices = cellrec['devices']
|
||||||
|
devlist = [val for pair in zip(devices[0], devices[1]) for val in pair]
|
||||||
|
devpair = list(devlist[p:p + 2] for p in range(0, len(devlist), 2))
|
||||||
|
for dev in devpair:
|
||||||
|
c1dev = dev[0]
|
||||||
|
c2dev = dev[1]
|
||||||
|
|
||||||
|
item1 = c1dev[0] + "(" + str(c1dev[1]) + ")"
|
||||||
|
item2 = c2dev[0] + "(" + str(c2dev[1]) + ")"
|
||||||
|
|
||||||
|
diffdevs = abs(c1dev[1] - c2dev[1])
|
||||||
|
if diffdevs == 0:
|
||||||
|
tagstyle = 'normal'
|
||||||
|
else:
|
||||||
|
tagstyle = 'error'
|
||||||
|
errcell['device'] += diffdevs
|
||||||
|
if topcell:
|
||||||
|
errtotal['device'] += diffdevs
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'nets' in cellrec:
|
||||||
|
item1 = cname1 + " Nets"
|
||||||
|
item2 = cname2 + " Nets"
|
||||||
|
tagstyle = 'header3'
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
nets = cellrec['nets']
|
||||||
|
|
||||||
|
item1 = nets[0]
|
||||||
|
item2 = nets[1]
|
||||||
|
diffnets = abs(nets[0] - nets[1])
|
||||||
|
if diffnets == 0:
|
||||||
|
tagstyle = 'normal'
|
||||||
|
else:
|
||||||
|
tagstyle = 'error'
|
||||||
|
errcell['net'] = diffnets
|
||||||
|
if topcell:
|
||||||
|
errtotal['net'] += diffnets
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'badnets' in cellrec:
|
||||||
|
badnets = cellrec['badnets']
|
||||||
|
|
||||||
|
if len(badnets) > 0:
|
||||||
|
item1 = cname1 + " Net Mismatches"
|
||||||
|
item2 = cname2 + " Net Mismatches"
|
||||||
|
tagstyle = 'header2'
|
||||||
|
index += 1
|
||||||
|
nest1 = index
|
||||||
|
self.treeView.insert(nest0, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
groupnum = 0
|
||||||
|
for group in badnets:
|
||||||
|
groupc1 = group[0]
|
||||||
|
groupc2 = group[1]
|
||||||
|
nnets = len(groupc1)
|
||||||
|
|
||||||
|
groupnum += 1
|
||||||
|
tagstyle = 'header3'
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
item1 = "Group " + str(groupnum) + ' (' + str(nnets) + ' nets)'
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item1], tags=[tagstyle])
|
||||||
|
|
||||||
|
tagstyle = 'error'
|
||||||
|
errcell['netmatch'] += nnets
|
||||||
|
if topcell:
|
||||||
|
errtotal['netmatch'] += nnets
|
||||||
|
|
||||||
|
for netnum in range(0, nnets):
|
||||||
|
if netnum > 0:
|
||||||
|
item1 = ""
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item1], tags=[tagstyle])
|
||||||
|
|
||||||
|
net1 = groupc1[netnum]
|
||||||
|
net2 = groupc2[netnum]
|
||||||
|
tagstyle = 'header4'
|
||||||
|
item1 = net1[0]
|
||||||
|
item2 = net2[0]
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
# Pad shorter device list to the length of the longer one
|
||||||
|
netdevs = list(itertools.zip_longest(net1[1], net2[1]))
|
||||||
|
for devpair in netdevs:
|
||||||
|
devc1 = devpair[0]
|
||||||
|
devc2 = devpair[1]
|
||||||
|
tagstyle = 'normal'
|
||||||
|
if devc1 and devc1[0] != "":
|
||||||
|
item1 = devc1[0] + '/' + devc1[1] + ' = ' + str(devc1[2])
|
||||||
|
else:
|
||||||
|
item1 = ""
|
||||||
|
if devc2 and devc2[0] != "":
|
||||||
|
item2 = devc2[0] + '/' + devc2[1] + ' = ' + str(devc2[2])
|
||||||
|
else:
|
||||||
|
item2 = ""
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'badelements' in cellrec:
|
||||||
|
badelements = cellrec['badelements']
|
||||||
|
|
||||||
|
if len(badelements) > 0:
|
||||||
|
item1 = cname1 + " Device Mismatches"
|
||||||
|
item2 = cname2 + " Device Mismatches"
|
||||||
|
tagstyle = 'header2'
|
||||||
|
index += 1
|
||||||
|
nest1 = index
|
||||||
|
self.treeView.insert(nest0, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
groupnum = 0
|
||||||
|
for group in badelements:
|
||||||
|
groupc1 = group[0]
|
||||||
|
groupc2 = group[1]
|
||||||
|
ndevs = len(groupc1)
|
||||||
|
|
||||||
|
groupnum += 1
|
||||||
|
tagstyle = 'header3'
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
item1 = "Group " + str(groupnum) + ' (' + str(ndevs) + ' devices)'
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item1], tags=[tagstyle])
|
||||||
|
|
||||||
|
tagstyle = 'error'
|
||||||
|
errcell['devmatch'] += ndevs
|
||||||
|
if topcell:
|
||||||
|
errtotal['devmatch'] += ndevs
|
||||||
|
|
||||||
|
for elemnum in range(0, ndevs):
|
||||||
|
if elemnum > 0:
|
||||||
|
item1 = ""
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item1], tags=[tagstyle])
|
||||||
|
|
||||||
|
elem1 = groupc1[elemnum]
|
||||||
|
elem2 = groupc2[elemnum]
|
||||||
|
tagstyle = 'header4'
|
||||||
|
item1 = elem1[0]
|
||||||
|
item2 = elem2[0]
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
# Pad shorter pin list to the length of the longer one
|
||||||
|
elempins = list(itertools.zip_longest(elem1[1], elem2[1]))
|
||||||
|
for pinpair in elempins:
|
||||||
|
pinc1 = pinpair[0]
|
||||||
|
pinc2 = pinpair[1]
|
||||||
|
tagstyle = 'normal'
|
||||||
|
if pinc1 and pinc1[0] != "":
|
||||||
|
item1 = pinc1[0] + ' = ' + str(pinc1[1])
|
||||||
|
else:
|
||||||
|
item1 = ""
|
||||||
|
if pinc2 and pinc2[0] != "":
|
||||||
|
item2 = pinc2[0] + ' = ' + str(pinc2[1])
|
||||||
|
else:
|
||||||
|
item2 = ""
|
||||||
|
index += 1
|
||||||
|
nest3 = index
|
||||||
|
self.treeView.insert(nest2, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'properties' in cellrec:
|
||||||
|
properties = cellrec['properties']
|
||||||
|
numproperr = len(properties)
|
||||||
|
if numproperr > 0:
|
||||||
|
item1 = cname1 + " Properties"
|
||||||
|
item2 = cname2 + " Properties"
|
||||||
|
tagstyle = 'header2'
|
||||||
|
index += 1
|
||||||
|
nest1 = index
|
||||||
|
self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
errcell['property'] = numproperr
|
||||||
|
errtotal['property'] += numproperr
|
||||||
|
|
||||||
|
for prop in properties:
|
||||||
|
|
||||||
|
if prop != properties[0]:
|
||||||
|
item1 = ""
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item1], tags=[tagstyle])
|
||||||
|
|
||||||
|
propc1 = prop[0]
|
||||||
|
propc2 = prop[1]
|
||||||
|
|
||||||
|
tagstyle = 'header3'
|
||||||
|
item1 = propc1[0]
|
||||||
|
item2 = propc2[0]
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
# Pad shorter property list to the length of the longer one
|
||||||
|
elemprops = list(itertools.zip_longest(propc1[1], propc2[1]))
|
||||||
|
for proppair in elemprops:
|
||||||
|
perrc1 = proppair[0]
|
||||||
|
perrc2 = proppair[1]
|
||||||
|
tagstyle = 'normal'
|
||||||
|
if perrc1 and perrc1[0] != "":
|
||||||
|
item1 = perrc1[0] + ' = ' + str(perrc1[1])
|
||||||
|
else:
|
||||||
|
item1 = ""
|
||||||
|
if perrc2 and perrc2[0] != "":
|
||||||
|
item2 = perrc2[0] + ' = ' + str(perrc2[1])
|
||||||
|
else:
|
||||||
|
item2 = ""
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
if 'pins' in cellrec:
|
||||||
|
item1 = cname1 + " Pins"
|
||||||
|
item2 = cname2 + " Pins"
|
||||||
|
tagstyle = 'header2'
|
||||||
|
index += 1
|
||||||
|
nest1 = index
|
||||||
|
self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
pins = cellrec['pins']
|
||||||
|
pinlist = [val for pair in zip(pins[0], pins[1]) for val in pair]
|
||||||
|
pinpair = list(pinlist[p:p + 2] for p in range(0, len(pinlist), 2))
|
||||||
|
for pin in pinpair:
|
||||||
|
item1 = pin[0]
|
||||||
|
item2 = pin[1]
|
||||||
|
if item1.lower() == item2.lower():
|
||||||
|
tagstyle = 'header4'
|
||||||
|
else:
|
||||||
|
tagstyle = 'error'
|
||||||
|
errcell['pin'] += 1
|
||||||
|
if topcell:
|
||||||
|
errtotal['pin'] += 1
|
||||||
|
index += 1
|
||||||
|
nest2 = index
|
||||||
|
self.treeView.insert(nest1, 'end', text=index, iid=index,
|
||||||
|
value=[item1, item2], tags=[tagstyle])
|
||||||
|
|
||||||
|
allcellerror = errcell['net'] + errcell['device'] + errcell['property'] + errcell['pin'] + errcell['netmatch'] + errcell['devmatch']
|
||||||
|
if allcellerror > 0:
|
||||||
|
item1 = 'Errors: Net = ' + str(errcell['net']) + ', Device = ' + str(errcell['device']) + ', Property = ' + str(errcell['property']) + ', Pin = ' + str(errcell['pin']) + ', Net match = ' + str(errcell['netmatch']) + ', Device match = ' + str(errcell['devmatch'])
|
||||||
|
tagstyle = 'error'
|
||||||
|
else:
|
||||||
|
item1 = 'LVS Clean'
|
||||||
|
tagstyle = 'clean'
|
||||||
|
|
||||||
|
item2 = ""
|
||||||
|
index += 1
|
||||||
|
nest0 = index
|
||||||
|
self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
item1 = "Final LVS result:"
|
||||||
|
item2 = ""
|
||||||
|
tagstyle = 'header1'
|
||||||
|
index += 1
|
||||||
|
nest0 = index
|
||||||
|
self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
allerror = errtotal['net'] + errtotal['device'] + errtotal['property'] + errtotal['pin'] + errtotal['netmatch'] + errtotal['devmatch']
|
||||||
|
if allerror > 0:
|
||||||
|
item1 = 'Errors: Net = ' + str(errtotal['net']) + ', Device = ' + str(errtotal['device']) + ', Property = ' + str(errtotal['property']) + ', Pin = ' + str(errtotal['pin']) + ', Net match = ' + str(errtotal['netmatch']) + ', Device match = ' + str(errtotal['devmatch'])
|
||||||
|
tagstyle = 'error'
|
||||||
|
else:
|
||||||
|
item1 = 'LVS Clean'
|
||||||
|
tagstyle = 'clean'
|
||||||
|
|
||||||
|
item2 = ""
|
||||||
|
index += 1
|
||||||
|
nest0 = index
|
||||||
|
self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2],
|
||||||
|
tags=[tagstyle])
|
||||||
|
|
||||||
|
for button in self.func_buttons:
|
||||||
|
button[0].pack_forget()
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
self.treeView.insert('', 'end', text='-', value=['(no items)', '(no items)'])
|
||||||
|
for button in self.func_buttons:
|
||||||
|
if button[1]:
|
||||||
|
button[0].pack(side='left', padx = 5)
|
||||||
|
else:
|
||||||
|
for button in self.func_buttons:
|
||||||
|
button[0].pack(side='left', padx = 5)
|
||||||
|
|
||||||
|
# Return values from the treeview
|
||||||
|
def getlist(self):
|
||||||
|
return self.treeView.get_children()
|
||||||
|
|
||||||
|
def func_callback(self, callback, event=None):
|
||||||
|
callback(self.treeView.item(self.treeView.selection()))
|
||||||
|
|
||||||
|
def bindselect(self, callback):
|
||||||
|
self.selectcallback = callback
|
||||||
|
|
||||||
|
def setselect(self, value):
|
||||||
|
self.treeView.selection_set(value)
|
||||||
|
|
||||||
|
def selected(self):
|
||||||
|
value = self.treeView.item(self.treeView.selection())
|
||||||
|
if value['values']:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
@ -39,24 +39,24 @@ PATH: /usr/local/bin
|
||||||
## Core tests. ##
|
## Core tests. ##
|
||||||
## ----------- ##
|
## ----------- ##
|
||||||
|
|
||||||
configure:2397: checking build system type
|
configure:2398: checking build system type
|
||||||
configure:2411: result: x86_64-unknown-linux-gnu
|
configure:2412: result: x86_64-unknown-linux-gnu
|
||||||
configure:2431: checking host system type
|
configure:2432: checking host system type
|
||||||
configure:2444: result: x86_64-unknown-linux-gnu
|
configure:2445: result: x86_64-unknown-linux-gnu
|
||||||
configure:2464: checking target system type
|
configure:2465: checking target system type
|
||||||
configure:2477: result: x86_64-unknown-linux-gnu
|
configure:2478: result: x86_64-unknown-linux-gnu
|
||||||
configure:2568: checking for gcc
|
configure:2569: checking for gcc
|
||||||
configure:2584: found /bin/gcc
|
configure:2585: found /bin/gcc
|
||||||
configure:2595: result: gcc
|
configure:2596: result: gcc
|
||||||
configure:2824: checking for C compiler version
|
configure:2825: checking for C compiler version
|
||||||
configure:2833: gcc --version >&5
|
configure:2834: gcc --version >&5
|
||||||
gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
|
gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
|
||||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||||
This is free software; see the source for copying conditions. There is NO
|
This is free software; see the source for copying conditions. There is NO
|
||||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
configure:2844: $? = 0
|
configure:2845: $? = 0
|
||||||
configure:2833: gcc -v >&5
|
configure:2834: gcc -v >&5
|
||||||
Using built-in specs.
|
Using built-in specs.
|
||||||
COLLECT_GCC=gcc
|
COLLECT_GCC=gcc
|
||||||
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
|
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
|
||||||
|
|
@ -64,58 +64,58 @@ Target: x86_64-redhat-linux
|
||||||
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
|
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
|
||||||
Thread model: posix
|
Thread model: posix
|
||||||
gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)
|
gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)
|
||||||
configure:2844: $? = 0
|
configure:2845: $? = 0
|
||||||
configure:2833: gcc -V >&5
|
configure:2834: gcc -V >&5
|
||||||
gcc: error: unrecognized command line option '-V'
|
gcc: error: unrecognized command line option '-V'
|
||||||
gcc: fatal error: no input files
|
gcc: fatal error: no input files
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:2844: $? = 4
|
configure:2845: $? = 4
|
||||||
configure:2833: gcc -qversion >&5
|
configure:2834: gcc -qversion >&5
|
||||||
gcc: error: unrecognized command line option '-qversion'
|
gcc: error: unrecognized command line option '-qversion'
|
||||||
gcc: fatal error: no input files
|
gcc: fatal error: no input files
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:2844: $? = 4
|
configure:2845: $? = 4
|
||||||
configure:2864: checking whether the C compiler works
|
configure:2865: checking whether the C compiler works
|
||||||
configure:2886: gcc -g conftest.c >&5
|
configure:2887: gcc -g conftest.c >&5
|
||||||
configure:2890: $? = 0
|
configure:2891: $? = 0
|
||||||
configure:2938: result: yes
|
configure:2939: result: yes
|
||||||
configure:2941: checking for C compiler default output file name
|
configure:2942: checking for C compiler default output file name
|
||||||
configure:2943: result: a.out
|
configure:2944: result: a.out
|
||||||
configure:2949: checking for suffix of executables
|
configure:2950: checking for suffix of executables
|
||||||
configure:2956: gcc -o conftest -g conftest.c >&5
|
configure:2957: gcc -o conftest -g conftest.c >&5
|
||||||
configure:2960: $? = 0
|
configure:2961: $? = 0
|
||||||
configure:2982: result:
|
configure:2983: result:
|
||||||
configure:3004: checking whether we are cross compiling
|
configure:3005: checking whether we are cross compiling
|
||||||
configure:3012: gcc -o conftest -g conftest.c >&5
|
configure:3013: gcc -o conftest -g conftest.c >&5
|
||||||
configure:3016: $? = 0
|
configure:3017: $? = 0
|
||||||
configure:3023: ./conftest
|
configure:3024: ./conftest
|
||||||
configure:3027: $? = 0
|
configure:3028: $? = 0
|
||||||
configure:3042: result: no
|
configure:3043: result: no
|
||||||
configure:3047: checking for suffix of object files
|
configure:3048: checking for suffix of object files
|
||||||
configure:3069: gcc -c -g conftest.c >&5
|
configure:3070: gcc -c -g conftest.c >&5
|
||||||
configure:3073: $? = 0
|
configure:3074: $? = 0
|
||||||
configure:3094: result: o
|
configure:3095: result: o
|
||||||
configure:3098: checking whether we are using the GNU C compiler
|
configure:3099: checking whether we are using the GNU C compiler
|
||||||
configure:3117: gcc -c -g conftest.c >&5
|
configure:3118: gcc -c -g conftest.c >&5
|
||||||
configure:3117: $? = 0
|
configure:3118: $? = 0
|
||||||
configure:3126: result: yes
|
configure:3127: result: yes
|
||||||
configure:3135: checking whether gcc accepts -g
|
configure:3136: checking whether gcc accepts -g
|
||||||
configure:3155: gcc -c -g conftest.c >&5
|
configure:3156: gcc -c -g conftest.c >&5
|
||||||
configure:3155: $? = 0
|
configure:3156: $? = 0
|
||||||
configure:3196: result: yes
|
configure:3197: result: yes
|
||||||
configure:3213: checking for gcc option to accept ISO C89
|
configure:3214: checking for gcc option to accept ISO C89
|
||||||
configure:3276: gcc -c -g conftest.c >&5
|
configure:3277: gcc -c -g conftest.c >&5
|
||||||
configure:3276: $? = 0
|
configure:3277: $? = 0
|
||||||
configure:3289: result: none needed
|
configure:3290: result: none needed
|
||||||
configure:3314: checking how to run the C preprocessor
|
configure:3315: checking how to run the C preprocessor
|
||||||
configure:3345: gcc -E conftest.c
|
configure:3346: gcc -E conftest.c
|
||||||
configure:3345: $? = 0
|
configure:3346: $? = 0
|
||||||
configure:3359: gcc -E conftest.c
|
configure:3360: gcc -E conftest.c
|
||||||
conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory
|
conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory
|
||||||
#include <ac_nonexistent.h>
|
#include <ac_nonexistent.h>
|
||||||
^
|
^
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:3359: $? = 1
|
configure:3360: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -125,18 +125,18 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| /* end confdefs.h. */
|
| /* end confdefs.h. */
|
||||||
| #include <ac_nonexistent.h>
|
| #include <ac_nonexistent.h>
|
||||||
configure:3384: result: gcc -E
|
configure:3385: result: gcc -E
|
||||||
configure:3404: gcc -E conftest.c
|
configure:3405: gcc -E conftest.c
|
||||||
configure:3404: $? = 0
|
configure:3405: $? = 0
|
||||||
configure:3418: gcc -E conftest.c
|
configure:3419: gcc -E conftest.c
|
||||||
conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory
|
conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory
|
||||||
#include <ac_nonexistent.h>
|
#include <ac_nonexistent.h>
|
||||||
^
|
^
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:3418: $? = 1
|
configure:3419: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -146,104 +146,104 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| /* end confdefs.h. */
|
| /* end confdefs.h. */
|
||||||
| #include <ac_nonexistent.h>
|
| #include <ac_nonexistent.h>
|
||||||
configure:3447: checking for library containing strerror
|
configure:3448: checking for library containing strerror
|
||||||
configure:3478: gcc -o conftest -g conftest.c >&5
|
configure:3479: gcc -o conftest -g conftest.c >&5
|
||||||
configure:3478: $? = 0
|
configure:3479: $? = 0
|
||||||
configure:3495: result: none required
|
configure:3496: result: none required
|
||||||
configure:3517: checking for a BSD-compatible install
|
configure:3518: checking for a BSD-compatible install
|
||||||
configure:3585: result: /bin/install -c
|
configure:3586: result: /bin/install -c
|
||||||
configure:3639: checking for ranlib
|
configure:3640: checking for ranlib
|
||||||
configure:3655: found /bin/ranlib
|
configure:3656: found /bin/ranlib
|
||||||
configure:3666: result: ranlib
|
configure:3667: result: ranlib
|
||||||
configure:3693: checking for gm4
|
configure:3694: checking for gm4
|
||||||
configure:3726: result: no
|
configure:3727: result: no
|
||||||
configure:3693: checking for gnum4
|
configure:3694: checking for gnum4
|
||||||
configure:3726: result: no
|
configure:3727: result: no
|
||||||
configure:3693: checking for m4
|
configure:3694: checking for m4
|
||||||
configure:3711: found /bin/m4
|
configure:3712: found /bin/m4
|
||||||
configure:3723: result: /bin/m4
|
configure:3724: result: /bin/m4
|
||||||
configure:3764: checking for ld used by GCC
|
configure:3765: checking for ld used by GCC
|
||||||
configure:3827: result: /bin/ld
|
configure:3828: result: /bin/ld
|
||||||
configure:3834: checking if the linker (/bin/ld) is GNU ld
|
configure:3835: checking if the linker (/bin/ld) is GNU ld
|
||||||
GNU ld version 2.24
|
GNU ld version 2.24
|
||||||
configure:3846: result: yes
|
configure:3847: result: yes
|
||||||
configure:3853: checking for grep that handles long lines and -e
|
configure:3854: checking for grep that handles long lines and -e
|
||||||
configure:3911: result: /bin/grep
|
configure:3912: result: /bin/grep
|
||||||
configure:3916: checking for egrep
|
configure:3917: checking for egrep
|
||||||
configure:3978: result: /bin/grep -E
|
configure:3979: result: /bin/grep -E
|
||||||
configure:3983: checking for ANSI C header files
|
configure:3984: checking for ANSI C header files
|
||||||
configure:4003: gcc -c -g conftest.c >&5
|
configure:4004: gcc -c -g conftest.c >&5
|
||||||
configure:4003: $? = 0
|
configure:4004: $? = 0
|
||||||
configure:4076: gcc -o conftest -g conftest.c >&5
|
configure:4077: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4076: $? = 0
|
configure:4077: $? = 0
|
||||||
configure:4076: ./conftest
|
configure:4077: ./conftest
|
||||||
configure:4076: $? = 0
|
configure:4077: $? = 0
|
||||||
configure:4087: result: yes
|
configure:4088: result: yes
|
||||||
configure:4100: checking for sys/types.h
|
configure:4101: checking for sys/types.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for sys/stat.h
|
configure:4101: checking for sys/stat.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for stdlib.h
|
configure:4101: checking for stdlib.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for string.h
|
configure:4101: checking for string.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for memory.h
|
configure:4101: checking for memory.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for strings.h
|
configure:4101: checking for strings.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for inttypes.h
|
configure:4101: checking for inttypes.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for stdint.h
|
configure:4101: checking for stdint.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4100: checking for unistd.h
|
configure:4101: checking for unistd.h
|
||||||
configure:4100: gcc -c -g conftest.c >&5
|
configure:4101: gcc -c -g conftest.c >&5
|
||||||
configure:4100: $? = 0
|
configure:4101: $? = 0
|
||||||
configure:4100: result: yes
|
configure:4101: result: yes
|
||||||
configure:4116: checking size of void *
|
configure:4117: checking size of void *
|
||||||
configure:4121: gcc -o conftest -g conftest.c >&5
|
configure:4122: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4121: $? = 0
|
configure:4122: $? = 0
|
||||||
configure:4121: ./conftest
|
configure:4122: ./conftest
|
||||||
configure:4121: $? = 0
|
configure:4122: $? = 0
|
||||||
configure:4135: result: 8
|
configure:4136: result: 8
|
||||||
configure:4149: checking size of unsigned int
|
configure:4150: checking size of unsigned int
|
||||||
configure:4154: gcc -o conftest -g conftest.c >&5
|
configure:4155: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4154: $? = 0
|
configure:4155: $? = 0
|
||||||
configure:4154: ./conftest
|
configure:4155: ./conftest
|
||||||
configure:4154: $? = 0
|
configure:4155: $? = 0
|
||||||
configure:4168: result: 4
|
configure:4169: result: 4
|
||||||
configure:4182: checking size of unsigned long
|
configure:4183: checking size of unsigned long
|
||||||
configure:4187: gcc -o conftest -g conftest.c >&5
|
configure:4188: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4187: $? = 0
|
configure:4188: $? = 0
|
||||||
configure:4187: ./conftest
|
configure:4188: ./conftest
|
||||||
configure:4187: $? = 0
|
configure:4188: $? = 0
|
||||||
configure:4201: result: 8
|
configure:4202: result: 8
|
||||||
configure:4215: checking size of unsigned long long
|
configure:4216: checking size of unsigned long long
|
||||||
configure:4220: gcc -o conftest -g conftest.c >&5
|
configure:4221: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4220: $? = 0
|
configure:4221: $? = 0
|
||||||
configure:4220: ./conftest
|
configure:4221: ./conftest
|
||||||
configure:4220: $? = 0
|
configure:4221: $? = 0
|
||||||
configure:4234: result: 8
|
configure:4235: result: 8
|
||||||
configure:4245: checking whether byte ordering is bigendian
|
configure:4246: checking whether byte ordering is bigendian
|
||||||
configure:4260: gcc -c -g conftest.c >&5
|
configure:4261: gcc -c -g conftest.c >&5
|
||||||
conftest.c:26:9: error: unknown type name 'not'
|
conftest.c:26:9: error: unknown type name 'not'
|
||||||
not a universal capable compiler
|
not a universal capable compiler
|
||||||
^
|
^
|
||||||
|
|
@ -251,7 +251,7 @@ conftest.c:26:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before
|
||||||
not a universal capable compiler
|
not a universal capable compiler
|
||||||
^
|
^
|
||||||
conftest.c:26:15: error: unknown type name 'universal'
|
conftest.c:26:15: error: unknown type name 'universal'
|
||||||
configure:4260: $? = 1
|
configure:4261: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -261,7 +261,7 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| #define STDC_HEADERS 1
|
| #define STDC_HEADERS 1
|
||||||
| #define HAVE_SYS_TYPES_H 1
|
| #define HAVE_SYS_TYPES_H 1
|
||||||
| #define HAVE_SYS_STAT_H 1
|
| #define HAVE_SYS_STAT_H 1
|
||||||
|
|
@ -282,9 +282,9 @@ configure: failed program was:
|
||||||
| #endif
|
| #endif
|
||||||
| typedef int dummy;
|
| typedef int dummy;
|
||||||
|
|
|
|
||||||
configure:4305: gcc -c -g conftest.c >&5
|
configure:4306: gcc -c -g conftest.c >&5
|
||||||
configure:4305: $? = 0
|
configure:4306: $? = 0
|
||||||
configure:4323: gcc -c -g conftest.c >&5
|
configure:4324: gcc -c -g conftest.c >&5
|
||||||
conftest.c: In function 'main':
|
conftest.c: In function 'main':
|
||||||
conftest.c:32:4: error: unknown type name 'not'
|
conftest.c:32:4: error: unknown type name 'not'
|
||||||
not big endian
|
not big endian
|
||||||
|
|
@ -292,7 +292,7 @@ conftest.c:32:4: error: unknown type name 'not'
|
||||||
conftest.c:32:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'endian'
|
conftest.c:32:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'endian'
|
||||||
not big endian
|
not big endian
|
||||||
^
|
^
|
||||||
configure:4323: $? = 1
|
configure:4324: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -302,7 +302,7 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| #define STDC_HEADERS 1
|
| #define STDC_HEADERS 1
|
||||||
| #define HAVE_SYS_TYPES_H 1
|
| #define HAVE_SYS_TYPES_H 1
|
||||||
| #define HAVE_SYS_STAT_H 1
|
| #define HAVE_SYS_STAT_H 1
|
||||||
|
|
@ -331,48 +331,48 @@ configure: failed program was:
|
||||||
| ;
|
| ;
|
||||||
| return 0;
|
| return 0;
|
||||||
| }
|
| }
|
||||||
configure:4451: result: no
|
configure:4452: result: no
|
||||||
configure:4470: checking for ANSI C header files
|
configure:4471: checking for ANSI C header files
|
||||||
configure:4574: result: yes
|
configure:4575: result: yes
|
||||||
configure:4586: checking for setenv
|
configure:4587: checking for setenv
|
||||||
configure:4586: gcc -o conftest -g conftest.c >&5
|
configure:4587: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4586: $? = 0
|
configure:4587: $? = 0
|
||||||
configure:4586: result: yes
|
configure:4587: result: yes
|
||||||
configure:4586: checking for putenv
|
configure:4587: checking for putenv
|
||||||
configure:4586: gcc -o conftest -g conftest.c >&5
|
configure:4587: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4586: $? = 0
|
configure:4587: $? = 0
|
||||||
configure:4586: result: yes
|
configure:4587: result: yes
|
||||||
configure:4596: checking for vfork
|
configure:4597: checking for vfork
|
||||||
configure:4596: gcc -o conftest -g conftest.c >&5
|
configure:4597: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4596: $? = 0
|
configure:4597: $? = 0
|
||||||
configure:4596: result: yes
|
configure:4597: result: yes
|
||||||
configure:4604: checking dirent.h usability
|
configure:4605: checking dirent.h usability
|
||||||
configure:4604: gcc -c -g conftest.c >&5
|
configure:4605: gcc -c -g conftest.c >&5
|
||||||
configure:4604: $? = 0
|
configure:4605: $? = 0
|
||||||
configure:4604: result: yes
|
configure:4605: result: yes
|
||||||
configure:4604: checking dirent.h presence
|
configure:4605: checking dirent.h presence
|
||||||
configure:4604: gcc -E -x c conftest.c
|
configure:4605: gcc -E -x c conftest.c
|
||||||
configure:4604: $? = 0
|
configure:4605: $? = 0
|
||||||
configure:4604: result: yes
|
configure:4605: result: yes
|
||||||
configure:4604: checking for dirent.h
|
configure:4605: checking for dirent.h
|
||||||
configure:4604: result: yes
|
configure:4605: result: yes
|
||||||
configure:4617: checking limits.h usability
|
configure:4618: checking limits.h usability
|
||||||
configure:4617: gcc -c -g conftest.c >&5
|
configure:4618: gcc -c -g conftest.c >&5
|
||||||
configure:4617: $? = 0
|
configure:4618: $? = 0
|
||||||
configure:4617: result: yes
|
configure:4618: result: yes
|
||||||
configure:4617: checking limits.h presence
|
configure:4618: checking limits.h presence
|
||||||
configure:4617: gcc -E -x c conftest.c
|
configure:4618: gcc -E -x c conftest.c
|
||||||
configure:4617: $? = 0
|
configure:4618: $? = 0
|
||||||
configure:4617: result: yes
|
configure:4618: result: yes
|
||||||
configure:4617: checking for limits.h
|
configure:4618: checking for limits.h
|
||||||
configure:4617: result: yes
|
configure:4618: result: yes
|
||||||
configure:4630: checking param.h usability
|
configure:4631: checking param.h usability
|
||||||
configure:4630: gcc -c -g conftest.c >&5
|
configure:4631: gcc -c -g conftest.c >&5
|
||||||
conftest.c:63:19: fatal error: param.h: No such file or directory
|
conftest.c:63:19: fatal error: param.h: No such file or directory
|
||||||
#include <param.h>
|
#include <param.h>
|
||||||
^
|
^
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:4630: $? = 1
|
configure:4631: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -382,7 +382,7 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| #define STDC_HEADERS 1
|
| #define STDC_HEADERS 1
|
||||||
| #define HAVE_SYS_TYPES_H 1
|
| #define HAVE_SYS_TYPES_H 1
|
||||||
| #define HAVE_SYS_STAT_H 1
|
| #define HAVE_SYS_STAT_H 1
|
||||||
|
|
@ -437,14 +437,14 @@ configure: failed program was:
|
||||||
| # include <unistd.h>
|
| # include <unistd.h>
|
||||||
| #endif
|
| #endif
|
||||||
| #include <param.h>
|
| #include <param.h>
|
||||||
configure:4630: result: no
|
configure:4631: result: no
|
||||||
configure:4630: checking param.h presence
|
configure:4631: checking param.h presence
|
||||||
configure:4630: gcc -E -x c conftest.c
|
configure:4631: gcc -E -x c conftest.c
|
||||||
conftest.c:30:19: fatal error: param.h: No such file or directory
|
conftest.c:30:19: fatal error: param.h: No such file or directory
|
||||||
#include <param.h>
|
#include <param.h>
|
||||||
^
|
^
|
||||||
compilation terminated.
|
compilation terminated.
|
||||||
configure:4630: $? = 1
|
configure:4631: $? = 1
|
||||||
configure: failed program was:
|
configure: failed program was:
|
||||||
| /* confdefs.h */
|
| /* confdefs.h */
|
||||||
| #define PACKAGE_NAME "netgen"
|
| #define PACKAGE_NAME "netgen"
|
||||||
|
|
@ -454,7 +454,7 @@ configure: failed program was:
|
||||||
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
| #define PACKAGE_URL ""
|
| #define PACKAGE_URL ""
|
||||||
| #define NETGEN_VERSION "1.5"
|
| #define NETGEN_VERSION "1.5"
|
||||||
| #define NETGEN_REVISION "90"
|
| #define NETGEN_REVISION "98"
|
||||||
| #define STDC_HEADERS 1
|
| #define STDC_HEADERS 1
|
||||||
| #define HAVE_SYS_TYPES_H 1
|
| #define HAVE_SYS_TYPES_H 1
|
||||||
| #define HAVE_SYS_STAT_H 1
|
| #define HAVE_SYS_STAT_H 1
|
||||||
|
|
@ -476,52 +476,55 @@ configure: failed program was:
|
||||||
| #define HAVE_LIMITS_H 1
|
| #define HAVE_LIMITS_H 1
|
||||||
| /* end confdefs.h. */
|
| /* end confdefs.h. */
|
||||||
| #include <param.h>
|
| #include <param.h>
|
||||||
configure:4630: result: no
|
configure:4631: result: no
|
||||||
configure:4630: checking for param.h
|
configure:4631: checking for param.h
|
||||||
configure:4630: result: no
|
configure:4631: result: no
|
||||||
configure:4641: checking for va_copy
|
configure:4644: checking for python3
|
||||||
configure:4659: gcc -o conftest -g conftest.c >&5
|
configure:4660: found /bin/python3
|
||||||
configure:4659: $? = 0
|
configure:4672: result: yes
|
||||||
configure:4668: result: yes
|
configure:4681: checking for va_copy
|
||||||
configure:4676: checking for __va_copy
|
configure:4699: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4694: gcc -o conftest -g conftest.c >&5
|
configure:4699: $? = 0
|
||||||
configure:4694: $? = 0
|
configure:4708: result: yes
|
||||||
configure:4703: result: yes
|
configure:4716: checking for __va_copy
|
||||||
configure:4834: checking for tclConfig.sh
|
configure:4734: gcc -o conftest -g conftest.c >&5
|
||||||
configure:4906: result: /usr/lib64/tclConfig.sh
|
configure:4734: $? = 0
|
||||||
configure:4922: checking for tkConfig.sh
|
configure:4743: result: yes
|
||||||
configure:4995: result: /usr/lib64/tkConfig.sh
|
configure:4874: checking for tclConfig.sh
|
||||||
configure:5128: checking for wish executable
|
configure:4946: result: /usr/lib64/tclConfig.sh
|
||||||
configure:5155: result: /usr/bin/wish
|
configure:4962: checking for tkConfig.sh
|
||||||
configure:5161: checking for tclsh executable
|
configure:5035: result: /usr/lib64/tkConfig.sh
|
||||||
configure:5187: result: /usr/bin/tclsh
|
configure:5168: checking for wish executable
|
||||||
configure:5310: checking for X
|
configure:5195: result: /usr/bin/wish
|
||||||
configure:5449: gcc -o conftest -g conftest.c -lX11 >&5
|
configure:5201: checking for tclsh executable
|
||||||
configure:5449: $? = 0
|
configure:5227: result: /usr/bin/tclsh
|
||||||
configure:5499: result: libraries , headers
|
configure:5350: checking for X
|
||||||
configure:5598: gcc -o conftest -g conftest.c -lX11 >&5
|
configure:5489: gcc -o conftest -g conftest.c -lX11 >&5
|
||||||
configure:5598: $? = 0
|
configure:5489: $? = 0
|
||||||
configure:5696: checking for gethostbyname
|
configure:5539: result: libraries , headers
|
||||||
configure:5696: gcc -o conftest -g conftest.c >&5
|
configure:5638: gcc -o conftest -g conftest.c -lX11 >&5
|
||||||
configure:5696: $? = 0
|
configure:5638: $? = 0
|
||||||
configure:5696: result: yes
|
configure:5736: checking for gethostbyname
|
||||||
configure:5793: checking for connect
|
configure:5736: gcc -o conftest -g conftest.c >&5
|
||||||
configure:5793: gcc -o conftest -g conftest.c >&5
|
configure:5736: $? = 0
|
||||||
configure:5793: $? = 0
|
configure:5736: result: yes
|
||||||
configure:5793: result: yes
|
configure:5833: checking for connect
|
||||||
configure:5842: checking for remove
|
configure:5833: gcc -o conftest -g conftest.c >&5
|
||||||
configure:5842: gcc -o conftest -g conftest.c >&5
|
configure:5833: $? = 0
|
||||||
configure:5842: $? = 0
|
configure:5833: result: yes
|
||||||
configure:5842: result: yes
|
configure:5882: checking for remove
|
||||||
configure:5891: checking for shmat
|
configure:5882: gcc -o conftest -g conftest.c >&5
|
||||||
configure:5891: gcc -o conftest -g conftest.c >&5
|
configure:5882: $? = 0
|
||||||
configure:5891: $? = 0
|
configure:5882: result: yes
|
||||||
configure:5891: result: yes
|
configure:5931: checking for shmat
|
||||||
configure:5949: checking for IceConnectionNumber in -lICE
|
configure:5931: gcc -o conftest -g conftest.c >&5
|
||||||
configure:5974: gcc -o conftest -g conftest.c -lICE >&5
|
configure:5931: $? = 0
|
||||||
configure:5974: $? = 0
|
configure:5931: result: yes
|
||||||
configure:5983: result: yes
|
configure:5989: checking for IceConnectionNumber in -lICE
|
||||||
configure:6704: creating ./config.status
|
configure:6014: gcc -o conftest -g conftest.c -lICE >&5
|
||||||
|
configure:6014: $? = 0
|
||||||
|
configure:6023: result: yes
|
||||||
|
configure:6745: creating ./config.status
|
||||||
|
|
||||||
## ---------------------- ##
|
## ---------------------- ##
|
||||||
## Running config.status. ##
|
## Running config.status. ##
|
||||||
|
|
@ -538,8 +541,8 @@ generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
on stravinsky
|
on stravinsky
|
||||||
|
|
||||||
config.status:783: creating defs.mak
|
config.status:784: creating defs.mak
|
||||||
config.status:886: WARNING: 'defs.mak.in' seems to ignore the --datarootdir setting
|
config.status:887: WARNING: 'defs.mak.in' seems to ignore the --datarootdir setting
|
||||||
|
|
||||||
## ---------------- ##
|
## ---------------- ##
|
||||||
## Cache variables. ##
|
## Cache variables. ##
|
||||||
|
|
@ -600,6 +603,7 @@ ac_cv_path_LD=/bin/ld
|
||||||
ac_cv_path_M4=/bin/m4
|
ac_cv_path_M4=/bin/m4
|
||||||
ac_cv_path_install='/bin/install -c'
|
ac_cv_path_install='/bin/install -c'
|
||||||
ac_cv_prog_CPP='gcc -E'
|
ac_cv_prog_CPP='gcc -E'
|
||||||
|
ac_cv_prog_HAVE_PYTHON3=yes
|
||||||
ac_cv_prog_ac_ct_CC=gcc
|
ac_cv_prog_ac_ct_CC=gcc
|
||||||
ac_cv_prog_ac_ct_RANLIB=ranlib
|
ac_cv_prog_ac_ct_RANLIB=ranlib
|
||||||
ac_cv_prog_cc_c89=
|
ac_cv_prog_cc_c89=
|
||||||
|
|
@ -621,7 +625,7 @@ CC='gcc'
|
||||||
CFLAGS='-g -m64 -fPIC'
|
CFLAGS='-g -m64 -fPIC'
|
||||||
CPP='gcc -E -x c'
|
CPP='gcc -E -x c'
|
||||||
CPPFLAGS=''
|
CPPFLAGS=''
|
||||||
DEFS='-DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"90\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1'
|
DEFS='-DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"98\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1'
|
||||||
DEPEND_FLAG='-MM'
|
DEPEND_FLAG='-MM'
|
||||||
ECHO_C=''
|
ECHO_C=''
|
||||||
ECHO_N='printf'
|
ECHO_N='printf'
|
||||||
|
|
@ -630,6 +634,7 @@ EGREP='/bin/grep -E'
|
||||||
EXEEXT=''
|
EXEEXT=''
|
||||||
EXTRA_LIB_SPECS='-ldl'
|
EXTRA_LIB_SPECS='-ldl'
|
||||||
GREP='/bin/grep'
|
GREP='/bin/grep'
|
||||||
|
HAVE_PYTHON3='yes'
|
||||||
INC_SPECS=''
|
INC_SPECS=''
|
||||||
INSTALL_DATA='${INSTALL} -m 644'
|
INSTALL_DATA='${INSTALL} -m 644'
|
||||||
INSTALL_PROGRAM='${INSTALL}'
|
INSTALL_PROGRAM='${INSTALL}'
|
||||||
|
|
@ -736,7 +741,7 @@ unused=''
|
||||||
#define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
#define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com"
|
||||||
#define PACKAGE_URL ""
|
#define PACKAGE_URL ""
|
||||||
#define NETGEN_VERSION "1.5"
|
#define NETGEN_VERSION "1.5"
|
||||||
#define NETGEN_REVISION "90"
|
#define NETGEN_REVISION "98"
|
||||||
#define STDC_HEADERS 1
|
#define STDC_HEADERS 1
|
||||||
#define HAVE_SYS_TYPES_H 1
|
#define HAVE_SYS_TYPES_H 1
|
||||||
#define HAVE_SYS_STAT_H 1
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
|
||||||
|
|
@ -624,6 +624,7 @@ S["X_LIBS"]=""
|
||||||
S["X_PRE_LIBS"]=" -lSM -lICE"
|
S["X_PRE_LIBS"]=" -lSM -lICE"
|
||||||
S["X_CFLAGS"]=""
|
S["X_CFLAGS"]=""
|
||||||
S["XMKMF"]=""
|
S["XMKMF"]=""
|
||||||
|
S["HAVE_PYTHON3"]="yes"
|
||||||
S["EGREP"]="/bin/grep -E"
|
S["EGREP"]="/bin/grep -E"
|
||||||
S["GREP"]="/bin/grep"
|
S["GREP"]="/bin/grep"
|
||||||
S["M4"]="/bin/m4"
|
S["M4"]="/bin/m4"
|
||||||
|
|
@ -659,7 +660,7 @@ S["ECHO_T"]=""
|
||||||
S["ECHO_N"]="-n"
|
S["ECHO_N"]="-n"
|
||||||
S["ECHO_C"]=""
|
S["ECHO_C"]=""
|
||||||
S["DEFS"]="-DPACKAGE_NAME=\\\"netgen\\\" -DPACKAGE_TARNAME=\\\"netgen\\\" -DPACKAGE_VERSION=\\\"1.3\\\" -DPACKAGE_STRING=\\\"netgen\\ 1.3\\\" -DPACKAGE_BUGREPORT=\\\"eda-dev@open"\
|
S["DEFS"]="-DPACKAGE_NAME=\\\"netgen\\\" -DPACKAGE_TARNAME=\\\"netgen\\\" -DPACKAGE_VERSION=\\\"1.3\\\" -DPACKAGE_STRING=\\\"netgen\\ 1.3\\\" -DPACKAGE_BUGREPORT=\\\"eda-dev@open"\
|
||||||
"circuitdesign.com\\\" -DPACKAGE_URL=\\\"\\\" -DNETGEN_VERSION=\\\"1.5\\\" -DNETGEN_REVISION=\\\"90\\\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -"\
|
"circuitdesign.com\\\" -DPACKAGE_URL=\\\"\\\" -DNETGEN_VERSION=\\\"1.5\\\" -DNETGEN_REVISION=\\\"98\\\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -"\
|
||||||
"DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -D"\
|
"DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -D"\
|
||||||
"SIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHA"\
|
"SIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHA"\
|
||||||
"VE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1"
|
"VE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1"
|
||||||
|
|
|
||||||
|
|
@ -664,6 +664,7 @@ X_LIBS
|
||||||
X_PRE_LIBS
|
X_PRE_LIBS
|
||||||
X_CFLAGS
|
X_CFLAGS
|
||||||
XMKMF
|
XMKMF
|
||||||
|
HAVE_PYTHON3
|
||||||
EGREP
|
EGREP
|
||||||
GREP
|
GREP
|
||||||
M4
|
M4
|
||||||
|
|
@ -4638,6 +4639,45 @@ fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
# Extract the first word of "python3", so it can be a program name with args.
|
||||||
|
set dummy python3; ac_word=$2
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||||
|
$as_echo_n "checking for $ac_word... " >&6; }
|
||||||
|
if ${ac_cv_prog_HAVE_PYTHON3+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
if test -n "$HAVE_PYTHON3"; then
|
||||||
|
ac_cv_prog_HAVE_PYTHON3="$HAVE_PYTHON3" # Let the user override the test.
|
||||||
|
else
|
||||||
|
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||||
|
for as_dir in $PATH
|
||||||
|
do
|
||||||
|
IFS=$as_save_IFS
|
||||||
|
test -z "$as_dir" && as_dir=.
|
||||||
|
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||||
|
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||||
|
ac_cv_prog_HAVE_PYTHON3="yes"
|
||||||
|
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
IFS=$as_save_IFS
|
||||||
|
|
||||||
|
test -z "$ac_cv_prog_HAVE_PYTHON3" && ac_cv_prog_HAVE_PYTHON3="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
HAVE_PYTHON3=$ac_cv_prog_HAVE_PYTHON3
|
||||||
|
if test -n "$HAVE_PYTHON3"; then
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_PYTHON3" >&5
|
||||||
|
$as_echo "$HAVE_PYTHON3" >&6; }
|
||||||
|
else
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||||
|
$as_echo "no" >&6; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5
|
||||||
$as_echo_n "checking for va_copy... " >&6; }
|
$as_echo_n "checking for va_copy... " >&6; }
|
||||||
if ${ac_cv_c_va_copy+:} false; then :
|
if ${ac_cv_c_va_copy+:} false; then :
|
||||||
|
|
@ -6546,6 +6586,7 @@ fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files defs.mak"
|
ac_config_files="$ac_config_files defs.mak"
|
||||||
|
|
@ -7737,6 +7778,20 @@ else
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
${ECHO_N} "Python3: "
|
||||||
|
if test "x${HAVE_PYTHON3}" == "x"; then
|
||||||
|
echo "no"
|
||||||
|
echo
|
||||||
|
echo " Without Python3, you cannot run the GUI interface to netgen."
|
||||||
|
echo " This is purely optional, as it contains no features not"
|
||||||
|
echo " available in the command-line (Tcl/Tk) version. If you want"
|
||||||
|
echo " python3 support, make sure that you have installed python3"
|
||||||
|
echo " on your system."
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "yes"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "-----------------------------------------------------------"
|
echo "-----------------------------------------------------------"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,9 @@ AC_CHECK_HEADERS(limits.h)
|
||||||
dnl Check for <param.h>
|
dnl Check for <param.h>
|
||||||
AC_CHECK_HEADERS(param.h)
|
AC_CHECK_HEADERS(param.h)
|
||||||
|
|
||||||
|
dnl Check for Python3
|
||||||
|
AC_CHECK_PROG(HAVE_PYTHON3, python3, yes, no)
|
||||||
|
|
||||||
dnl Check for va_copy
|
dnl Check for va_copy
|
||||||
AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy,
|
AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy,
|
||||||
AC_TRY_LINK(
|
AC_TRY_LINK(
|
||||||
|
|
@ -1274,6 +1277,7 @@ AC_SUBST(gr_cflags)
|
||||||
AC_SUBST(gr_dflags)
|
AC_SUBST(gr_dflags)
|
||||||
AC_SUBST(gr_libs)
|
AC_SUBST(gr_libs)
|
||||||
AC_SUBST(gr_srcs)
|
AC_SUBST(gr_srcs)
|
||||||
|
AC_SUBST(HAVE_PYTHON3)
|
||||||
|
|
||||||
AC_SUBST(X_LIBS)
|
AC_SUBST(X_LIBS)
|
||||||
AC_SUBST(X_CFLAGS)
|
AC_SUBST(X_CFLAGS)
|
||||||
|
|
@ -1314,6 +1318,20 @@ else
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
${ECHO_N} "Python3: "
|
||||||
|
if test "x${HAVE_PYTHON3}" == "x"; then
|
||||||
|
echo "no"
|
||||||
|
echo
|
||||||
|
echo " Without Python3, you cannot run the GUI interface to netgen."
|
||||||
|
echo " This is purely optional, as it contains no features not"
|
||||||
|
echo " available in the command-line (Tcl/Tk) version. If you want"
|
||||||
|
echo " python3 support, make sure that you have installed python3"
|
||||||
|
echo " on your system."
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "yes"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "-----------------------------------------------------------"
|
echo "-----------------------------------------------------------"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ MANDIR = ${mandir}
|
||||||
LIBDIR = ${libdir}
|
LIBDIR = ${libdir}
|
||||||
DOCDIR = ${libdir}/netgen/doc
|
DOCDIR = ${libdir}/netgen/doc
|
||||||
TCLDIR = ${libdir}/netgen/tcl
|
TCLDIR = ${libdir}/netgen/tcl
|
||||||
|
PYDIR = ${libdir}/netgen/python
|
||||||
|
|
||||||
MAIN_EXTRA_LIBS = ${NETGENDIR}/tcltk/libtcltk.o
|
MAIN_EXTRA_LIBS = ${NETGENDIR}/tcltk/libtcltk.o
|
||||||
LD_EXTRA_LIBS =
|
LD_EXTRA_LIBS =
|
||||||
|
|
@ -66,8 +67,8 @@ CPP = gcc -E -x c
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
|
|
||||||
CPPFLAGS = -I. -I${NETGENDIR}
|
CPPFLAGS = -I. -I${NETGENDIR}
|
||||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"90\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"98\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||||
DFLAGS_NOSTUB = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"90\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
DFLAGS_NOSTUB = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"98\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||||
CFLAGS = -g -m64 -fPIC -fPIC
|
CFLAGS = -g -m64 -fPIC -fPIC
|
||||||
|
|
||||||
DEPEND_FILE = Depend
|
DEPEND_FILE = Depend
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ MANDIR = ${mandir}
|
||||||
LIBDIR = ${libdir}
|
LIBDIR = ${libdir}
|
||||||
DOCDIR = ${libdir}/netgen/doc
|
DOCDIR = ${libdir}/netgen/doc
|
||||||
TCLDIR = ${libdir}/netgen/tcl
|
TCLDIR = ${libdir}/netgen/tcl
|
||||||
|
PYDIR = ${libdir}/netgen/python
|
||||||
|
|
||||||
MAIN_EXTRA_LIBS = @extra_libs@
|
MAIN_EXTRA_LIBS = @extra_libs@
|
||||||
LD_EXTRA_LIBS = @ld_extra_libs@
|
LD_EXTRA_LIBS = @ld_extra_libs@
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ netgen.tcl: netgen.tcl.in
|
||||||
|
|
||||||
netgen.sh: netgen.sh.in
|
netgen.sh: netgen.sh.in
|
||||||
sed -e 's%TCL_DIR%${TCLDIR}%g' \
|
sed -e 's%TCL_DIR%${TCLDIR}%g' \
|
||||||
|
-e 's%PY_DIR%${PYDIR}%g' \
|
||||||
-e 's%TCLLIB_DIR%${TCL_LIB_DIR}%g' \
|
-e 's%TCLLIB_DIR%${TCL_LIB_DIR}%g' \
|
||||||
-e 's%WISH_EXE%${WISH_EXE}%g' \
|
-e 's%WISH_EXE%${WISH_EXE}%g' \
|
||||||
netgen.sh.in > netgen.sh
|
netgen.sh.in > netgen.sh
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
TKCON=true
|
TKCON=true
|
||||||
BATCH=
|
BATCH=
|
||||||
|
GUI=
|
||||||
NETGEN_WISH=WISH_EXE
|
NETGEN_WISH=WISH_EXE
|
||||||
export NETGEN_WISH
|
export NETGEN_WISH
|
||||||
|
|
||||||
|
|
@ -29,6 +30,7 @@ for i in "$@" ; do
|
||||||
case $i in
|
case $i in
|
||||||
-noc*) TKCON=;;
|
-noc*) TKCON=;;
|
||||||
-bat*) BATCH=true; TKCON=;;
|
-bat*) BATCH=true; TKCON=;;
|
||||||
|
-gui) GUI=true; TKCON=;;
|
||||||
*) arglist="$arglist${arglist:+ }\"${i//\"/\\\"}\"";;
|
*) arglist="$arglist${arglist:+ }\"${i//\"/\\\"}\"";;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
@ -40,7 +42,10 @@ if [ $TKCON ]; then
|
||||||
-slave "package require Tk; set argc $#; set argv [list $arglist]; \
|
-slave "package require Tk; set argc $#; set argv [list $arglist]; \
|
||||||
source TCL_DIR/netgen.tcl"
|
source TCL_DIR/netgen.tcl"
|
||||||
|
|
||||||
else
|
# Run the Python LVS manager GUI
|
||||||
|
|
||||||
|
elif [ $GUI ]; then
|
||||||
|
exec PY_DIR/lvs_manager.py $@
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run the stand-in for wish (netgenexec), which acts exactly like "wish"
|
# Run the stand-in for wish (netgenexec), which acts exactly like "wish"
|
||||||
|
|
@ -49,6 +54,7 @@ else
|
||||||
# capable of sourcing the startup script.
|
# capable of sourcing the startup script.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
else
|
||||||
exec TCL_DIR/netgenexec -- "$@"
|
exec TCL_DIR/netgenexec -- "$@"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue