├── VERSION ├── tech ├── osu035_redm4 │ ├── osu035.prm │ ├── osu035_redm4.par │ ├── osu035_stdcells.v │ ├── osu035_redm4.magicrc.in │ ├── osu035_redm4_setup.tcl │ ├── osu035_stdcells.gds2 │ ├── osu035_stdcells.lib │ ├── osu035_stdcells.sp │ ├── Makefile.in │ └── osu035_redm4.sh ├── gscl45nm │ ├── gscl45nm.gds │ ├── gscl45nm_setup.tcl │ ├── gscl45nm.magicrc.in │ ├── gscl45nm.prm │ ├── Makefile.in │ ├── gscl45nm.par │ └── gscl45nm.sh ├── osu018 │ ├── osu018_stdcells.gds2 │ ├── osu018_setup.tcl │ ├── osu018.magicrc.in │ ├── osu018.prm │ ├── Makefile.in │ ├── SCN6M_SUBM.10.layer_map.txt │ ├── osu018.par │ └── osu018.sh ├── osu035 │ ├── osu035_stdcells.gds2 │ ├── osu035_setup.tcl │ ├── osu035.magicrc.in │ ├── osu035.prm │ ├── Makefile.in │ ├── osu035.par │ └── osu035.sh ├── osu050 │ ├── osu05_stdcells.gds2 │ ├── osu050_setup.tcl │ ├── osu050.magicrc.in │ ├── osu050.prm │ ├── Makefile.in │ ├── osu050.par │ └── osu050.sh └── Makefile.in ├── scripts ├── qflow_help.txt ├── qflow.in ├── makesim.sh ├── consoletext.py.in ├── place2net2.tcl.in ├── tksimpledialog.py.in ├── place2lef2.tcl.in ├── textreport.py.in ├── count_lvs.py.in ├── ybuffer.tcl.in ├── removeblocks.tcl.in ├── annotate.tcl.in ├── cleanup.sh ├── ypostproc.tcl.in ├── checkdirs.sh.in ├── getpowerground.tcl.in ├── magic_gds.sh ├── magic_drc.sh ├── blif2sim.tcl.in ├── getfillcell.tcl.in ├── blifanno.tcl.in ├── netgen_lvs.sh ├── tooltip.py.in ├── getantennacell.tcl.in ├── Makefile.in └── rtl2sim.tcl.in ├── Makefile.in ├── src ├── readdef.h ├── hash.h ├── readliberty.h ├── readverilog.h ├── Makefile.in └── lef.h ├── .gitignore ├── .github └── workflows │ └── main.yml ├── README └── install-sh /VERSION: -------------------------------------------------------------------------------- 1 | 1.4.104 2 | -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035.prm: -------------------------------------------------------------------------------- 1 | ../osu035/osu035.prm -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_redm4.par: -------------------------------------------------------------------------------- 1 | ../osu035/osu035.par -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_stdcells.v: -------------------------------------------------------------------------------- 1 | ../osu035/osu035_stdcells.v -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_redm4.magicrc.in: -------------------------------------------------------------------------------- 1 | ../osu035/osu035.magicrc.in -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_redm4_setup.tcl: -------------------------------------------------------------------------------- 1 | ../osu035/osu035_setup.tcl -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_stdcells.gds2: -------------------------------------------------------------------------------- 1 | ../osu035/osu035_stdcells.gds2 -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_stdcells.lib: -------------------------------------------------------------------------------- 1 | ../osu035/osu035_stdcells.lib -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_stdcells.sp: -------------------------------------------------------------------------------- 1 | ../osu035/osu035_stdcells.sp -------------------------------------------------------------------------------- /tech/gscl45nm/gscl45nm.gds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RTimothyEdwards/qflow/HEAD/tech/gscl45nm/gscl45nm.gds -------------------------------------------------------------------------------- /tech/osu018/osu018_stdcells.gds2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RTimothyEdwards/qflow/HEAD/tech/osu018/osu018_stdcells.gds2 -------------------------------------------------------------------------------- /tech/osu035/osu035_stdcells.gds2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RTimothyEdwards/qflow/HEAD/tech/osu035/osu035_stdcells.gds2 -------------------------------------------------------------------------------- /tech/osu050/osu05_stdcells.gds2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RTimothyEdwards/qflow/HEAD/tech/osu050/osu05_stdcells.gds2 -------------------------------------------------------------------------------- /tech/osu018/osu018_setup.tcl: -------------------------------------------------------------------------------- 1 | ignore class {-circuit1 FILL} 2 | ignore class {-circuit2 FILL} 3 | permute default 4 | property default 5 | property {-circuit1 nfet} remove ad pd as ps 6 | property {-circuit1 pfet} remove ad pd as ps 7 | -------------------------------------------------------------------------------- /tech/osu035/osu035_setup.tcl: -------------------------------------------------------------------------------- 1 | ignore class {-circuit1 FILL} 2 | ignore class {-circuit2 FILL} 3 | permute default 4 | property default 5 | property {-circuit1 nfet} remove ad pd as ps 6 | property {-circuit1 pfet} remove ad pd as ps 7 | -------------------------------------------------------------------------------- /tech/osu050/osu050_setup.tcl: -------------------------------------------------------------------------------- 1 | ignore class {-circuit1 FILL} 2 | ignore class {-circuit2 FILL} 3 | permute default 4 | property default 5 | property {-circuit1 nfet} remove ad pd as ps 6 | property {-circuit1 pfet} remove ad pd as ps 7 | -------------------------------------------------------------------------------- /tech/gscl45nm/gscl45nm_setup.tcl: -------------------------------------------------------------------------------- 1 | ignore class {-circuit1 FILL} 2 | ignore class {-circuit2 FILL} 3 | permute default 4 | property default 5 | property {-circuit1 nfet} remove ad pd as ps 6 | property {-circuit1 pfet} remove ad pd as ps 7 | -------------------------------------------------------------------------------- /scripts/qflow_help.txt: -------------------------------------------------------------------------------- 1 | 1. 2 | Selecting a project 3 | ------- 4 | 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. 5 | . 6 | -------------------------------------------------------------------------------- /scripts/qflow.in: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | # 3 | #------------------------------------------------------------------ 4 | # qflow --- main program launcher 5 | #------------------------------------------------------------------ 6 | 7 | exec QFLOW_SCRIPT_DIR/qflow.sh $argv:q 8 | exit 0 9 | -------------------------------------------------------------------------------- /tech/osu035/osu035.magicrc.in: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------- 2 | # .magicrc startup file for OSU035 project under qflow 3 | #----------------------------------------------------- 4 | 5 | path sys +QFLOW_LIB_DIR/tech/osu035 6 | tech load SCN4M_SUBM.20 -noprompt 7 | scalegrid 1 4 8 | set GND gnd 9 | set VDD vdd 10 | 11 | drc euclidean on 12 | drc off 13 | 14 | addpath digital 15 | 16 | -------------------------------------------------------------------------------- /tech/osu018/osu018.magicrc.in: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------- 2 | # .magicrc startup file for OSU018 project under qflow 3 | #----------------------------------------------------- 4 | 5 | path sys +QFLOW_LIB_DIR/tech/osu018 6 | tech load SCN6M_SUBM.10 -noprompt 7 | # scalegrid 1 9 8 | set GND gnd 9 | set VDD vdd 10 | 11 | drc euclidean on 12 | drc off 13 | 14 | addpath digital 15 | 16 | -------------------------------------------------------------------------------- /tech/osu050/osu050.magicrc.in: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------- 2 | # .magicrc startup file for OSU050 project under qflow 3 | #----------------------------------------------------- 4 | 5 | path sys +QFLOW_LIB_DIR/tech/osu050 6 | tech load SCN3ME_SUBM.30 -noprompt 7 | scalegrid 1 4 8 | set GND gnd 9 | set VDD vdd 10 | 11 | drc euclidean on 12 | drc off 13 | 14 | addpath digital 15 | 16 | -------------------------------------------------------------------------------- /tech/gscl45nm/gscl45nm.magicrc.in: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------- 2 | # .magicrc startup file for gscl45nm project under qflow 3 | #----------------------------------------------------- 4 | 5 | path sys +QFLOW_LIB_DIR/tech/gscl45nm 6 | tech load gscl45nm -noprompt 7 | 8 | # Set internal grid to 5nm (lambda is 25nm) 9 | scalegrid 1 5 10 | 11 | set GND gnd 12 | set VDD vdd 13 | 14 | drc euclidean on 15 | drc off 16 | 17 | addpath digital 18 | 19 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project main Makefile 3 | # 4 | 5 | SHELL = /bin/sh 6 | 7 | EXEEXT = @EXEEXT@ 8 | 9 | TARGETS = src scripts tech 10 | 11 | all: $(TARGETS) 12 | @for target in $(TARGETS); do\ 13 | (cd $$target ; $(MAKE) all) ;\ 14 | done 15 | 16 | install: 17 | @for target in $(TARGETS); do\ 18 | (cd $$target ; $(MAKE) install) ;\ 19 | done 20 | 21 | clean: 22 | @for target in $(TARGETS); do\ 23 | (cd $$target ; $(MAKE) clean) ;\ 24 | done 25 | 26 | distclean: 27 | @for target in $(TARGETS); do\ 28 | (cd $$target ; $(MAKE) distclean) ;\ 29 | done 30 | 31 | uninstall: 32 | @for target in $(TARGETS); do\ 33 | (cd $$target ; $(MAKE) uninstall) ;\ 34 | done 35 | -------------------------------------------------------------------------------- /src/readdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * def.h -- 3 | * 4 | * This file includes the DEF I/O functions 5 | * 6 | */ 7 | 8 | #ifndef _DEFINT_H 9 | #define _DEFINT_H 10 | 11 | #include "lef.h" 12 | 13 | extern int DefRead(char *inName, float *); 14 | 15 | extern int Numnets; 16 | extern int Numgates; 17 | extern int Numpins; 18 | extern int numSpecial; 19 | 20 | extern GATE DefFindGate(char *name); 21 | extern NET DefFindNet(char *name); 22 | extern ROW DefFindRow(int yval); 23 | extern ROW DefLowestRow(); 24 | extern void DefAddGateInstance(GATE gate); 25 | extern char *DefDesign(); 26 | 27 | /* External access to hash tables for recursion functions */ 28 | extern struct hashtable InstanceTable; 29 | extern struct hashtable NetTable; 30 | 31 | #endif /* _DEFINT_H */ 32 | -------------------------------------------------------------------------------- /scripts/makesim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | # 3 | # makesim.sh cellname 4 | # 5 | #--------------------------------------------------------------- 6 | # Run magic in batch mode to extract and generate a .sim view 7 | # for the argument cellname 8 | #--------------------------------------------------------------- 9 | 10 | if ($#argv < 1) then 11 | echo "Usage: makesim.sh " 12 | exit 1 13 | endif 14 | 15 | set magdir=${argv[1]:h} 16 | if ("$magdir" == "$argv[1]") then 17 | set magdir="." 18 | endif 19 | set cellname=${argv[1]:t:r} 20 | 21 | cd $magdir 22 | rm -f ${cellname}.ext 23 | rm -f ${cellname}.sim 24 | 25 | /usr/local/bin/magic -dnull -noconsole < gscl45nm.magicrc 32 | 33 | install: ${TECH_FILES} 34 | @echo "Installing gscl45nm tech files" 35 | $(INSTALL) -d $(DESTDIR)$(TECHINSTALL)/gscl45nm 36 | for target in $(TECH_FILES); do \ 37 | $(INSTALL) $$target $(DESTDIR)$(TECHINSTALL)/gscl45nm ;\ 38 | done 39 | 40 | clean: 41 | $(RM) -f gscl45nm.magicrc 42 | 43 | distclean: 44 | $(RM) -f gscl45nm.magicrc 45 | 46 | uninstall: 47 | 48 | -------------------------------------------------------------------------------- /tech/osu018/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project included technology osu018 files 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | DEFS = @DEFS@ 8 | LIBS = @LIBS@ 9 | LDFLAGS = @LDFLAGS@ 10 | INSTALL = @INSTALL@ 11 | 12 | prefix = @prefix@ 13 | exec_prefix = @exec_prefix@ 14 | 15 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 16 | 17 | TECH_FILES = osu018.par osu018_stdcells.lef osu018.sh 18 | TECH_FILES += osu018_stdcells.sp osu018.magicrc osu018.prm 19 | TECH_FILES += SCN6M_SUBM.10.tech osu018_stdcells.lib 20 | TECH_FILES += osu018_stdcells.v osu018_setup.tcl osu018_stdcells.gds2 21 | 22 | TECHINSTALL = @DIST_DIR@/share/qflow/tech 23 | 24 | # Substitute the target qflow tech directory name in .magicrc so that magic 25 | # can find the OSU018 techfile 26 | 27 | all: osu018.magicrc.in 28 | $(RM) -f osu018.magicrc 29 | cat osu018.magicrc.in | sed -e \ 30 | '/QFLOW_LIB_DIR/s#QFLOW_LIB_DIR#$(QFLOW_LIB_DIR)#' \ 31 | > osu018.magicrc 32 | 33 | install: ${TECH_FILES} 34 | @echo "Installing osu018 tech files" 35 | $(INSTALL) -d $(DESTDIR)$(TECHINSTALL)/osu018 36 | for target in $(TECH_FILES); do \ 37 | $(INSTALL) $$target $(DESTDIR)$(TECHINSTALL)/osu018 ;\ 38 | done 39 | 40 | clean: 41 | $(RM) -f osu018.magicrc 42 | 43 | distclean: 44 | $(RM) -f osu018.magicrc 45 | 46 | uninstall: 47 | 48 | -------------------------------------------------------------------------------- /tech/osu035/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project included technology osu035 files 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | DEFS = @DEFS@ 8 | LIBS = @LIBS@ 9 | LDFLAGS = @LDFLAGS@ 10 | INSTALL = @INSTALL@ 11 | 12 | prefix = @prefix@ 13 | exec_prefix = @exec_prefix@ 14 | 15 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 16 | 17 | TECH_FILES = osu035.par osu035_stdcells.lef osu035.sh 18 | TECH_FILES += osu035_stdcells.sp osu035.magicrc osu035.prm 19 | TECH_FILES += SCN4M_SUBM.20.tech osu035_stdcells.lib 20 | TECH_FILES += osu035_stdcells.v osu035_setup.tcl osu035_stdcells.gds2 21 | 22 | TECHINSTALL = @DIST_DIR@/share/qflow/tech 23 | 24 | # Substitute the target qflow tech directory name in .magicrc so that magic 25 | # can find the OSU035 techfile 26 | 27 | all: osu035.magicrc.in 28 | $(RM) -f osu035.magicrc 29 | cat osu035.magicrc.in | sed -e \ 30 | '/QFLOW_LIB_DIR/s#QFLOW_LIB_DIR#$(QFLOW_LIB_DIR)#' \ 31 | > osu035.magicrc 32 | 33 | install: ${TECH_FILES} 34 | @echo "Installing osu035 tech files" 35 | $(INSTALL) -d $(DESTDIR)$(TECHINSTALL)/osu035 36 | for target in $(TECH_FILES); do \ 37 | $(INSTALL) $$target $(DESTDIR)$(TECHINSTALL)/osu035 ;\ 38 | done 39 | 40 | clean: 41 | $(RM) -f osu035.magicrc 42 | 43 | distclean: 44 | $(RM) -f osu035.magicrc 45 | 46 | uninstall: 47 | 48 | -------------------------------------------------------------------------------- /tech/osu050/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project included technology osu050 files 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | DEFS = @DEFS@ 8 | LIBS = @LIBS@ 9 | LDFLAGS = @LDFLAGS@ 10 | INSTALL = @INSTALL@ 11 | 12 | prefix = @prefix@ 13 | exec_prefix = @exec_prefix@ 14 | 15 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 16 | 17 | TECH_FILES = osu050.par osu050_stdcells.lef osu050.sh 18 | TECH_FILES += osu050_stdcells.sp osu050.magicrc osu050.prm 19 | TECH_FILES += SCN3ME_SUBM.30.tech osu05_stdcells.lib 20 | TECH_FILES += osu05_stdcells.v osu050_setup.tcl osu05_stdcells.gds2 21 | 22 | TECHINSTALL = @DIST_DIR@/share/qflow/tech 23 | 24 | # Substitute the target qflow tech directory name in .magicrc so that magic 25 | # can find the OSU050 techfile 26 | 27 | all: osu050.magicrc.in 28 | $(RM) -f osu050.magicrc 29 | cat osu050.magicrc.in | sed -e \ 30 | '/QFLOW_LIB_DIR/s#QFLOW_LIB_DIR#$(QFLOW_LIB_DIR)#' \ 31 | > osu050.magicrc 32 | 33 | install: ${TECH_FILES} 34 | @echo "Installing osu050 tech files" 35 | $(INSTALL) -d $(DESTDIR)$(TECHINSTALL)/osu050 36 | for target in $(TECH_FILES); do \ 37 | $(INSTALL) $$target $(DESTDIR)$(TECHINSTALL)/osu050 ;\ 38 | done 39 | 40 | clean: 41 | $(RM) -f osu050.magicrc 42 | 43 | distclean: 44 | $(RM) -f osu050.magicrc 45 | 46 | uninstall: 47 | 48 | -------------------------------------------------------------------------------- /tech/osu035_redm4/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project included technology osu035_redm4 files 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | DEFS = @DEFS@ 8 | LIBS = @LIBS@ 9 | LDFLAGS = @LDFLAGS@ 10 | INSTALL = @INSTALL@ 11 | 12 | prefix = @prefix@ 13 | exec_prefix = @exec_prefix@ 14 | 15 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 16 | 17 | TECH_FILES = osu035_redm4.par osu035_redm4.sh osu035_redm4.magicrc osu035.prm 18 | TECH_FILES += osu035_redm4_stdcells.lef osu035_stdcells.sp osu035_stdcells.lib 19 | TECH_FILES += osu035_stdcells.v osu035_redm4_setup.tcl osu035_stdcells.gds2 20 | 21 | TECHINSTALL = @DIST_DIR@/share/qflow/tech 22 | 23 | # Substitute the target qflow tech directory name in .magicrc so that magic 24 | # can find the OSU035_REDM4 techfile 25 | 26 | all: osu035_redm4.magicrc 27 | 28 | install: ${TECH_FILES} 29 | @echo "Installing osu035_redm4 tech files" 30 | $(INSTALL) -d $(DESTDIR)$(TECHINSTALL)/osu035_redm4 31 | for target in $(TECH_FILES); do \ 32 | $(INSTALL) $$target $(DESTDIR)$(TECHINSTALL)/osu035_redm4 ;\ 33 | done 34 | 35 | osu035_redm4.magicrc: osu035_redm4.magicrc.in Makefile 36 | sed < $< -e '/QFLOW_LIB_DIR/s#QFLOW_LIB_DIR#$(QFLOW_LIB_DIR)#' > $@ 37 | 38 | clean: 39 | $(RM) -f osu035_redm4.magicrc 40 | 41 | distclean: 42 | $(RM) -f osu035_redm4.magicrc 43 | 44 | uninstall: 45 | 46 | -------------------------------------------------------------------------------- /tech/osu018/SCN6M_SUBM.10.layer_map.txt: -------------------------------------------------------------------------------- 1 | CIF/GDS layer map 2 | ------------------------------------------ 3 | CIF GDS 4 | name layer description 5 | ------------------------------------------ 6 | CWN 42 0 nwell 7 | CRW 65 0 nwell resistor 8 | CWND 92 0 nwell resistor marker 9 | CWP 41 0 pwell 10 | CAA 43 0 active (diffusion) 11 | CSN 45 0 N+ implant 12 | CSP 44 0 P+ implant 13 | CRD 66 0 active/poly resistor marker 14 | CCA 48 0 active (diffusion) contact 15 | CCC 25 0 generic contact 16 | CPG 46 0 polysilicon 17 | CCP 47 0 poly contact 18 | CV1 50 0 via1 19 | CV2 61 0 via2 20 | CV3 30 0 via3 21 | CV4 32 0 via4 22 | CV5 36 0 via5 23 | CM1 49 0 metal1 24 | CRM 70 0 metal resistor marker 25 | CRF 71 0 metal1 resistor 26 | CMFP 81 0 metal1 pin 27 | CM2 51 0 metal2 28 | CRS 72 0 metal2 resistor 29 | CMSP 82 0 metal2 pin 30 | 100 100 0 poly fill 31 | 101 101 0 metal1 fill 32 | 102 102 0 metal2 fill 33 | 103 103 0 metal3 fill 34 | 104 104 0 metal4 fill 35 | 105 105 0 metal5 fill 36 | 106 106 0 metal6 fill 37 | 109 109 0 active (diffusion) fill 38 | 119 119 0 implant fill 39 | 110 110 0 active/poly/metal fill (?) 40 | CM3 62 0 metal3 41 | CRT 73 0 metal3 resistor 42 | CMTP 83 0 metal3 pin 43 | CM4 31 0 metal4 44 | CRQ 74 0 metal4 resistor 45 | CMQP 84 0 metal4 pin 46 | CM5 33 0 metal5 47 | CRP 75 0 metal5 resistor 48 | CMPP 85 0 metal5 pin 49 | CM6 37 0 metal6 50 | CR6 76 0 metal6 resistor 51 | CM6P 85 0 metal6 pin 52 | CTM 35 0 redistribution metal 53 | CRI 79 0 redistribution resistor 54 | XP 26 0 pad 55 | COG 52 0 pad cut (overglass) 56 | CFI 27 0 field implant 57 | CX 63 0 comment 58 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | # Sequence of patterns matched against refs/tags 4 | tags: 5 | - '1.*' 6 | 7 | name: CI 8 | 9 | jobs: 10 | build_linux: 11 | name: Build/Linux 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Get the version 17 | id: get_version 18 | run: | 19 | export VERSION_NUM=$(ruby -e "print '$GITHUB_REF'.split(/[\/\.]/).select {|v| v == v.to_i.to_s }.join('.')") 20 | echo ::set-output name=value::${VERSION_NUM} 21 | - name: Build project 22 | run: | 23 | ./configure 24 | make -j$(nproc) 25 | sudo make install 26 | tar -cvf /tmp/qflow_binaries.tar.gz -C /usr/local/share/qflow . 27 | - name: Create Release 28 | id: create_release 29 | uses: actions/create-release@v1 30 | env: 31 | GITHUB_TOKEN: ${{ github.token }} 32 | with: 33 | tag_name: ${{ steps.get_version.outputs.value }} 34 | release_name: ${{ steps.get_version.outputs.value }} 35 | draft: false 36 | prerelease: false 37 | - name: Upload Release Asset 38 | id: upload-release-asset 39 | uses: actions/upload-release-asset@v1 40 | env: 41 | GITHUB_TOKEN: ${{ github.token }} 42 | with: 43 | upload_url: ${{ steps.create_release.outputs.upload_url }} 44 | asset_path: /tmp/qflow_binaries.tar.gz 45 | asset_name: qflow_${{ steps.get_version.outputs.value }}_linux_amd64.tar.gz 46 | asset_content_type: application/gzip 47 | -------------------------------------------------------------------------------- /tech/osu050/osu050.par: -------------------------------------------------------------------------------- 1 | # osu050.par --- Parameter file for GrayWolf 2 | # NOTE: all distance units are in centimicrons unless otherwise stated 3 | 4 | RULES 5 | # Values are resistance in ohms/sq, and capacitance in fF/um^2 6 | layer metal1 0.09 0.032 horizontal 7 | layer metal2 0.09 0.016 vertical 8 | layer metal3 0.05 0.010 horizontal 9 | 10 | via via12 metal1 metal2 11 | via via23 metal2 metal3 12 | 13 | width metal1 90 14 | width metal2 90 15 | width metal3 150 16 | width via12 150 17 | width via23 150 18 | 19 | # Note: width + spacing = track pitch, as far as GrayWolf is 20 | # concerned. So adjust spacing to make the correct pitch. 21 | # A track pitch < actual track pitch may cause pins to overlap! 22 | # Track pitches for the preferred routing direction are: 23 | # metal1: 300, metal2: 240, metal3: 300 24 | 25 | spacing metal1 metal1 210 26 | spacing metal2 metal2 150 27 | spacing metal3 metal3 150 28 | 29 | # Stacked vias allowed 30 | spacing via12 via23 0 31 | 32 | overhang via12 metal1 8 33 | overhang via12 metal2 6 34 | 35 | overhang via23 metal2 8 36 | overhang via23 metal3 6 37 | 38 | ENDRULES 39 | 40 | *vertical_wire_weight : 1.0 41 | *vertical_path_weight : 1.0 42 | *padspacing : variable 43 | *rowSep : 0.0 0 44 | *track.pitch : 0.0 45 | *minimum_pad_space : 360 46 | *gridX : 240 47 | *gridY : 300 48 | *gridOffsetX : 0 49 | *gridOffsetY : 0 50 | *graphics.wait : off 51 | *last_chance.wait : off 52 | *random.seed : 12345 53 | 54 | TWMC*chip.aspect.ratio : 0.75 55 | 56 | TWSC*feedThruWidth : 240 layer 1 57 | TWSC*do.global.route : on 58 | TWSC*ignore_feeds : true 59 | TWSC*call_row_evener : true 60 | TWSC*even_rows_maximally : true 61 | # TWSC*no.graphics : on 62 | 63 | GENR*row_to_tile_spacing: 1 64 | # GENR*numrows : 6 65 | GENR*flip_alternate_rows : 1 66 | -------------------------------------------------------------------------------- /tech/osu018/osu018.par: -------------------------------------------------------------------------------- 1 | # osu018.par --- Parameter file for GrayWolf 2 | # NOTE: all distance units are in centimicrons unless otherwise stated 3 | 4 | RULES 5 | # values are resistance in ohms/sq and capacitance in fF/um^2 6 | layer metal1 0.07 0.030 horizontal 7 | layer metal2 0.07 0.017 vertical 8 | layer metal3 0.07 0.006 horizontal 9 | layer metal4 0.04 0.004 vertical 10 | 11 | via via12 metal1 metal2 12 | via via23 metal2 metal3 13 | via via34 metal3 metal4 14 | 15 | width metal1 60 16 | width metal2 60 17 | width metal3 60 18 | width metal4 120 19 | width via12 60 20 | width via23 60 21 | width via34 120 22 | 23 | # Set spacing = track pitch - width, so that GrayWolf places pins 24 | # on the right pitch. 25 | # Pitches are (in um): 26 | # metal1 = 200, metal2 = 160, metal3 = 200, metal4 = 320 27 | 28 | spacing metal1 metal1 140 29 | spacing metal2 metal2 100 30 | spacing metal3 metal3 140 31 | spacing metal4 metal4 200 32 | 33 | # Stacked vias allowed 34 | spacing via12 via23 0 35 | spacing via23 via34 0 36 | 37 | overhang via12 metal1 8 38 | overhang via12 metal2 6 39 | 40 | overhang via23 metal2 8 41 | overhang via23 metal3 6 42 | 43 | overhang via34 metal3 14 44 | overhang via34 metal4 16 45 | ENDRULES 46 | 47 | *vertical_wire_weight : 1.0 48 | *vertical_path_weight : 1.0 49 | *padspacing : variable 50 | *rowSep : 0.0 0 51 | *track.pitch : 80 52 | *minimum_pad_space : 120 53 | *gridX : 80 54 | *gridY : 100 55 | *gridOffsetX : 0 56 | *gridOffsetY : 0 57 | *graphics.wait : off 58 | *last_chance.wait : off 59 | *random.seed : 12345 60 | 61 | TWMC*chip.aspect.ratio : 0.75 62 | 63 | TWSC*feedThruWidth : 80 layer 1 64 | TWSC*do.global.route : on 65 | TWSC*ignore_feeds : true 66 | TWSC*call_row_evener : true 67 | TWSC*even_rows_maximally : true 68 | # TWSC*no.graphics : on 69 | 70 | GENR*row_to_tile_spacing: 1 71 | # GENR*numrows : 6 72 | GENR*flip_alternate_rows : 1 73 | -------------------------------------------------------------------------------- /scripts/consoletext.py.in: -------------------------------------------------------------------------------- 1 | #!ENV_PATH python3 2 | # 3 | #-------------------------------------------------------- 4 | """ 5 | consoletext --- extends tkinter class Text 6 | with stdout and stderr redirection. 7 | """ 8 | #-------------------------------------------------------- 9 | # Written by Tim Edwards 10 | # efabless, inc. 11 | # September 11, 2016 12 | # Version 0.1 13 | #-------------------------------------------------------- 14 | 15 | import sys 16 | import tkinter 17 | 18 | class ConsoleText(tkinter.Text): 19 | linelimit = 500 20 | class IORedirector(object): 21 | '''A general class for redirecting I/O to this Text widget.''' 22 | def __init__(self,text_area): 23 | self.text_area = text_area 24 | 25 | class StdoutRedirector(IORedirector): 26 | '''A class for redirecting stdout to this Text widget.''' 27 | def write(self,str): 28 | self.text_area.write(str,False) 29 | 30 | class StderrRedirector(IORedirector): 31 | '''A class for redirecting stderr to this Text widget.''' 32 | def write(self,str): 33 | self.text_area.write(str,True) 34 | 35 | def __init__(self, master=None, cnf={}, **kw): 36 | '''See the __init__ for Tkinter.Text.''' 37 | 38 | tkinter.Text.__init__(self, master, cnf, **kw) 39 | 40 | self.tag_configure('stdout',background='white',foreground='black') 41 | self.tag_configure('stderr',background='white',foreground='red') 42 | # None of these works! Cannot change selected text background! 43 | self.config(selectbackground='blue', selectforeground='white') 44 | self.tag_configure('sel',background='blue',foreground='white') 45 | 46 | def write(self, val, is_stderr=False): 47 | lines = int(self.index('end-1c').split('.')[0]) 48 | if lines > self.linelimit: 49 | self.delete('1.0', str(lines - self.linelimit) + '.0') 50 | self.insert('end',val,'stderr' if is_stderr else 'stdout') 51 | self.see('end') 52 | 53 | def limit(self, val): 54 | self.linelimit = val 55 | -------------------------------------------------------------------------------- /tech/gscl45nm/gscl45nm.par: -------------------------------------------------------------------------------- 1 | # gscl45nm.par --- Parameter file for GrayWolf 2 | # NOTE: all distance units are in centimicrons unless otherwise stated 3 | 4 | RULES 5 | # values are resistance in ohms/sq and capacitance in fF/um^2 6 | layer metal1 0.07 0.030 horizontal 7 | layer metal2 0.07 0.017 vertical 8 | layer metal3 0.07 0.006 horizontal 9 | layer metal4 0.04 0.004 vertical 10 | 11 | via via12 metal1 metal2 12 | via via23 metal2 metal3 13 | via via34 metal3 metal4 14 | 15 | width metal1 60 16 | width metal2 60 17 | width metal3 60 18 | width metal4 120 19 | width via12 60 20 | width via23 60 21 | width via34 120 22 | 23 | # Set spacing = track pitch - width, so that GrayWolf places pins 24 | # on the right pitch. 25 | # Pitches are (in um): 26 | # metal1 = 200, metal2 = 160, metal3 = 200, metal4 = 320 27 | 28 | spacing metal1 metal1 140 29 | spacing metal2 metal2 100 30 | spacing metal3 metal3 140 31 | spacing metal4 metal4 200 32 | 33 | # Stacked vias allowed 34 | spacing via12 via23 0 35 | spacing via23 via34 0 36 | 37 | overhang via12 metal1 8 38 | overhang via12 metal2 6 39 | 40 | overhang via23 metal2 8 41 | overhang via23 metal3 6 42 | 43 | overhang via34 metal3 14 44 | overhang via34 metal4 16 45 | ENDRULES 46 | 47 | *vertical_wire_weight : 1.0 48 | *vertical_path_weight : 1.0 49 | *padspacing : variable 50 | *rowSep : 0.0 0 51 | *track.pitch : 80 52 | *minimum_pad_space : 120 53 | *gridX : 80 54 | *gridY : 100 55 | *gridOffsetX : 0 56 | *gridOffsetY : 0 57 | *graphics.wait : off 58 | *last_chance.wait : off 59 | *random.seed : 12345 60 | 61 | TWMC*chip.aspect.ratio : 0.75 62 | 63 | TWSC*feedThruWidth : 80 layer 1 64 | TWSC*do.global.route : on 65 | TWSC*ignore_feeds : true 66 | TWSC*call_row_evener : true 67 | TWSC*even_rows_maximally : true 68 | # TWSC*no.graphics : on 69 | 70 | GENR*row_to_tile_spacing: 1 71 | # GENR*numrows : 6 72 | GENR*flip_alternate_rows : 1 73 | -------------------------------------------------------------------------------- /tech/osu035/osu035.par: -------------------------------------------------------------------------------- 1 | # osu035.par --- Parameter file for GrayWolf 2 | # NOTE: all distance units are in centimicrons unless otherwise stated 3 | 4 | RULES 5 | # values are resistance in ohms/sq and capacitance in fF/um^2 6 | layer metal1 0.07 0.030 horizontal 7 | layer metal2 0.07 0.017 vertical 8 | layer metal3 0.07 0.006 horizontal 9 | layer metal4 0.04 0.004 vertical 10 | 11 | via via12 metal1 metal2 12 | via via23 metal2 metal3 13 | via via34 metal3 metal4 14 | 15 | width metal1 60 16 | width metal2 60 17 | width metal3 60 18 | width metal4 120 19 | width via12 60 20 | width via23 60 21 | width via34 120 22 | 23 | # Set spacing = track pitch - width, so that GrayWolf places pins 24 | # on the right pitch. 25 | # Pitches are (in um): 26 | # metal1 = 200, metal2 = 160, metal3 = 200, metal4 = 320 27 | 28 | spacing metal1 metal1 140 29 | spacing metal2 metal2 100 30 | spacing metal3 metal3 140 31 | spacing metal4 metal4 200 32 | 33 | # Stacked vias allowed 34 | spacing via12 via23 0 35 | spacing via23 via34 0 36 | 37 | overhang via12 metal1 8 38 | overhang via12 metal2 6 39 | 40 | overhang via23 metal2 8 41 | overhang via23 metal3 6 42 | 43 | overhang via34 metal3 14 44 | overhang via34 metal4 16 45 | ENDRULES 46 | 47 | *vertical_wire_weight : 1.0 48 | *vertical_path_weight : 1.0 49 | *padspacing : variable 50 | *rowSep : 0.0 0 51 | *track.pitch : 160 52 | *minimum_pad_space : 240 53 | *gridX : 160 54 | *gridY : 200 55 | *gridOffsetX : 0 56 | *gridOffsetY : 0 57 | *graphics.wait : off 58 | *last_chance.wait : off 59 | *random.seed : 12345 60 | 61 | TWMC*chip.aspect.ratio : 0.75 62 | 63 | TWSC*feedThruWidth : 160 layer 1 64 | TWSC*do.global.route : on 65 | TWSC*ignore_feeds : true 66 | TWSC*call_row_evener : true 67 | TWSC*even_rows_maximally : true 68 | # TWSC*no.graphics : on 69 | 70 | GENR*row_to_tile_spacing: 1 71 | # GENR*numrows : 6 72 | GENR*flip_alternate_rows : 1 73 | -------------------------------------------------------------------------------- /scripts/place2net2.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # place2net2.tcl --- 4 | # 5 | # Read a GrayWolf .pin netlist file and produce a netlist file for 6 | # use with the Magic router. The nets are sorted by minor net number. 7 | # This makes use of GrayWolf's feedthroughs and the result is good for 8 | # strict channel routing (no routes are outside any channel). 9 | # 10 | # This version (place2net2) differs from the original (place2net) in that 11 | # it assumes that feedthroughs will NOT be used. It puts together all 12 | # subnets belonging to a single network, and removes all of the feedthrough 13 | # entries. 14 | # 15 | # This version also changes the output from ".net" to ".list" to avoid having 16 | # GrayWolf choke the next time it's run. 17 | #--------------------------------------------------------------------------- 18 | 19 | if {$argc == 0} { 20 | puts stdout "Usage: place2net2 " 21 | exit 0 22 | } 23 | 24 | set topname [file rootname [lindex $argv 0]] 25 | set pinfile ${topname}.pin 26 | set netfile ${topname}.list 27 | 28 | if [catch {open $pinfile r} fpin] { 29 | puts stderr "Error: can't open file $pinfile for input" 30 | exit 0 31 | } 32 | 33 | if [catch {open $netfile w} fnet] { 34 | puts stderr "Error: can't open file $netfile for output" 35 | exit 0 36 | } 37 | 38 | #-------------------------------------------------------------- 39 | 40 | puts -nonewline $fnet " Netlist File" 41 | 42 | # Parse the .pin file, writing one line of output for each line of input. 43 | 44 | set curnet {} 45 | set netblock {} 46 | 47 | while {[gets $fpin line] >= 0} { 48 | # Each line in the file is: 49 | # 50 | regexp {^([^ ]+)[ \t]+(\d+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+[^ ]+[ \t]+[^ ]+[ \t]+([^ ]+)} \ 51 | $line lmatch netname subnet instance pinname px py layer 52 | if {"$netname" != "$curnet"} { 53 | set curnet $netname 54 | puts $fnet "" 55 | } 56 | if {[string first twfeed ${instance}] == -1} { 57 | if {[string first twpin_ ${instance}] == 0} { 58 | puts $fnet ${pinname} 59 | } elseif {$instance != "PSEUDO_CELL"} { 60 | puts $fnet ${instance}/${pinname} 61 | } 62 | } 63 | } 64 | 65 | close $fpin 66 | close $fnet 67 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _HASH_H 2 | #define _HASH_H 3 | 4 | #define TINYHASHSIZE 17 5 | #define SMALLHASHSIZE 997 6 | #define LARGEHASHSIZE 99997 7 | 8 | struct hashlist { 9 | char *name; 10 | void *ptr; 11 | struct hashlist *next; 12 | }; 13 | 14 | struct hashtable { 15 | int hashsize; 16 | int hashfirstindex; /* for iterating through table */ 17 | struct hashlist *hashfirstptr; /* ditto */ 18 | struct hashlist **hashtab; /* this is the actual table */ 19 | }; 20 | 21 | extern void InitializeHashTable(struct hashtable *table, int hashsize); 22 | extern int RecurseHashTable(struct hashtable *table, 23 | int (*func)(struct hashlist *elem)); 24 | extern int RecurseHashTableValue(struct hashtable *table, 25 | int (*func)(struct hashlist *elem, int), int); 26 | extern struct nlist *RecurseHashTablePointer(struct hashtable *table, 27 | struct nlist *(*func)(struct hashlist *elem, 28 | void *), void *pointer); 29 | 30 | extern int CountHashTableEntries(struct hashlist *p); 31 | extern int CountHashTableBinsUsed(struct hashlist *p); 32 | extern void HashDelete(char *name, struct hashtable *table); 33 | extern void HashIntDelete(char *name, int value, struct hashtable *table); 34 | extern void HashKill(struct hashtable *table); 35 | 36 | /* these functions return a pointer to a hash list element */ 37 | extern struct hashlist *HashInstall(char *name, struct hashtable *table); 38 | extern struct hashlist *HashPtrInstall(char *name, void *ptr, 39 | struct hashtable *table); 40 | extern struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr, 41 | struct hashtable *table); 42 | 43 | /* these functions return the ->ptr field of a struct hashtable */ 44 | extern void *HashLookup(char *s, struct hashtable *table); 45 | extern void *HashIntLookup(char *s, int i, struct hashtable *table); 46 | extern void *HashFirst(struct hashtable *table); 47 | extern void *HashNext(struct hashtable *table); 48 | 49 | extern unsigned long hashnocase(char *s, int); 50 | extern unsigned long hash(char *s, int); 51 | 52 | extern int (*matchfunc)(char *, char *); 53 | /* matchintfunc() compares based on the name and the first */ 54 | /* entry of the pointer value, which is cast as an integer */ 55 | extern int (*matchintfunc)(char *, char *, int, int); 56 | extern unsigned long (*hashfunc)(char *, int); 57 | 58 | /* the matching functions themselves */ 59 | extern int match(char *s1, char *s2); 60 | extern int matchnocase(char *s1, char *s2); 61 | 62 | #endif /* _HASH_H */ 63 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NEW 2 | qflow v.1.4 3 | --------------------------------------------------------------- 4 | Tim Edwards 5 | Open Circuit Design 6 | v1.0 April 2013 7 | v1.1 May 2015 8 | v1.2 May 2018 9 | v1.3 December 2018 10 | v1.4 December 2018 11 | --------------------------------------------------------------- 12 | GPL Copyright (c) 2018 13 | --------------------------------------------------------------- 14 | Default technology uses OSU open source digital cell libraries 15 | See http://vlsiarch.ecen.okstate.edu/flows/ 16 | --------------------------------------------------------------- 17 | 18 | To compile and install: 19 | 20 | ./configure 21 | make 22 | make install 23 | 24 | See full instructions on http://opencircuitdesign.com/qflow/ 25 | 26 | The ./configure needs arguments for each tool of the tool 27 | chain that is not in the standard search path. Qflow will 28 | need to be able to find the following tools: 29 | 30 | yosys 31 | graywolf 32 | qrouter 33 | magic 34 | netgen 35 | 36 | All of these tools typically install in a standard location 37 | that is in the normal user path, such as /usr/local/bin/. 38 | 39 | -------------------------------------------------------------- 40 | "qflow" is the original verilog digital flow from 41 | opencircuitdesign, reorganized for the following reasons: 42 | 43 | (1) All the technology-independent scripts and programs can 44 | be organized in one place, and not be copied for every 45 | project. 46 | 47 | (2) All the technology-dependent files can be organized 48 | under a single tech directory, with the technology 49 | specified on the command-line, or even pulled from a 50 | file in the layout directory. 51 | 52 | (3) Various working directories can be reassigned by 53 | setting environment variables 54 | 55 | (4) The C source code files can be compiled under a standard 56 | "make" process 57 | 58 | (5) The compile and install process can be put under gnu 59 | automake/autoconf. 60 | 61 | (6) The location of external programs (e.g., qrouter and graywolf) 62 | can be searched for by autoconf, or passed as arguments 63 | to the configure script 64 | 65 | (7) Try to convert and handle all files in standard formats: 66 | mainly RTL verilog, LEF, and DEF. 67 | 68 | (8) Consolidate all configuration information into a single 69 | config file that can call out each tool or tools for 70 | which the configuration information applies, much like 71 | graywolf does, except extended to include the other 72 | tools in qflow. 73 | -------------------------------------------------------------- 74 | -------------------------------------------------------------------------------- /scripts/tksimpledialog.py.in: -------------------------------------------------------------------------------- 1 | #!ENV_PATH python3 2 | # 3 | # Dialog class for tkinter 4 | 5 | import os 6 | import tkinter 7 | from tkinter import ttk 8 | 9 | class Dialog(tkinter.Toplevel): 10 | 11 | def __init__(self, parent, message = None, title = None, seed = None, border = 'blue', **kwargs): 12 | 13 | tkinter.Toplevel.__init__(self, parent) 14 | self.transient(parent) 15 | 16 | if title: 17 | self.title(title) 18 | 19 | self.configure(background=border, padx=2, pady=2) 20 | self.obox = ttk.Frame(self) 21 | self.obox.pack(side = 'left', fill = 'both', expand = 'true') 22 | 23 | self.parent = parent 24 | self.result = None 25 | body = ttk.Frame(self.obox) 26 | self.initial_focus = self.body(body, message, seed, **kwargs) 27 | body.pack(padx = 5, pady = 5) 28 | self.buttonbox() 29 | self.grab_set() 30 | 31 | if not self.initial_focus: 32 | self.initial_focus = self 33 | 34 | self.protocol("WM_DELETE_WINDOW", self.cancel) 35 | self.geometry("+%d+%d" % (parent.winfo_rootx() + 50, 36 | parent.winfo_rooty() + 50)) 37 | 38 | self.initial_focus.focus_set() 39 | self.wait_window(self) 40 | 41 | # Construction hooks 42 | 43 | def body(self, master, **kwargs): 44 | # Create dialog body. Return widget that should have 45 | # initial focus. This method should be overridden 46 | pass 47 | 48 | def buttonbox(self): 49 | # Add standard button box. Override if you don't want the 50 | # standard buttons 51 | 52 | box = ttk.Frame(self.obox) 53 | 54 | self.okb = ttk.Button(box, text="OK", width=10, command=self.ok, default='active') 55 | self.okb.pack(side='left', padx=5, pady=5) 56 | w = ttk.Button(box, text="Cancel", width=10, command=self.cancel) 57 | w.pack(side='left', padx=5, pady=5) 58 | 59 | self.bind("", self.ok) 60 | self.bind("", self.cancel) 61 | box.pack(fill='x', expand='true') 62 | 63 | # Standard button semantics 64 | 65 | def ok(self, event=None): 66 | 67 | if not self.validate(): 68 | self.initial_focus.focus_set() # put focus back 69 | return 70 | 71 | self.withdraw() 72 | self.update_idletasks() 73 | self.result = self.apply() 74 | self.cancel() 75 | 76 | def cancel(self, event=None): 77 | 78 | # Put focus back to the parent window 79 | self.parent.focus_set() 80 | self.destroy() 81 | 82 | def validate(self): 83 | return 1 # Override this 84 | 85 | def apply(self): 86 | return None # Override this 87 | -------------------------------------------------------------------------------- /src/readliberty.h: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------*/ 2 | /* readliberty.h --- */ 3 | /* */ 4 | /* Header file for readliberty.c */ 5 | /*--------------------------------------------------------------*/ 6 | 7 | #define LIB_LINE_MAX 65535 8 | 9 | #define INIT 0 10 | #define LIBBLOCK 1 11 | #define CELLDEF 2 12 | #define PINDEF 3 13 | #define TIMING 4 14 | 15 | // Pin types (a clock is also an input) 16 | #define PIN_UNKNOWN -1 17 | #define PIN_INPUT 0 18 | #define PIN_CLOCK 1 19 | #define PIN_OUTPUT 2 20 | #define PIN_POWER 3 21 | #define PIN_GROUND 4 22 | 23 | // Function translation 24 | #define GROUPBEGIN 1 25 | #define GROUPEND 2 26 | #define SIGNAL 3 27 | #define OPERATOR 4 28 | #define XOPERATOR 5 29 | #define SEPARATOR 6 30 | 31 | /*--------------------------------------------------------------*/ 32 | /* Database */ 33 | /*--------------------------------------------------------------*/ 34 | 35 | typedef struct _lutable *lutableptr; 36 | 37 | typedef struct _lutable { 38 | char *name; 39 | char invert; // 0 if times x caps, 1 if caps x times 40 | char *var1; // Name of array in index1 41 | char *var2; // Name of array in index2 42 | int tsize; // Number of entries in time array 43 | int csize; // Number of entries in cap array 44 | double *times; // Time array (units fF) 45 | double *caps; // Cap array (units ps) 46 | lutableptr next; 47 | } LUTable; 48 | 49 | /*--------------------------------------------------------------*/ 50 | 51 | typedef struct _bustype *bustypeptr; 52 | 53 | typedef struct _bustype { 54 | char *name; 55 | int from; // Bus array first index 56 | int to; // Bus array last index 57 | bustypeptr next; 58 | } BUStype; 59 | 60 | /*--------------------------------------------------------------*/ 61 | 62 | typedef struct _pin *pinptr; 63 | 64 | typedef struct _pin { 65 | char *name; 66 | int type; 67 | double cap; 68 | double maxtrans; 69 | double maxcap; 70 | pinptr next; 71 | } Pin; 72 | 73 | /*--------------------------------------------------------------*/ 74 | 75 | typedef struct _cell *cellptr; 76 | 77 | typedef struct _cell { 78 | char *name; 79 | char *function; 80 | Pin *pins; 81 | double area; 82 | double slope; 83 | double mintrans; 84 | LUTable *reftable; 85 | double *times; // Local values for time indexes, if given 86 | double *caps; // Local values for cap indexes, if given 87 | double *values; // Matrix of all values 88 | cellptr next; 89 | } Cell; 90 | 91 | /*--------------------------------------------------------------*/ 92 | 93 | extern int get_pintype(Cell *curcell, char *pinname); 94 | extern int get_pincap(Cell *curcell, char *pinname, double *retcap); 95 | extern int get_values(Cell *curcell, double *retdelay, double *retcap); 96 | extern Cell *read_liberty(char *libfile, char *pattern); 97 | extern Cell *get_cell_by_name(Cell *cell, char *name); 98 | extern Pin *get_pin_by_name(Cell *curcell, char *pinname); 99 | extern void delete_cell_list(Cell *cell); 100 | 101 | /*--------------------------------------------------------------*/ 102 | -------------------------------------------------------------------------------- /tech/osu035/osu035.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | #--------------------------------------------------------------- 3 | # Shell script setting up all variables used by the qflow scripts 4 | # for this project 5 | #--------------------------------------------------------------- 6 | 7 | # The LEF file containing standard cell macros 8 | 9 | set leffile=osu035_stdcells.lef 10 | 11 | # The SPICE netlist containing subcell definitions for all the standard cells 12 | 13 | set spicefile=osu035_stdcells.sp 14 | 15 | # The liberty format file containing standard cell timing and function information 16 | 17 | set libertyfile=osu035_stdcells.lib 18 | 19 | # If there is another LEF file containing technology information 20 | # that is separate from the file containing standard cell macros, 21 | # set this. Otherwise, leave it defined as an empty string. 22 | 23 | set techleffile="" 24 | 25 | # All cells below should be the lowest output drive strength value, 26 | # if the standard cell set has multiple cells with different drive 27 | # strengths. Comment out any cells that do not exist. 28 | 29 | set flopcell=DFFPOSX1 ;# Standard positive-clocked DFF, no set or reset 30 | # set flopset=DFFS ;# DFF with preset, if available 31 | # set flopreset=DFFSR ;# DFF with clear, if available 32 | set flopsetreset=DFFSR ;# DFF with both set and clear 33 | set setpin=S ;# The name of the set pin on DFFs 34 | set resetpin=R ;# The name of the clear/reset pin on DFFs 35 | set setpininvert=1 ;# Set this to 1 if the set pin is inverted (!set) 36 | set resetpininvert=1 ;# Set this to 1 if the reset pin is inverted (!reset) 37 | set floppinout=Q ;# Name of the output pin on DFFs 38 | set floppinin=D ;# Name of the output pin on DFFs 39 | set floppinclk=CLK ;# Name of the clock pin on DFFs 40 | 41 | set bufcell=BUFX2 ;# Minimum drive strength buffer cell 42 | set bufpin_in=A ;# Name of input port to buffer cell 43 | set bufpin_out=Y ;# Name of output port to buffer cell 44 | set clkbufcell=CLKBUF1 ;# Minimum drive strength clock buffer cell 45 | set clkbufpin_in=A ;# Name of input port to clock buffer cell 46 | set clkbufpin_out=Y ;# Name of output port to clock buffer cell 47 | set inverter=INVX1 ;# Minimum drive strength inverter cell 48 | set invertpin_in=A ;# Name of input port to inverter cell 49 | set invertpin_out=Y ;# Name of output port to inverter cell 50 | set norgate=NOR2X1 ;# 2-input NOR gate, minimum drive strength 51 | set norpin_in1=A ;# Name of first input pin to NOR gate 52 | set norpin_in2=B ;# Name of second input pin to NOR gate 53 | set norpin_out=Y ;# Name of output pin from OR gate 54 | set nandgate=NAND2X1 ;# 2-input NAND gate, minimum drive strength 55 | set nandpin_in1=A ;# Name of first input pin to NAND gate 56 | set nandpin_in2=B ;# Name of second input pin to NAND gate 57 | set nandpin_out=Y ;# Name of output pin from NAND gate 58 | set fillcell=FILL ;# Spacer (filler) cell (may use regexp) 59 | set decapcell="" ;# Decap (filler) cell (may use regexp) 60 | set antennacell="" ;# Antenna (filler) cell (may use regexp) 61 | set antennapin_in="" ;# Input pin name of antennta cell, if it exists 62 | 63 | set tiehi="" ;# Cell to connect to power, if one exists 64 | set tiehipin_out="" ;# Output pin name of tiehi cell, if it exists 65 | set tielo="" ;# Cell to connect to ground, if one exists 66 | set tielopin_out="" ;# Output pin name of tielo cell, if it exists 67 | 68 | set separator="" ;# Separator between gate names and drive strengths 69 | set techfile=SCN4M_SUBM.20 ;# magic techfile 70 | set magicrc=osu035.magicrc ;# magic startup script 71 | set gdsfile=osu035_stdcells.gds2 ;# GDS database of standard cells 72 | 73 | # Option defaults 74 | set fanout_options="-l 200 -c 30" ;# blifFanout target maximum latency 75 | ;# per gate 200ps, output load set to 50fF 76 | set vesta_options="--summary reports --long" 77 | set addspacers_options="-stripe 5 150 PG" 78 | -------------------------------------------------------------------------------- /tech/osu050/osu050.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | #--------------------------------------------------------------- 3 | # Shell script setting up all variables used by the qflow scripts 4 | # for this project 5 | #--------------------------------------------------------------- 6 | 7 | # The LEF file containing standard cell macros 8 | 9 | set leffile=osu050_stdcells.lef 10 | 11 | # The SPICE netlist containing subcell definitions for all the standard cells 12 | 13 | set spicefile=osu050_stdcells.sp 14 | 15 | # The liberty format file containing standard cell timing and function information 16 | 17 | set libertyfile=osu05_stdcells.lib 18 | 19 | # If there is another LEF file containing technology information 20 | # that is separate from the file containing standard cell macros, 21 | # set this. Otherwise, leave it defined as an empty string. 22 | 23 | set techleffile="" 24 | 25 | # All cells below should be the lowest output drive strength value, 26 | # if the standard cell set has multiple cells with different drive 27 | # strengths. Comment out any cells that do not exist. 28 | 29 | set flopcell=DFFPOSX1 ;# Standard positive-clocked DFF, no set or reset 30 | # set flopset=DFFS ;# DFF with preset, if available 31 | # set flopreset=DFFSR ;# DFF with clear, if available 32 | set flopsetreset=DFFSR ;# DFF with both set and clear 33 | set setpin=S ;# The name of the set pin on DFFs 34 | set resetpin=R ;# The name of the clear/reset pin on DFFs 35 | set setpininvert=1 ;# Set this to 1 if the set pin is inverted (!set) 36 | set resetpininvert=1 ;# Set this to 1 if the reset pin is inverted (!reset) 37 | set floppinout=Q ;# Name of the output pin on DFFs 38 | set floppinin=D ;# Name of the input pin on DFFs 39 | set floppinclk=CLK ;# Name of the clock pin on DFFs 40 | 41 | set bufcell=BUFX2 ;# Minimum drive strength buffer cell 42 | set bufpin_in=A ;# Name of input port to buffer cell 43 | set bufpin_out=Y ;# Name of output port to buffer cell 44 | set clkbufcell=CLKBUF1 ;# Minimum drive strength clock buffer cell 45 | set clkbufpin_in=A ;# Name of input port to clock buffer cell 46 | set clkbufpin_out=Y ;# Name of output port to clock buffer cell 47 | set inverter=INVX1 ;# Minimum drive strength inverter cell 48 | set invertpin_in=A ;# Name of input port to inverter cell 49 | set invertpin_out=Y ;# Name of output port to inverter cell 50 | set norgate=NOR2X1 ;# 2-input NOR gate, minimum drive strength 51 | set norpin_in1=A ;# Name of first input pin to NOR gate 52 | set norpin_in2=B ;# Name of second input pin to NOR gate 53 | set norpin_out=Y ;# Name of output pin from OR gate 54 | set nandgate=NAND2X1 ;# 2-input NAND gate, minimum drive strength 55 | set nandpin_in1=A ;# Name of first input pin to NAND gate 56 | set nandpin_in2=B ;# Name of second input pin to NAND gate 57 | set nandpin_out=Y ;# Name of output pin from NAND gate 58 | set fillcell=FILL ;# Spacer (filler) cell (may use regexp) 59 | set decapcell="" ;# Decap (filler) cell (may use regexp) 60 | set antennacell="" ;# Antenna (filler) cell (may use regexp) 61 | set antennapin_in="" ;# Name of input pin to antenna cell, if it exists 62 | 63 | set tiehi="" ;# Cell to connect to power, if one exists 64 | set tiehipin_out="" ;# Output pin name of tiehi cell, if it exists 65 | set tielo="" ;# Cell to connect to ground, if one exists 66 | set tielopin_out="" ;# Output pin name of tielo cell, if it exists 67 | 68 | set separator="" ;# Separator between gate names and drive strengths 69 | set techfile=SCN3ME_SUBM.30 ;# magic techfile 70 | set magicrc=osu050.magicrc ;# magic startup script 71 | set gdsfile=osu05_stdcells.gds2 ;# GDS database of standard cells 72 | 73 | # Option defaults 74 | set fanout_options="-l 300 -c 75" ;# blifFanout target maximum latency 75 | ;# per gate 300ps, output load set to 75fF 76 | set vesta_options="--long" 77 | set addspacers_options="-stripe 8 225 PG" 78 | -------------------------------------------------------------------------------- /tech/osu035_redm4/osu035_redm4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | #--------------------------------------------------------------- 3 | # Shell script setting up all variables used by the qflow scripts 4 | # for this project 5 | #--------------------------------------------------------------- 6 | 7 | # The LEF file containing standard cell macros 8 | 9 | set leffile=osu035_redm4_stdcells.lef 10 | 11 | # The SPICE netlist containing subcell definitions for all the standard cells 12 | 13 | set spicefile=osu035_stdcells.sp 14 | 15 | # The liberty format file containing standard cell timing and function information 16 | 17 | set libertyfile=osu035_stdcells.lib 18 | 19 | # If there is another LEF file containing technology information 20 | # that is separate from the file containing standard cell macros, 21 | # set this. Otherwise, leave it defined as an empty string. 22 | 23 | set techleffile="" 24 | 25 | # All cells below should be the lowest output drive strength value, 26 | # if the standard cell set has multiple cells with different drive 27 | # strengths. Comment out any cells that do not exist. 28 | 29 | set flopcell=DFFPOSX1 ;# Standard positive-clocked DFF, no set or reset 30 | # set flopset=DFFS ;# DFF with preset, if available 31 | # set flopreset=DFFSR ;# DFF with clear, if available 32 | set flopsetreset=DFFSR ;# DFF with both set and clear 33 | set setpin=S ;# The name of the set pin on DFFs 34 | set resetpin=R ;# The name of the clear/reset pin on DFFs 35 | set setpininvert=1 ;# Set this to 1 if the set pin is inverted (!set) 36 | set resetpininvert=1 ;# Set this to 1 if the reset pin is inverted (!reset) 37 | set floppinout=Q ;# Name of the output pin on DFFs 38 | set floppinin=D ;# Name of the output pin on DFFs 39 | set floppinclk=CLK ;# Name of the clock pin on DFFs 40 | 41 | set bufcell=BUFX2 ;# Minimum drive strength buffer cell 42 | set bufpin_in=A ;# Name of input port to buffer cell 43 | set bufpin_out=Y ;# Name of output port to buffer cell 44 | set clkbufcell=CLKBUF1 ;# Minimum drive strength clock buffer cell 45 | set clkbufpin_in=A ;# Name of input port to clock buffer cell 46 | set clkbufpin_out=Y ;# Name of output port to clock buffer cell 47 | set inverter=INVX1 ;# Minimum drive strength inverter cell 48 | set invertpin_in=A ;# Name of input port to inverter cell 49 | set invertpin_out=Y ;# Name of output port to inverter cell 50 | set norgate=NOR2X1 ;# 2-input NOR gate, minimum drive strength 51 | set norpin_in1=A ;# Name of first input pin to NOR gate 52 | set norpin_in2=B ;# Name of second input pin to NOR gate 53 | set norpin_out=Y ;# Name of output pin from OR gate 54 | set nandgate=NAND2X1 ;# 2-input NAND gate, minimum drive strength 55 | set nandpin_in1=A ;# Name of first input pin to NAND gate 56 | set nandpin_in2=B ;# Name of second input pin to NAND gate 57 | set nandpin_out=Y ;# Name of output pin from NAND gate 58 | set fillcell=FILL ;# Spacer (filler) cell (may use regexp) 59 | set decapcell="" ;# Decap (filler) cell (may use regexp) 60 | set antennacell="" ;# Antenna (filler) cell (may use regexp) 61 | set antennapin_in="" ;# Input pin name of antennta cell, if it exists 62 | 63 | set tiehi="" ;# Cell to connect to power, if one exists 64 | set tiehipin_out="" ;# Output pin name of tiehi cell, if it exists 65 | set tielo="" ;# Cell to connect to ground, if one exists 66 | set tielopin_out="" ;# Output pin name of tielo cell, if it exists 67 | 68 | set separator="" ;# Separator between gate names and drive strengths 69 | set techfile=SCN4M_SUBM.20 ;# magic techfile 70 | set magicrc=osu035_redm4.magicrc ;# magic startup script 71 | set gdsfile=osu035_stdcells.gds2 ;# GDS database of standard cells 72 | 73 | # Option defaults 74 | set fanout_options="-l 200 -c 30" ;# blifFanout target maximum latency 75 | ;# per gate 200ps, output load set to 50fF 76 | set vesta_options="--summary reports --long" 77 | set addspacers_options="-stripe 5 150 PG" 78 | -------------------------------------------------------------------------------- /scripts/place2lef2.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # place2lef2.tcl --- 4 | # 5 | # Read a GrayWolf .pl1 cell placement output file into Magic, using 6 | # cells from the LEF database. If there are feedthroughs, then we also 7 | # need the .pin file so we know where to draw the two pins of the feedthrough. 8 | # 9 | # Source this file into Magic and then call function "place2lef " 10 | # 11 | # Written by Tim Edwards, July 25, 2006, for MultiGiG, Inc. 12 | # 13 | # Modified from place2lef.tcl: This version assumes the existance of the 14 | # LEF views of each digital cell if the LEF file is not specified, and also 15 | # does not generate twfeed cells. 16 | #--------------------------------------------------------------------------- 17 | 18 | proc place2lef {topcell {leffile {}} {refdir "."}} { 19 | 20 | addpath ../digital 21 | box values 0 0 0 0 22 | 23 | set topname [file rootname $topcell] 24 | set pl1name ${refdir}/${topname}.pl1 25 | set pinname ${refdir}/${topname}.pin 26 | 27 | if [catch {open $pl1name r} fpl1] { 28 | puts stderr "Error: can't open file $pl1name for input" 29 | return 30 | } 31 | 32 | if {$leffile != {}} { 33 | set lefname [file rootname $leffile] 34 | if {[file dirname ${lefname}] == "."} { 35 | set lefname ${refdir}/${lefname}.lef 36 | } else { 37 | set lefname ${lefname}.lef 38 | } 39 | 40 | if {[glob -nocomplain -- $lefname] == {}} { 41 | set leflist [glob ${refdir}/*.lef] 42 | if {[llength $leflist] == 1} { 43 | set lefname [lindex $leflist 0] 44 | } else { 45 | puts stderr "Error: Couldn't find LEF file ${lefname} and" 46 | puts stderr "no (or too many) LEF files in reference directory ${refdir}" 47 | } 48 | } 49 | 50 | if [catch {lef read $lefname}] { 51 | puts stderr "Error reading LEF file ${lefname}" 52 | return 53 | } 54 | } 55 | 56 | while {[gets $fpl1 line] >= 0} { 57 | # Each line in the file is 58 | regexp \ 59 | {^[ \t]*([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)[ \t]+([^ ]+)} \ 60 | $line lmatch instance llx lly urx ury orient 61 | switch $orient { 62 | 0 {set ostr ""} 63 | 1 {set ostr "v"} 64 | 2 {set ostr "h"} 65 | 3 {set ostr "180"} 66 | 4 {set ostr "90h"} 67 | 5 {set ostr "90v"} 68 | 6 {set ostr "270"} 69 | 7 {set ostr "90"} 70 | } 71 | 72 | # Handle the "cells" named "twpin_*" 73 | 74 | if {[string equal -length 6 $instance twpin_]} { 75 | set llxnm [expr {$llx * 25}] 76 | set llynm [expr {$lly * 25}] 77 | set urxnm [expr {$urx * 25}] 78 | set urynm [expr {$ury * 25}] 79 | set labname [string range $instance 6 end] 80 | box size 0.50um 0.50um 81 | box position ${llxnm}nm ${llynm}nm 82 | box move ne 0.50um 83 | paint m2 84 | label $labname n m2 85 | } else { 86 | 87 | # Ignore the cells named "twfeed*" 88 | 89 | if {![string equal -length 6 $instance twfeed]} { 90 | 91 | # Get cellname from instance name. 92 | regsub {([^_]+)_[\d]+} $instance {\1} cellname 93 | 94 | set llxnm [expr {$llx * 25}] 95 | set llynm [expr {$lly * 25}] 96 | 97 | box position ${llxnm}nm ${llynm}nm 98 | if {$ostr == ""} { 99 | getcell $cellname 100 | } else { 101 | getcell $cellname $ostr 102 | } 103 | identify $instance 104 | } 105 | } 106 | } 107 | 108 | close $fpl1 109 | 110 | view 111 | select top cell 112 | expand 113 | } 114 | -------------------------------------------------------------------------------- /tech/osu018/osu018.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | #--------------------------------------------------------------- 3 | # Shell script setting up all variables used by the qflow scripts 4 | # for this project 5 | #--------------------------------------------------------------- 6 | 7 | # The LEF file containing standard cell macros 8 | 9 | set leffile=osu018_stdcells.lef 10 | 11 | # The SPICE netlist containing subcell definitions for all the standard cells 12 | 13 | set spicefile=osu018_stdcells.sp 14 | 15 | # The liberty format file containing standard cell timing and function information 16 | 17 | set libertyfile=osu018_stdcells.lib 18 | 19 | # If there is another LEF file containing technology information 20 | # that is separate from the file containing standard cell macros, 21 | # set this. Otherwise, leave it defined as an empty string. 22 | 23 | set techleffile="" 24 | 25 | # All cells below should be the lowest output drive strength value, 26 | # if the standard cell set has multiple cells with different drive 27 | # strengths. Comment out any cells that do not exist. 28 | 29 | set flopcell=DFFPOSX1 ;# Standard positive-clocked DFF, no set or reset 30 | # set flopset=DFFS ;# DFF with preset, if available 31 | # set flopreset=DFFSR ;# DFF with clear, if available 32 | set flopsetreset=DFFSR ;# DFF with both set and clear 33 | set setpin=S ;# The name of the set pin on DFFs 34 | set resetpin=R ;# The name of the clear/reset pin on DFFs 35 | set setpininvert=1 ;# Set this to 1 if the set pin is inverted (!set) 36 | set resetpininvert=1 ;# Set this to 1 if the reset pin is inverted (!reset) 37 | set floppinout=Q ;# Name of the output pin on DFFs 38 | set floppinin=D ;# Name of the output pin on DFFs 39 | set floppinclk=CLK ;# Name of the clock pin on DFFs 40 | 41 | set bufcell=BUFX2 ;# Minimum drive strength buffer cell 42 | set bufpin_in=A ;# Name of input port to buffer cell 43 | set bufpin_out=Y ;# Name of output port to buffer cell 44 | set clkbufcell=CLKBUF1 ;# Minimum drive strength clock buffer cell 45 | set clkbufpin_in=A ;# Name of input port to clock buffer cell 46 | set clkbufpin_out=Y ;# Name of output port to clock buffer cell 47 | set inverter=INVX1 ;# Minimum drive strength inverter cell 48 | set invertpin_in=A ;# Name of input port to inverter cell 49 | set invertpin_out=Y ;# Name of output port to inverter cell 50 | set norgate=NOR2X1 ;# 2-input NOR gate, minimum drive strength 51 | set norpin_in1=A ;# Name of first input pin to NOR gate 52 | set norpin_in2=B ;# Name of second input pin to NOR gate 53 | set norpin_out=Y ;# Name of output pin from OR gate 54 | set nandgate=NAND2X1 ;# 2-input NAND gate, minimum drive strength 55 | set nandpin_in1=A ;# Name of first input pin to NAND gate 56 | set nandpin_in2=B ;# Name of second input pin to NAND gate 57 | set nandpin_out=Y ;# Name of output pin from NAND gate 58 | set fillcell=FILL ;# Spacer (filler) cell (may use regexp) 59 | set decapcell="" ;# Decap (filler) cell (may use regexp) 60 | set antennacell="" ;# Antenna (filler) cell (may use regexp) 61 | set antennapin_in="" ;# Name of input pin to antenna cell, if it exists 62 | 63 | set tiehi="" ;# Cell to connect to power, if one exists 64 | set tiehipin_out="" ;# Output pin name of tiehi cell, if it exists 65 | set tielo="" ;# Cell to connect to ground, if one exists 66 | set tielopin_out="" ;# Output pin name of tielo cell, if it exists 67 | 68 | set separator="" ;# Separator between gate names and drive strengths 69 | set techfile=SCN6M_SUBM.10 ;# magic techfile 70 | set magicrc=osu018.magicrc ;# magic startup script 71 | set gdsfile=osu018_stdcells.gds2 ;# GDS database of standard cells 72 | 73 | # Option defaults 74 | set fanout_options="-l 100 -c 20" ;# blifFanout target maximum latency 75 | ;# per gate 100ps, output load set to 20fF 76 | set via_stacks="1" 77 | set vesta_options="--summary reports --long" 78 | set addspacers_options="-stripe 2.0 50.0 PG" 79 | set xspice_options="-io_time=1n -time=100p -idelay=10p -odelay=100p -cload=500f" 80 | -------------------------------------------------------------------------------- /tech/gscl45nm/gscl45nm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh 2 | #--------------------------------------------------------------- 3 | # Shell script setting up all variables used by the qflow scripts 4 | # for this project 5 | #--------------------------------------------------------------- 6 | 7 | # The LEF file containing standard cell macros 8 | 9 | set leffile=gscl45nm.lef 10 | 11 | # The SPICE netlist containing subcell definitions for all the standard cells 12 | 13 | set spicefile=gscl45nm.sp 14 | 15 | # The liberty format file containing standard cell timing and function information 16 | 17 | set libertyfile=gscl45nm.lib 18 | 19 | # If there is another LEF file containing technology information 20 | # that is separate from the file containing standard cell macros, 21 | # set this. Otherwise, leave it defined as an empty string. 22 | 23 | set techleffile="" 24 | 25 | # All cells below should be the lowest output drive strength value, 26 | # if the standard cell set has multiple cells with different drive 27 | # strengths. Comment out any cells that do not exist. 28 | 29 | set flopcell=DFFPOSX1 ;# Standard positive-clocked DFF, no set or reset 30 | # set flopset=DFFS ;# DFF with preset, if available 31 | # set flopreset=DFFSR ;# DFF with clear, if available 32 | set flopsetreset=DFFSR ;# DFF with both set and clear 33 | set setpin=S ;# The name of the set pin on DFFs 34 | set resetpin=R ;# The name of the clear/reset pin on DFFs 35 | set setpininvert=1 ;# Set this to 1 if the set pin is inverted (!set) 36 | set resetpininvert=1 ;# Set this to 1 if the reset pin is inverted (!reset) 37 | set floppinout=Q ;# Name of the output pin on DFFs 38 | set floppinin=D ;# Name of the output pin on DFFs 39 | set floppinclk=CLK ;# Name of the clock pin on DFFs 40 | 41 | set bufcell=BUFX2 ;# Minimum drive strength buffer cell 42 | set bufpin_in=A ;# Name of input port to buffer cell 43 | set bufpin_out=Y ;# Name of output port to buffer cell 44 | set clkbufcell=CLKBUF1 ;# Minimum drive strength clock buffer cell 45 | set clkbufpin_in=A ;# Name of input port to clock buffer cell 46 | set clkbufpin_out=Y ;# Name of output port to clock buffer cell 47 | set inverter=INVX1 ;# Minimum drive strength inverter cell 48 | set invertpin_in=A ;# Name of input port to inverter cell 49 | set invertpin_out=Y ;# Name of output port to inverter cell 50 | set norgate=NOR2X1 ;# 2-input NOR gate, minimum drive strength 51 | set norpin_in1=A ;# Name of first input pin to NOR gate 52 | set norpin_in2=B ;# Name of second input pin to NOR gate 53 | set norpin_out=Y ;# Name of output pin from OR gate 54 | set nandgate=NAND2X1 ;# 2-input NAND gate, minimum drive strength 55 | set nandpin_in1=A ;# Name of first input pin to NAND gate 56 | set nandpin_in2=B ;# Name of second input pin to NAND gate 57 | set nandpin_out=Y ;# Name of output pin from NAND gate 58 | set fillcell=FILL ;# Spacer (filler) cell (may use regexp) 59 | set decapcell="" ;# Decap (filler) cell (may use regexp) 60 | set antennacell="" ;# Antenna (filler) cell (may use regexp) 61 | set antennapin_in="" ;# Name of input pin to antenna cell, if it exists 62 | 63 | set tiehi="" ;# Cell to connect to power, if one exists 64 | set tiehipin_out="" ;# Output pin name of tiehi cell, if it exists 65 | set tielo="" ;# Cell to connect to ground, if one exists 66 | set tielopin_out="" ;# Output pin name of tielo cell, if it exists 67 | 68 | set gndnet=gnd ;# Name used for ground pins in standard cells 69 | set vddnet=vdd ;# Name used for power pins in standard cells 70 | 71 | set separator="" ;# Separator between gate names and drive strengths 72 | set techfile=gscl45nm ;# magic techfile 73 | set magicrc=gscl45nm.magicrc ;# magic startup script 74 | set gdsfile=gscl45nm.gds ;# GDS database of standard cells 75 | 76 | set fanout_options="-l 200 -c 50" ;# blifFanout target maximum latency 77 | ;# per gate 200ps, output load set to 50fF 78 | 79 | set base_units="1000" ;# Use nanometer base units instead of centimicrons 80 | set vesta_options="--summary reports --long" 81 | set num_layers=6 ;# Normally restrict routing to 6 layers 82 | set addspacers_options="-stripe 1.7 50.0 PG" 83 | set xspice_options="-io_time=50p -time=10p -idelay=10p -odelay=30p -cload=50f" 84 | -------------------------------------------------------------------------------- /scripts/textreport.py.in: -------------------------------------------------------------------------------- 1 | #!ENV_PATH python3 2 | # 3 | #-------------------------------------------------------- 4 | # Text Report Window for Qflow output 5 | # tool (simple text window with contents read from file) 6 | # 7 | #-------------------------------------------------------- 8 | # Written by Tim Edwards 9 | # efabless, inc. 10 | # June 26, 2017 11 | # Version 0.1 12 | #-------------------------------------------------------- 13 | 14 | import os 15 | import re 16 | import tkinter 17 | from tkinter import ttk 18 | 19 | class TextReport(tkinter.Toplevel): 20 | """Qflow text report window.""" 21 | 22 | def __init__(self, parent=None, fontsize = 11, *args, **kwargs): 23 | '''See the __init__ for Tkinter.Toplevel.''' 24 | tkinter.Toplevel.__init__(self, parent, *args, **kwargs) 25 | 26 | s = ttk.Style() 27 | s.configure('normal.TButton', font=('Helvetica', fontsize), border = 3, relief = 'raised') 28 | self.protocol("WM_DELETE_WINDOW", self.close) 29 | 30 | self.withdraw() 31 | self.title('Qflow Text Report') 32 | 33 | self.texttitle = ttk.Label(self, style='title.TLabel', text = '(no text)') 34 | self.texttitle.grid(column = 0, row = 0, sticky = "news") 35 | self.textbar = ttk.Separator(self, orient='horizontal') 36 | self.textbar.grid(column = 0, row = 1, sticky = "news") 37 | 38 | self.hframe = tkinter.Frame(self) 39 | self.hframe.grid(column = 0, row = 2, sticky = "news") 40 | self.hframe.textdisplay = ttk.Frame(self.hframe) 41 | self.hframe.textdisplay.pack(side = 'left', fill = 'both', expand = 'true') 42 | self.hframe.textdisplay.page = tkinter.Text(self.hframe.textdisplay, wrap='word') 43 | self.hframe.textdisplay.page.pack(side = 'top', fill = 'both', expand = 'true') 44 | # Add scrollbar to text window 45 | self.hframe.scrollbar = ttk.Scrollbar(self.hframe) 46 | self.hframe.scrollbar.pack(side='right', fill='y') 47 | # attach text window to scrollbar 48 | self.hframe.textdisplay.page.config(yscrollcommand = self.hframe.scrollbar.set) 49 | self.hframe.scrollbar.config(command = self.hframe.textdisplay.page.yview) 50 | 51 | self.bbar = ttk.Frame(self) 52 | self.bbar.grid(column = 0, row = 3, sticky = "news") 53 | self.bbar.close_button = ttk.Button(self.bbar, text='Close', 54 | command=self.close, style = 'normal.TButton') 55 | self.bbar.close_button.grid(column=0, row=0, padx = 5) 56 | 57 | self.rowconfigure(0, weight=0) 58 | self.rowconfigure(1, weight=0) 59 | self.rowconfigure(2, weight=1) 60 | self.rowconfigure(3, weight=0) 61 | self.columnconfigure(0, weight=1) 62 | 63 | # Initialize with empty page 64 | self.text = [] 65 | self.title = '(No file to display)' 66 | self.timestamp = 0 67 | 68 | def grid_configure(self, padx, pady): 69 | pass 70 | 71 | def display(self, filename=''): 72 | # Read from file if text is empty 73 | if filename != '': 74 | if filename == self.title: 75 | statbuf = os.stat(filename) 76 | if self.text == [] or self.timestamp < statbuf.st_mtime: 77 | self.add_text_from_file(filename) 78 | self.timestamp = statbuf.st_mtime 79 | else: 80 | self.add_text_from_file(filename) 81 | 82 | # Remove and replace contents 83 | self.hframe.textdisplay.page.delete('1.0', 'end') 84 | self.hframe.textdisplay.page.insert('end', self.text) 85 | self.texttitle.configure(text = self.title) 86 | self.open() 87 | 88 | # Fill the text report from a file. 89 | 90 | def add_text_from_file(self, filename): 91 | print('Loading text text from file ' + filename) 92 | with open(filename, 'r', encoding='utf-8') as f: 93 | self.text = f.read() 94 | self.title = filename 95 | self.display() 96 | 97 | def close(self): 98 | # pop down text window 99 | self.withdraw() 100 | 101 | def open(self): 102 | # pop up text window 103 | self.deiconify() 104 | self.lift() 105 | -------------------------------------------------------------------------------- /src/readverilog.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------*/ 2 | /* readverilog.h -- Input for Verilog format (structural verilog only) */ 3 | /*----------------------------------------------------------------------*/ 4 | 5 | /*------------------------------------------------------*/ 6 | /* Definitions and structures */ 7 | /*------------------------------------------------------*/ 8 | 9 | #ifndef FALSE 10 | #define FALSE 0 11 | #endif 12 | #ifndef TRUE 13 | #define TRUE 1 14 | #endif 15 | 16 | /* 'X' is used here to separate the single-character delimiters */ 17 | /* from the two-character delimiters. */ 18 | 19 | #define VLOG_DELIMITERS "///**/(**)#(X,;:(){}[]=" 20 | #define VLOG_PIN_NAME_DELIMITERS "///**/(**)X()" 21 | #define VLOG_PIN_CHECK_DELIMITERS "///**/(**)X(),{}" 22 | 23 | #define VERILOG_EXTENSION ".v" 24 | 25 | /*------------------------------------------------------*/ 26 | /* Ports and instances are hashed for quick lookup but */ 27 | /* also placed in a linked list so that they can be */ 28 | /* output in the same order as the original file. */ 29 | /*------------------------------------------------------*/ 30 | 31 | struct portrec { 32 | char *name; 33 | char *net; /* May be a {...} list */ 34 | int direction; 35 | struct portrec *next; 36 | }; 37 | 38 | struct instance { /* Hashed by instance name */ 39 | char *instname; 40 | char *cellname; 41 | int arraystart; /* -1 if not arrayed */ 42 | int arrayend; /* -1 if not arrayed */ 43 | struct portrec *portlist; 44 | struct hashtable propdict; /* Instance properties */ 45 | struct instance *next; 46 | }; 47 | 48 | /*------------------------------------------------------*/ 49 | /* Basic cell definition (hashed by name) */ 50 | /*------------------------------------------------------*/ 51 | 52 | struct cellrec { 53 | char *name; /* Cellname */ 54 | 55 | struct hashtable nets; /* Internal nets */ 56 | struct hashtable propdict; /* Properties */ 57 | 58 | struct portrec *portlist; 59 | struct instance *instlist; 60 | struct instance *lastinst; /* Track last item in list */ 61 | }; 62 | 63 | /*------------------------------------------------------*/ 64 | 65 | #define PORT_NONE 0 66 | #define PORT_INPUT 1 67 | #define PORT_OUTPUT 2 68 | #define PORT_INOUT 3 69 | 70 | #define BUS_NONE -1 71 | 72 | /*------------------------------------------------------*/ 73 | /* Net structure (hashed by root name, if a bus) */ 74 | /*------------------------------------------------------*/ 75 | 76 | struct netrec { 77 | int start; /* start index, if a bus */ 78 | int end; /* end index, if a bus */ 79 | }; 80 | 81 | /*------------------------------------------------------*/ 82 | /* Structure for stacking nested module definitions */ 83 | /*------------------------------------------------------*/ 84 | 85 | struct cellstack { 86 | struct cellrec *cell; 87 | struct cellstack *next; 88 | }; 89 | 90 | /*------------------------------------------------------*/ 91 | /* Structure for nested "include" files */ 92 | /*------------------------------------------------------*/ 93 | 94 | struct filestack { 95 | FILE *file; 96 | struct filestack *next; 97 | }; 98 | 99 | /*------------------------------------------------------*/ 100 | /* External variable declarations */ 101 | /*------------------------------------------------------*/ 102 | 103 | extern int vlinenum; 104 | 105 | /*------------------------------------------------------*/ 106 | /* External function declarations */ 107 | /*------------------------------------------------------*/ 108 | 109 | extern void IncludeVerilog(char *, struct cellstack **, int); 110 | extern struct cellrec *ReadVerilog(char *); 111 | extern void FreeVerilog(struct cellrec *); 112 | extern void VerilogDefine(char *, char *); 113 | extern struct instance *AppendInstance(struct cellrec *cell, char *cellname); 114 | extern struct instance *PrependInstance(struct cellrec *cell, char *cellname); 115 | extern struct portrec *InstPort(struct instance *inst, char *portname, char *netname); 116 | extern void *BusHashLookup(char *s, struct hashtable *table); 117 | extern int GetBus(char *astr, struct netrec *wb, struct hashtable *nets); 118 | extern struct netrec *Net(struct cellrec *cell, char *netname); 119 | 120 | // readverilog.h 121 | -------------------------------------------------------------------------------- /scripts/count_lvs.py.in: -------------------------------------------------------------------------------- 1 | #!ENV_PATH python3 2 | # 3 | #--------------------------------------------------------- 4 | # LVS failure check 5 | # 6 | # This is a Python script that parses the comp.json 7 | # output from netgen and reports on the number of 8 | # errors in the top-level netlist. 9 | # 10 | #--------------------------------------------------------- 11 | # Written by Tim Edwards 12 | # efabless, inc. 13 | # Pulled from qflow GUI as standalone script Aug 20, 2018 14 | #--------------------------------------------------------- 15 | 16 | import os 17 | import re 18 | import sys 19 | import json 20 | 21 | def count_LVS_failures(filename): 22 | with open(filename, 'r') as cfile: 23 | lvsdata = json.load(cfile) 24 | 25 | # Count errors in the JSON file 26 | failures = 0 27 | devfail = 0 28 | netfail = 0 29 | pinfail = 0 30 | propfail = 0 31 | netdiff = 0 32 | devdiff = 0 33 | ncells = len(lvsdata) 34 | for c in range(0, ncells): 35 | cellrec = lvsdata[c] 36 | 37 | if c == ncells - 1: 38 | topcell = True 39 | else: 40 | topcell = False 41 | 42 | # Most errors must only be counted for the top cell, because individual 43 | # failing cells are flattened and the matching attempted again on the 44 | # flattened netlist. 45 | 46 | if topcell: 47 | if 'devices' in cellrec: 48 | devices = cellrec['devices'] 49 | devlist = [val for pair in zip(devices[0], devices[1]) for val in pair] 50 | devpair = list(devlist[p:p + 2] for p in range(0, len(devlist), 2)) 51 | for dev in devpair: 52 | c1dev = dev[0] 53 | c2dev = dev[1] 54 | diffdevs = abs(c1dev[1] - c2dev[1]) 55 | failures += diffdevs 56 | devdiff += diffdevs 57 | 58 | if 'nets' in cellrec: 59 | nets = cellrec['nets'] 60 | diffnets = abs(nets[0] - nets[1]) 61 | failures += diffnets 62 | netdiff += diffnets 63 | 64 | if 'badnets' in cellrec: 65 | badnets = cellrec['badnets'] 66 | failures += len(badnets) 67 | netfail += len(badnets) 68 | 69 | if 'badelements' in cellrec: 70 | badelements = cellrec['badelements'] 71 | failures += len(badelements) 72 | devfail += len(badelements) 73 | 74 | if 'pins' in cellrec: 75 | pins = cellrec['pins'] 76 | pinlist = [val for pair in zip(pins[0], pins[1]) for val in pair] 77 | pinpair = list(pinlist[p:p + 2] for p in range(0, len(pinlist), 2)) 78 | for pin in pinpair: 79 | # Avoid flagging global vs. local names, e.g., "gnd" vs. "gnd!," 80 | # and ignore case when comparing pins. 81 | pin0 = re.sub('!$', '', pin[0].lower()) 82 | pin1 = re.sub('!$', '', pin[1].lower()) 83 | if pin0 != pin1: 84 | # The text "(no pin)" indicates a missing pin that can be 85 | # ignored because the pin in the other netlist is a no-connect 86 | if pin0 != '(no pin)' and pin1 != '(no pin)': 87 | failures += 1 88 | pinfail += 1 89 | 90 | # Property errors must be counted for every cell 91 | if 'properties' in cellrec: 92 | properties = cellrec['properties'] 93 | failures += len(properties) 94 | propfail += len(properties) 95 | 96 | return [failures, netfail, devfail, pinfail, propfail, netdiff, devdiff] 97 | 98 | if __name__ == '__main__': 99 | 100 | failures = count_LVS_failures('comp.json') 101 | 102 | total = failures[0] 103 | if total > 0: 104 | failed = True 105 | print('LVS reports:') 106 | print(' net count difference = ' + str(failures[5])) 107 | print(' device count difference = ' + str(failures[6])) 108 | print(' unmatched nets = ' + str(failures[1])) 109 | print(' unmatched devices = ' + str(failures[2])) 110 | print(' unmatched pins = ' + str(failures[3])) 111 | print(' property failures = ' + str(failures[4])) 112 | else: 113 | print('LVS reports no net, device, pin, or property mismatches.') 114 | 115 | print('') 116 | print('Total errors = ' + str(total)) 117 | 118 | -------------------------------------------------------------------------------- /scripts/ybuffer.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #------------------------------------------------------------------------- 3 | # ybuffer --- post-process a mapped .blif file generated by yosys 4 | # 5 | # Note that this file handles mapped blif files ONLY. The only statements 6 | # allowed in the file are ".model", ".inputs", ".outputs", ".latch", 7 | # ".gate" (or ".subckt"), and ".end". 8 | # 9 | # All output nets are recorded 10 | # Buffers are inserted before each output 11 | # The existing output name is appended with "_RAW" and becomes an 12 | # internal net. 13 | # 14 | #------------------------------------------------------------------------- 15 | # Written by Tim Edwards October 25, 2013 16 | # Open Circuit Design 17 | #------------------------------------------------------------------------- 18 | 19 | if {$argc < 3} { 20 | puts stderr \ 21 | "Usage: ybuffer.tcl input_blif_file output_blif_file variables_file" 22 | exit 1 23 | } 24 | 25 | puts stdout "Buffering all outputs of module" 26 | 27 | set mbliffile [lindex $argv 0] 28 | set cellname [file rootname $mbliffile] 29 | if {"$cellname" == "$mbliffile"} { 30 | set mbliffile ${cellname}.blif 31 | } 32 | 33 | set rootname ${cellname} 34 | set outfile [lindex $argv 1] 35 | set varsfile [lindex $argv 2] 36 | 37 | #------------------------------------------------------------- 38 | # Open files for read and write 39 | 40 | if [catch {open $mbliffile r} bnet] { 41 | puts stderr "Error: can't open file $mbliffile for reading!" 42 | exit 1 43 | } 44 | 45 | if [catch {open $varsfile r} vfd] { 46 | puts stderr "Error: can't open file $varsfile for reading!" 47 | exit 1 48 | } 49 | 50 | if [catch {open $outfile w} onet] { 51 | puts stderr "Error: can't open file $outfile for writing!" 52 | exit 1 53 | } 54 | 55 | #------------------------------------------------------------- 56 | # The variables file is a UNIX tcsh script, but it can be 57 | # processed like a Tcl script if we substitute space for '=' 58 | # in the "set" commands. Then all the variables are in Tcl 59 | # variable space. 60 | #------------------------------------------------------------- 61 | 62 | while {[gets $vfd line] >= 0} { 63 | set tcmd [string map {= \ } $line] 64 | eval $tcmd 65 | } 66 | 67 | #------------------------------------------------------------- 68 | # Yosys first pass of the blif file 69 | # Parse all outputs and remember names. 70 | #------------------------------------------------------------- 71 | 72 | set outputs {} 73 | set mode none 74 | 75 | while {[gets $bnet line] >= 0} { 76 | if [regexp {^.outputs[ \t]*(.*)$} $line lmatch rest] { 77 | set mode outputs 78 | set line $rest 79 | } 80 | 81 | if {$mode == "outputs"} { 82 | while {[regexp {^[ \t]*([^ \t]+)(.*)$} $line lmatch signame rest] > 0} { 83 | lappend outputs $signame 84 | set line $rest 85 | } 86 | if {![regexp {^\\[ \n\t]*$} $line lmatch]} { 87 | set mode none 88 | } 89 | } 90 | } 91 | seek $bnet 0 92 | 93 | #------------------------------------------------------------- 94 | # Now post-process the blif file 95 | # The main thing to remember is that internal signals will be 96 | # outputs of flops, but external pin names have to be translated 97 | # to their internal names by looking at the OUTPUT section. 98 | #------------------------------------------------------------- 99 | 100 | while {[gets $bnet line] >= 0} { 101 | if [regexp {^[ \t]*\.gate} $line lmatch] { 102 | break 103 | } 104 | puts $onet $line 105 | } 106 | 107 | # Add buffers 108 | 109 | foreach signal $outputs { 110 | puts $onet " .gate ${bufcell} ${bufpin_in}=${signal}_RAW ${bufpin_out}=${signal}" 111 | } 112 | 113 | # Reorder the outputs in decreasing order, such that outputs that are substrings 114 | # of other outputs come after those outputs. That way it will always match to 115 | # the longest matching output name. 116 | 117 | set outputs [lsort -decreasing $outputs] 118 | 119 | while {1} { 120 | 121 | # All references to any signal in the output list have "_RAW" appended to the name 122 | 123 | if [regexp {^[ \t]*\.gate} $line lmatch] { 124 | set fidx 0 125 | foreach signal $outputs { 126 | while {1} { 127 | set sidx [string first ${signal} $line $fidx] 128 | if {$sidx < 0} { 129 | break 130 | } else { 131 | set fidx [string first " " $line $sidx] 132 | if {$fidx < 0} { 133 | if {[expr {[string length $line] - $sidx}] == [string length $signal]} { 134 | set line "${line}_RAW" 135 | } 136 | break 137 | } else { 138 | if {[expr {$fidx - $sidx}] == [string length $signal]} { 139 | set line [string replace $line $fidx $fidx "_RAW "] 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | puts $onet $line 148 | 149 | if [regexp {^[ \t]*.end} $line lmatch] break 150 | if {[gets $bnet line] < 0} break 151 | } 152 | 153 | close $bnet 154 | close $onet 155 | -------------------------------------------------------------------------------- /scripts/removeblocks.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # removeblocks.tcl --- 4 | # 5 | # First reads a .cel1 file from the layout directory, if 6 | # there is one. If not, there is nothing to do. 7 | # 8 | # Parse all the "hardcell" lines and make a list of all the hardcell 9 | # names that are being used as partial layout blockages. Then, remove 10 | # lines with these names from the .pl1 and .pl2 files. 11 | # 12 | # For each blockage, append an "obstruction" line to the .obs 13 | # file so that the router will be forced to route around each block. 14 | #--------------------------------------------------------------------------- 15 | 16 | if {$argc == 0} { 17 | puts stdout "Usage: removeblocks " 18 | exit 0 19 | } 20 | 21 | set topname [file rootname [lindex $argv 0]] 22 | 23 | set cel1file ${topname}.cel1 24 | set pl1file ${topname}.pl1 25 | set pl2file ${topname}.pl2 26 | set obsfile ${topname}.obs 27 | set infofile ${topname}.info 28 | 29 | set tpl1file ${topname}_tmp.pl1 30 | set tpl2file ${topname}_tmp.pl2 31 | 32 | if [catch {open $cel1file r} fcel1] { 33 | puts stdout "No ${cel1file} file with partial blockages, so nothing to do." 34 | exit 0 35 | } 36 | 37 | #-------------------------------------------------------------- 38 | 39 | # Parse the .cel1 file, making a list of hardcell names 40 | 41 | set cellnames {} 42 | 43 | while {[gets $fcel1 line] >= 0} { 44 | # Look for lines in the file with the syntax: 45 | # hardcell name 46 | if [regexp {^[ \t]*hardcell[ \t]+([^ \t]+)[\ t]+name[ \t]+([^ \t\r\n]+)}\ 47 | $line lmatch cellid cellname] { 48 | lappend cellnames $cellname 49 | } 50 | } 51 | close $fcel1 52 | 53 | if {[llength $cellnames] == 0} { 54 | puts stdout "File ${cel1file} contains no hard macros; ignoring." 55 | exit 1 56 | } 57 | 58 | # Read the info file to get the units scale used for graywolf input/output 59 | # and the list of route layers to be blocked. 60 | 61 | set units 100 62 | set layers {} 63 | if [catch {open $infofile r} finf] { 64 | puts stderr "Error: can't open file $infofile for input; no obstructions will be generated." 65 | } else { 66 | while {[gets $finf line] >= 0} { 67 | if [regexp {^[ \t]*units[ \t]+scale[ \t]+([^ \t]+)} $line lmatch units] { 68 | puts stdout "Using scalefactor ${units} for route blockages." 69 | } elseif [regexp {^[ \t]*([^ \t]+)[ \t]+} $line lmatch layer] { 70 | if {$layer != "qrouter"} { 71 | lappend layers $layer 72 | } 73 | } 74 | } 75 | } 76 | 77 | # Open graywolf output files for reading and writing 78 | 79 | if [catch {open $pl1file r} fpl1] { 80 | puts stderr "Error: can't open file $pl1file for input" 81 | exit 1 82 | } 83 | 84 | if [catch {open $pl2file r} fpl2] { 85 | puts stderr "Error: can't open file $pl2file for input" 86 | exit 1 87 | } 88 | 89 | if [catch {open $tpl1file w} ftpl1] { 90 | puts stderr "Error: can't open file $tpl1file for output" 91 | exit 1 92 | } 93 | 94 | if [catch {open $tpl2file w} ftpl2] { 95 | puts stderr "Error: can't open file $tpl2file for output" 96 | exit 1 97 | } 98 | 99 | if [catch {open $obsfile w} fobs] { 100 | puts stderr "Error: can't open file $obsfile for output" 101 | exit 1 102 | } 103 | 104 | # Parse the .pl1 file, removing lines containing blockage hardcells 105 | 106 | while {[gets $fpl1 line] >= 0} { 107 | if [regexp {^[ \t]*([^ \t]+)[ \t]+} $line lmatch cellname] { 108 | if {[lsearch $cellnames $cellname] < 0} { 109 | puts $ftpl1 $line 110 | } else { 111 | # Parse the coordinates 112 | if [regexp {^[ \t]*[^ \t]+[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+} $line lmatch llx lly urx ury] { 113 | set blx1 [expr $llx / ($units + 0.0)] 114 | set bly1 [expr $lly / ($units + 0.0)] 115 | set blx2 [expr $urx / ($units + 0.0)] 116 | set bly2 [expr $ury / ($units + 0.0)] 117 | puts stdout "Blockage found at ($blx1 $bly1) to ($blx2 $bly2)" 118 | foreach layer $layers { 119 | puts $fobs "obstruction $blx1 $bly1 $blx2 $bly2 $layer" 120 | } 121 | } else { 122 | puts stderr "Error: Failed to parse blockage coordinates" 123 | } 124 | } 125 | } else { 126 | puts $ftpl1 $line 127 | } 128 | } 129 | close $fobs 130 | 131 | # Do the same thing with the .pl2 file 132 | 133 | while {[gets $fpl2 line] >= 0} { 134 | if [regexp {^[ \t]*([^ \t]+)[ \t]+} $line lmatch cellname] { 135 | if {[lsearch $cellnames $cellname] < 0} { 136 | puts $ftpl2 $line 137 | } 138 | } else { 139 | puts $ftpl2 $line 140 | } 141 | } 142 | 143 | close $ftpl1 144 | close $ftpl2 145 | close $fpl1 146 | close $fpl2 147 | 148 | # Now rename the temporary files, overwriting the originals 149 | file rename -force $tpl1file $pl1file 150 | file rename -force $tpl2file $pl2file 151 | 152 | # Successful exit 153 | exit 0 154 | -------------------------------------------------------------------------------- /scripts/annotate.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # annotate.tcl --- 4 | # 5 | # Read a file "antenna.out" produced by qrouter, and use this to 6 | # back-annotate the .v verilog structural netlist for input 7 | # to static timing analysis. 8 | # 9 | # The "antenna.out" file contains connections made by the router to 10 | # antenna anchoring cells. It is solely a product of the routing and 11 | # should not permanently affect any netlist that becomes input to any 12 | # stage prior to routing (e.g., the .blif or .cel files used for 13 | # placement). 14 | # 15 | # The output is written to the filename specified. Input and output 16 | # files are opened at the same time, so do not specify the same file to 17 | # be overwritten. 18 | # 19 | # 5/18/2018: A file "fillcells.txt" containing all the fill cells added 20 | # to the design may be appended to the "antenna.out" file. Add these to 21 | # the netlist as well. However, antenna entries in "antenna.out" also 22 | # appear in "fillcells.txt", so ignore redundant entries. 23 | #--------------------------------------------------------------------------- 24 | 25 | namespace path {::tcl::mathop ::tcl::mathfunc} 26 | 27 | if {$argc != 3 && $argc != 4} { 28 | puts stdout "Usage: annotate.tcl []" 29 | exit 0 30 | } 31 | 32 | puts stdout "Running annotate.tcl" 33 | 34 | set antennaname [lindex $argv 0] 35 | set vlogname [lindex $argv 1] 36 | set vlogoutname [lindex $argv 2] 37 | 38 | # If an additional file name is given, it should point to the file 39 | # that sets vddnet and gndnet in the design (picked up from the LEF 40 | # files, so no need to re-parse them. 41 | 42 | if {$argc == 4} { 43 | set pwrgndfile [lindex $argv 3] 44 | 45 | if [catch {open $pwrgndfile r} fpwr] { 46 | puts stderr "Can't open file $pwrgndfile for input, assuming standard names." 47 | set vddnet false 48 | set gndnet false 49 | } else { 50 | 51 | # Read file and evaluate the same way the other shell script files are 52 | # in other of the qflow Tcl scripts (e.g., ypostproc.tcl). 53 | 54 | while {[gets $fpwr line] >= 0} { 55 | set tcmd [string map {= \ } $line] 56 | eval $tcmd 57 | } 58 | close $fpwr 59 | } 60 | } else { 61 | set vddnet false 62 | set gndnet false 63 | } 64 | 65 | set debug false 66 | 67 | #----------------------------------------------------------------- 68 | # Open antenna file for reading 69 | #----------------------------------------------------------------- 70 | 71 | if [catch {open $antennaname r} fant] { 72 | puts stderr "Error: can't open file $antennaname for input" 73 | exit 1 74 | } 75 | 76 | #----------------------------------------------------------------- 77 | # Read the antenna update file. 78 | #----------------------------------------------------------------- 79 | 80 | set added 0 81 | set changelist [dict create] 82 | set instlist [dict create] 83 | 84 | # NOTE: Lines in section "Unfixed antenna errors" are not nets to be 85 | # annotated, but a list of nets that are creating DRC antenna errors. 86 | # These nets are ignored. 87 | 88 | set in_unfix false 89 | while {[gets $fant line] >= 0} { 90 | if {$in_unfix == false} { 91 | if [regexp {[ \t]*Net=([^ \t]+)[ \t]+Instance=([^ \t]+)[ \t]+Cell=([^ \t]+)[ \t]+Pin=([^ \t]+)} $line lmatch netname instname cellname pinname] { 92 | # Keep instances seen in a dictionary and ignore redundant entries 93 | if [catch {dict get $instlist $instname}] { 94 | incr added 95 | dict set changelist $instname [list $netname $cellname $pinname] 96 | dict set instlist $instname true 97 | } 98 | } 99 | } 100 | if [regexp {[ \t]*Unfixed antenna errors:} $line lmatch] { 101 | set in_unfix true 102 | } elseif [regexp {[ \t]*# Fill cell instances} $line lmatch] { 103 | set in_unfix false 104 | } 105 | } 106 | if {$added == 0} { 107 | puts stdout "No nets needed annotating." 108 | exit 0 109 | } 110 | 111 | close $fant ;# Done with antenna input file 112 | 113 | #----------------------------------------------------------------- 114 | # Open verilog files for reading and writing 115 | #----------------------------------------------------------------- 116 | 117 | if [catch {open $vlogname r} fvlog] { 118 | puts stderr "Error: can't open file $vlogname for input" 119 | exit 1 120 | } 121 | 122 | if [catch {open $vlogoutname w} fvout] { 123 | puts stderr "Error: can't open file $vlogoutname for output" 124 | exit 1 125 | } 126 | 127 | while {[gets $fvlog line] >= 0} { 128 | if [regexp {[ \t]*endmodule} $line lmatch] { 129 | # Insert the list here 130 | dict for {instname netchange} $changelist { 131 | set netname [lindex $netchange 0] 132 | set cellname [lindex $netchange 1] 133 | set pinname [lindex $netchange 2] 134 | if {${pinname} != "-" && ${pinname} != ""} { 135 | puts $fvout "${cellname} ${instname} ( .${pinname}(${netname}) );" 136 | } else { 137 | puts $fvout "${cellname} ${instname} ( );" 138 | } 139 | } 140 | } 141 | puts $fvout $line 142 | } 143 | 144 | close $fvlog 145 | close $fvout 146 | 147 | puts stdout "Done with annotate.tcl" 148 | exit 0 149 | -------------------------------------------------------------------------------- /scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | #---------------------------------------------------------- 3 | # Workspace cleanup script for qflow 4 | #---------------------------------------------------------- 5 | # Tim Edwards, April 2013 6 | #---------------------------------------------------------- 7 | 8 | # Split out options from the main arguments (no options---this is a placeholder) 9 | set argline=(`getopt "p" $argv[1-]`) 10 | set cmdargs=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $2}'` 11 | set argc=`echo $cmdargs | wc -w` 12 | 13 | if ($argc == 2) then 14 | set argv1=`echo $cmdargs | cut -d' ' -f1` 15 | set argv2=`echo $cmdargs | cut -d' ' -f2` 16 | else 17 | echo "Usage: cleanup.sh [options] " 18 | echo " where" 19 | echo " is the name of the project directory containing" 20 | echo " a file called qflow_vars.sh." 21 | echo " is the root name of the verilog file, and" 22 | echo " [options] are:" 23 | echo " -p purge (keep sources only)" 24 | exit 1 25 | endif 26 | 27 | set purge=0 28 | 29 | foreach option (${argline}) 30 | switch (${option}) 31 | case -p: 32 | set purge=1 33 | breaksw 34 | case --: 35 | break 36 | endsw 37 | end 38 | 39 | set projectpath=$argv1 40 | set sourcename=$argv2 41 | set rootname=${sourcename:h} 42 | 43 | # This script is called with the first argument , which should 44 | # have file "qflow_vars.sh". Get all of our standard variable definitions 45 | # from the qflow_vars.sh file. 46 | 47 | if (! -f ${projectpath}/qflow_vars.sh ) then 48 | echo "Error: Cannot find file qflow_vars.sh in path ${projectpath}" 49 | exit 1 50 | endif 51 | 52 | source ${projectpath}/qflow_vars.sh 53 | cd ${projectpath} 54 | if (-f project_vars.sh) then 55 | source project_vars.sh 56 | endif 57 | 58 | #---------------------------------------------------------- 59 | # Cleanup verilog parsing files. Leave the original source! 60 | #---------------------------------------------------------- 61 | 62 | cd ${layoutdir} 63 | 64 | # Check if rootname needs a "_buf" suffix, which we use 65 | # when AddIO2blif is told to double-buffer the outputs. 66 | 67 | set origname=${rootname} 68 | if ( ! -f ${rootname}.cel && -f ${rootname}_buf.cel ) then 69 | set rootname=${rootname}_buf 70 | endif 71 | 72 | cd ${sourcedir} 73 | 74 | rm -f ${origname}.blif 75 | rm -f ${origname}.xml 76 | rm -f ${origname}_tmp.blif 77 | rm -f ${origname}_mapped.blif 78 | rm -f ${origname}_mapped_tmp.blif 79 | rm -f ${origname}.clk 80 | rm -f ${origname}.enc 81 | rm -f ${origname}.init 82 | 83 | rm -f ${origname}_mapped.v.orig 84 | rm -f ${origname}_mapped.v 85 | rm -f ${origname}_tmp.v 86 | 87 | if ( $purge == 1 ) then 88 | rm -f ${origname}.ys 89 | endif 90 | 91 | #---------------------------------------------------------- 92 | # Clean up files from synthesis. Leave the final buffered 93 | # .blif netlist and the RTL verilog files 94 | #---------------------------------------------------------- 95 | 96 | cd ${synthdir} 97 | 98 | rm -f ${origname}_bak.v 99 | rm -f ${origname}_tmp.v 100 | rm -f ${rootname}_orig.v 101 | rm -f ${rootname}_sized.v 102 | rm -f ${rootname}_mapped.v 103 | rm -f ${rootname}_anno.v 104 | rm -f ${rootname}_postroute.v 105 | rm -f ${rootname}_mapped.v 106 | rm -f ${rootname}.anno.v 107 | rm -f ${rootname}_nofanout 108 | rm -f tmp.blif 109 | rm -f tmp.v 110 | 111 | if ( $purge == 1 ) then 112 | rm -f ${origname}.v 113 | rm -f ${rootname}.spc 114 | rm -f ${rootname}.xspice 115 | rm -f ${rootname}.spef 116 | rm -f ${rootname}.sdf 117 | rm -f ${rootname}.dly 118 | rm -f ${rootname}.rtl.v 119 | rm -f ${rootname}.rtlbb.v 120 | rm -f ${rootname}.rtlnopwr.v 121 | rm -f ${rootname}_synth.rtl.v 122 | rm -f ${rootname}_synth.rtlbb.v 123 | rm -f ${rootname}_synth.rtlnopwr.v 124 | rm -f ${rootname}_powerground 125 | endif 126 | 127 | #---------------------------------------------------------- 128 | # Clean up the (excessively numerous) GrayWolf files 129 | # Keep the input .cel and .par files, and the input 130 | # _unroute.def file and the final output .def file. 131 | #---------------------------------------------------------- 132 | 133 | cd ${layoutdir} 134 | 135 | rm -f ${rootname}.blk ${rootname}.gen ${rootname}.gsav ${rootname}.history 136 | rm -f ${rootname}.log ${rootname}.mcel ${rootname}.mdat ${rootname}.mgeo 137 | rm -f ${rootname}.mout ${rootname}.mpin ${rootname}.mpth ${rootname}.msav 138 | rm -f ${rootname}.mver ${rootname}.mvio ${rootname}.stat ${rootname}.out 139 | rm -f ${rootname}.mtmp ${rootname}.pth ${rootname}.sav ${rootname}.scel 140 | rm -f ${rootname}.txt ${rootname}.info 141 | 142 | rm -f *.ext 143 | 144 | rm -f ${rootname}.pin ${rootname}.pl1 ${rootname}.pl2 145 | rm -f antenna.out fillcells.txt fail.out 146 | 147 | rm -f run_drc_map9v3.tcl 148 | rm -f generate_gds_map9v3.tcl 149 | rm -f migrate_map9v3.tcl 150 | 151 | rm -f cn 152 | rm -f failed 153 | 154 | if ( $purge == 1 ) then 155 | rm -f comp.out 156 | rm -f comp.json 157 | rm -f qflow.magicrc 158 | rm -f ${rootname}.spice 159 | rm -f ${rootname}.cel 160 | rm -f ${rootname}.cfg 161 | rm -f ${rootname}.rc 162 | rm -f ${rootname}.cel.bak 163 | rm -f ${rootname}.lef 164 | rm -f ${rootname}.def 165 | rm -f ${rootname}_unroute.def 166 | rm -f ${rootname}.mag 167 | rm -f ${rootname}.obs 168 | rm -f ${rootname}.gds 169 | rm -f ${rootname}.par.orig 170 | endif 171 | 172 | cd ${logdir} 173 | 174 | if ( $purge == 1 ) then 175 | rm -f drc.log 176 | rm -f lvs.log 177 | rm -f gdsii.log 178 | rm -f migrate.log 179 | rm -f place.log 180 | rm -f post_sta.log 181 | rm -f prep.log 182 | rm -f route.log 183 | rm -f sta.log 184 | rm -f synth.log 185 | endif 186 | 187 | #------------------------------------------------------------ 188 | # Done! 189 | #------------------------------------------------------------ 190 | -------------------------------------------------------------------------------- /scripts/ypostproc.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #------------------------------------------------------------------------- 3 | # ypostproc --- post-process a mapped .blif file generated by yosys 4 | # 5 | # Note that this file handles mapped blif files ONLY. The only statements 6 | # allowed in the file are ".model", ".inputs", ".outputs", ".latch", 7 | # ".gate" (or ".subckt"), and ".end". 8 | # 9 | # Lines using "$false" or "$true" are replaced with the net names for 10 | # power and ground buses in the tech script (to be expanded to handle 11 | # TIEHI and TIELO cells, if available in the standard cell set) 12 | # 13 | #------------------------------------------------------------------------- 14 | # Written by Tim Edwards October 8-9, 2013 15 | # Open Circuit Design 16 | # Modified for yosys, October 24, 2013 17 | #------------------------------------------------------------------------- 18 | 19 | if {$argc < 3} { 20 | puts stderr \ 21 | "Usage: ypostproc.tcl mapped_blif_file root_modname variables_file [vddnet gndnet] [-anchor=/]" 22 | exit 1 23 | } 24 | 25 | puts stdout "Yosys syntax postprocessing" 26 | 27 | set mbliffile [lindex $argv 0] 28 | set cellname [file rootname $mbliffile] 29 | if {"$cellname" == "$mbliffile"} { 30 | set mbliffile ${cellname}.blif 31 | } 32 | 33 | set outfile ${cellname}_tmp.blif 34 | set rootname [lindex $argv 1] 35 | set varsfile [lindex $argv 2] 36 | 37 | # Check if the last argument is "-anchor" 38 | set doanchors false 39 | set opttest [split [lindex $argv $argc-1] =] 40 | 41 | #------------------------------------------------------------- 42 | # Open files for read and write 43 | 44 | if [catch {open $mbliffile r} bnet] { 45 | puts stderr "Error: can't open file $mbliffile for reading!" 46 | exit 1 47 | } 48 | 49 | if [catch {open $varsfile r} vfd] { 50 | puts stderr "Error: can't open file $varsfile for reading!" 51 | exit 1 52 | } 53 | 54 | if [catch {open $outfile w} onet] { 55 | puts stderr "Error: can't open file $outfile for writing!" 56 | exit 1 57 | } 58 | 59 | #------------------------------------------------------------- 60 | # The variables file is a UNIX tcsh script, but it can be 61 | # processed like a Tcl script if we substitute space for '=' 62 | # in the "set" commands. Then all the variables are in Tcl 63 | # variable space. 64 | #------------------------------------------------------------- 65 | 66 | while {[gets $vfd line] >= 0} { 67 | set tcmd [string map {= \ } $line] 68 | eval $tcmd 69 | } 70 | close $vfd 71 | 72 | # Process antenna anchoring option 73 | 74 | if {[lindex $opttest 0] == "-anchor"} { 75 | set doanchors true 76 | set anchoropt [split [lindex $opttest 1] /] 77 | set antennacell [lindex $anchoropt 0] 78 | set antennapin [lindex $anchoropt 1] 79 | } 80 | 81 | # Get vddnet and gndnet from arguments, if given; otherwise 82 | # pick up from variables file, and failing that, give them 83 | # default names. 84 | 85 | if {$argc == 5} { 86 | set vddnet [lindex $argv 3] 87 | set gndnet [lindex $argv 4] 88 | } else { 89 | if [catch {set vddnet}] {set vddnet VDD} 90 | if [catch {set gndnet}] {set gndnet GND} 91 | } 92 | 93 | #------------------------------------------------------------- 94 | # Yosys first pass of the blif file 95 | # Look for all ".names x y" records and remember y as an 96 | # alias for x. 97 | #------------------------------------------------------------- 98 | 99 | while {[gets $bnet line] >= 0} { 100 | # set line [string map {\[ \< \] \>} $line] 101 | if [regexp {^.names[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*$} $line lmatch signame sigalias] { 102 | # Technically, should check if the next line is "1 1" but I don't think there are 103 | # any exceptions in yosys output. 104 | if [catch {set ${signame}(alias)}] { 105 | set ${signame}(alias) {} 106 | } 107 | lappend ${signame}(alias) $sigalias 108 | } 109 | } 110 | seek $bnet 0 111 | 112 | #------------------------------------------------------------- 113 | # Now post-process the blif file 114 | # The main thing to remember is that internal signals will be 115 | # outputs of flops, but external pin names have to be translated 116 | # to their internal names by looking at the OUTPUT section. 117 | #------------------------------------------------------------- 118 | 119 | set cycle 0 120 | while {[gets $bnet line] >= 0} { 121 | # set line [string map {\[ \< \] \> \.subckt \.gate} $line] 122 | set line [string map {\.subckt \.gate} $line] 123 | if [regexp {^.gate} $line lmatch] { 124 | break 125 | } elseif [regexp {^.names} $line lmatch] { 126 | break 127 | } elseif [regexp {^.latch} $line lmatch] { 128 | break 129 | } elseif [regexp {^.inputs} $line lmatch] { 130 | set inputs [lrange $line 1 end] 131 | } 132 | puts $onet $line 133 | } 134 | 135 | # Replace all .latch statements with .gate, with the appropriate gate type and pins, 136 | # and copy all .gate statements as-is. 137 | 138 | while {1} { 139 | 140 | # All lines starting with ".names" are converted into buffers. These should be 141 | # pruned. . . 142 | 143 | if [regexp {^.names} $line lmatch] { 144 | if {[regexp {\$true$} $line lmatch]} { 145 | set line [string map [subst {\\\$false $gndnet \\\$true $vddnet}] $line] 146 | if [regexp {^.names[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*$} $line lmatch sigin sigout] { 147 | puts $onet ".gate ${bufcell} ${bufpin_in}=${sigin} ${bufpin_out}=${sigout}" 148 | } 149 | gets $bnet line 150 | } 151 | } elseif [regexp {^.end} $line lmatch] { 152 | # Add antenna cells to anchor each input pin against antenna rule violations 153 | if $doanchors { 154 | foreach input $inputs { 155 | puts $onet ".gate ${antennacell} ${antennapin}=${input}" 156 | } 157 | } 158 | puts $onet $line 159 | break 160 | } else { 161 | set line [string map [subst {\\\$false $gndnet \\\$true $vddnet}] $line] 162 | puts $onet $line 163 | } 164 | 165 | if {[gets $bnet line] < 0} break 166 | # set line [string map {\[ \< \] \> \.subckt \.gate} $line] 167 | set line [string map {\.subckt \.gate} $line] 168 | } 169 | 170 | close $bnet 171 | close $onet 172 | -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project source compile makefile 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | LIBS = @LIBS@ 8 | LDFLAGS = @LDFLAGS@ 9 | INSTALL = @INSTALL@ 10 | 11 | prefix = @prefix@ 12 | exec_prefix = @exec_prefix@ 13 | 14 | DEFS = @DEFS@ -DQFLOW_VERSION=\"@VERSION@\" -DQFLOW_REVISION=\"@REVISION@\" 15 | 16 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 17 | 18 | QFLOW_GRAYWOLF_PATH = @QFLOW_GRAYWOLF_PATH@ 19 | QFLOW_REPLACE_PATH = @QFLOW_REPLACE_PATH@ 20 | QFLOW_NTUPLACE3_PATH = @QFLOW_NTUPLACE3_PATH@ 21 | QFLOW_NTUPLACE4_PATH = @QFLOW_NTUPLACE4_PATH@ 22 | QFLOW_QROUTER_PATH = @QFLOW_QROUTER_PATH@ 23 | QFLOW_MAGIC_PATH = @QFLOW_MAGIC_PATH@ 24 | QFLOW_NETGEN_PATH = @QFLOW_NETGEN_PATH@ 25 | QFLOW_YOSYS_PATH = @QFLOW_YOSYS_PATH@ 26 | QFLOW_OPENTIMER_PATH = @QFLOW_OPENTIMER_PATH@ 27 | QFLOW_OPENSTA_PATH = @QFLOW_OPENSTA_PATH@ 28 | 29 | HAVE_YOSYS = @HAVE_YOSYS@ 30 | HAVE_MAGIC = @HAVE_MAGIC@ 31 | HAVE_NETGEN = @HAVE_NETGEN@ 32 | HAVE_OPENTIMER = @HAVE_OPENTIMER@ 33 | HAVE_OPENSTA = @HAVE_OPENSTA@ 34 | HAVE_GRAYWOLF = @HAVE_GRAYWOLF@ 35 | HAVE_REPLACE = @HAVE_REPLACE@ 36 | HAVE_QROUTER = @HAVE_QROUTER@ 37 | 38 | OBJECTS = vlog2Spice.o vlog2Verilog.o vlog2Def.o vlog2Cel.o vlogFanout.o 39 | OBJECTS += DEF2Verilog.o addspacers.o 40 | OBJECTS += vesta.o spice2delay.o rc2dly.o 41 | OBJECTS += blif2BSpice.o blif2Verilog.o blifFanout.o 42 | HASHLIB = hash.o 43 | LIBERTYLIB = readliberty.o 44 | VERILOGLIB = readverilog.o 45 | LEFLIB = readlef.o 46 | DEFLIB = readdef.o 47 | SOURCES := $(patsubst %.o,%.c,$(OBJECTS)) 48 | TARGETS := $(patsubst %.o,%$(EXEEXT),$(OBJECTS)) 49 | 50 | BININSTALL = ${QFLOW_LIB_DIR}/bin 51 | INSTALL_BININSTALL = @DIST_DIR@/share/qflow/bin 52 | 53 | all: $(TARGETS) 54 | 55 | vlog2Spice$(EXEEXT): vlog2Spice.o $(HASHLIB) $(VERILOGLIB) 56 | $(CC) $(LDFLAGS) vlog2Spice.o $(HASHLIB) $(VERILOGLIB) -o $@ $(LIBS) 57 | 58 | vlog2Verilog$(EXEEXT): vlog2Verilog.o $(HASHLIB) $(LEFLIB) $(VERILOGLIB) 59 | $(CC) $(LDFLAGS) vlog2Verilog.o $(HASHLIB) $(VERILOGLIB) $(LEFLIB) \ 60 | -o $@ $(LIBS) 61 | 62 | vlog2Cel$(EXEEXT): vlog2Cel.o $(HASHLIB) $(LEFLIB) $(VERILOGLIB) 63 | $(CC) $(LDFLAGS) vlog2Cel.o $(HASHLIB) $(VERILOGLIB) $(LEFLIB) \ 64 | -o $@ $(LIBS) -lm 65 | 66 | vlog2Def$(EXEEXT): vlog2Def.o $(HASHLIB) $(LEFLIB) $(VERILOGLIB) 67 | $(CC) $(LDFLAGS) vlog2Def.o $(HASHLIB) $(LEFLIB) $(VERILOGLIB) -o $@ $(LIBS) -lm 68 | 69 | vlogFanout$(EXEEXT): vlogFanout.o $(HASHLIB) $(LIBERTYLIB) $(VERILOGLIB) 70 | $(CC) $(LDFLAGS) vlogFanout.o $(HASHLIB) $(VERILOGLIB) $(LIBERTYLIB) \ 71 | -DQFLOW_VERSION=\"VERSION\" -DQFLOW_REVISION=\"REVISION\" \ 72 | $(DEPENDS) -o $@ $(LIBS) -lm 73 | 74 | DEF2Verilog$(EXEEXT): DEF2Verilog.o $(HASHLIB) $(VERILOGLIB) $(DEFLIB) $(LEFLIB) 75 | $(CC) $(LDFLAGS) DEF2Verilog.o $(HASHLIB) $(VERILOGLIB) $(DEFLIB) $(LEFLIB) \ 76 | -DQFLOW_VERSION=\"VERSION\" -DQFLOW_REVISION=\"REVISION\" \ 77 | $(DEPENDS) -o $@ $(LIBS) -lm 78 | 79 | addspacers$(EXEEXT): addspacers.o $(HASHLIB) $(LEFLIB) $(DEFLIB) 80 | $(CC) $(LDFLAGS) addspacers.o $(HASHLIB) $(LEFLIB) $(DEFLIB) -o $@ $(LIBS) -lm 81 | 82 | blif2BSpice$(EXEEXT): blif2BSpice.o 83 | $(CC) $(LDFLAGS) blif2BSpice.o -o $@ $(LIBS) 84 | 85 | blif2Verilog$(EXEEXT): blif2Verilog.o 86 | $(CC) $(LDFLAGS) blif2Verilog.o -o $@ $(LIBS) 87 | 88 | blifFanout$(EXEEXT): blifFanout.o $(HASHLIB) $(LIBERTYLIB) 89 | $(CC) $(LDFLAGS) blifFanout.o $(HASHLIB) $(LIBERTYLIB) \ 90 | -DQFLOW_VERSION=\"VERSION\" -DQFLOW_REVISION=\"REVISION\" \ 91 | $(DEPENDS) -o $@ $(LIBS) -lm 92 | 93 | vesta$(EXEEXT): vesta.o $(HASHLIB) $(VERILOGLIB) 94 | $(CC) $(LDFLAGS) vesta.o $(HASHLIB) $(VERILOGLIB) -o $@ $(LIBS) 95 | 96 | spice2delay$(EXEEXT): spice2delay.o $(HASHLIB) $(LIBERTYLIB) 97 | $(CC) $(LDFLAGS) spice2delay.o $(HASHLIB) $(LIBERTYLIB) -o $@ $(LIBS) 98 | 99 | rc2dly$(EXEEXT): rc2dly.o $(LIBERTYLIB) $(HASHLIB) $(VERILOGLIB) 100 | $(CC) $(LDFLAGS) rc2dly.o $(LIBERTYLIB) $(HASHLIB) $(VERILOGLIB) -o $@ $(LIBS) 101 | 102 | install: $(TARGETS) 103 | @echo "Installing verilog, SPICE, etc. file format handlers" 104 | $(INSTALL) -d $(DESTDIR)${INSTALL_BININSTALL} 105 | @for target in $(TARGETS); do \ 106 | $(INSTALL) $$target $(DESTDIR)${INSTALL_BININSTALL} ;\ 107 | done 108 | @echo "Installing links to third-party synthesis flow tool executables" 109 | @if test "${HAVE_GRAYWOLF}" = "1"; then \ 110 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f graywolf; ln -s $(QFLOW_GRAYWOLF_PATH) graywolf) ;\ 111 | fi 112 | @if test "${HAVE_REPLACE}" = "1"; then \ 113 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f RePlAce; ln -s $(QFLOW_REPLACE_PATH) RePlAce) ;\ 114 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f ntuplace3; ln -s $(QFLOW_NTUPLACE3_PATH) ntuplace3) ;\ 115 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f ntuplace4h; ln -s $(QFLOW_NTUPLACE4_PATH) ntuplace4h) ;\ 116 | fi 117 | @if test "${HAVE_QROUTER}" = "1"; then \ 118 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f qrouter; ln -s $(QFLOW_QROUTER_PATH) qrouter) ;\ 119 | fi 120 | @if test "${HAVE_MAGIC}" = "1"; then \ 121 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f magic; ln -s $(QFLOW_MAGIC_PATH) magic) ;\ 122 | fi 123 | @if test "${HAVE_NETGEN}" = "1"; then \ 124 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f netgen; ln -s $(QFLOW_NETGEN_PATH) netgen); \ 125 | fi 126 | @if test "${HAVE_YOSYS}" = "1"; then \ 127 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f yosys; ln -s $(QFLOW_YOSYS_PATH) yosys); \ 128 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f yosys-abc; ln -s $(QFLOW_YOSYS_PATH)-abc yosys-abc); \ 129 | fi 130 | @if test "${HAVE_OPENTIMER}" = "1"; then \ 131 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f ot-shell; ln -s $(QFLOW_OPENTIMER_PATH) ot-shell); \ 132 | fi 133 | @if test "${HAVE_OPENSTA}" = "1"; then \ 134 | (cd $(DESTDIR)${INSTALL_BININSTALL}; $(RM) -f sta; ln -s $(QFLOW_OPENSTA_PATH) sta); \ 135 | fi 136 | 137 | uninstall: 138 | $(RM) -rf ${INSTALL_BININSTALL} 139 | 140 | clean: 141 | $(RM) -f $(OBJECTS) $(HASHLIB) $(LIBERTYLIB) $(LEFLIB) $(DEFLIB) $(VERILOGLIB) 142 | $(RM) -f $(TARGETS) 143 | 144 | veryclean: 145 | $(RM) -f $(OBJECTS) $(HASHLIB) $(LIBERTYLIB) $(LEFLIB) $(DEFLIB) $(VERILOGLIB) 146 | $(RM) -f $(TARGETS) 147 | 148 | distclean: 149 | $(RM) -f $(OBJECTS) $(HASHLIB) $(LIBERTYLIB) $(LEFLIB) $(DEFLIB) $(VERILOGLIB) 150 | $(RM) -f $(TARGETS) 151 | 152 | .c.o: 153 | $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) -c $< -o $@ 154 | -------------------------------------------------------------------------------- /scripts/checkdirs.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | # 3 | #------------------------------------------------------------------------- 4 | # checkdirs.sh 5 | #------------------------------------------------------------------------- 6 | # April 2013 7 | # Tim Edwards, Open Circuit Design 8 | #------------------------------------------------------------------------- 9 | # 10 | # This script searches for technology directories and project directories. 11 | # It sets variables associated with each directory for other scripts to 12 | # use. 13 | # 14 | # The directory hierarchy is expected to be set up as follows: 15 | # 16 | # ----> source/ 17 | # ----> synthesis/ 18 | # ----> layout/ 19 | # ----> tech/ (optional) 20 | # 21 | # "tech" is optional if the technology is in the qflow install location, 22 | # QFLOW_TECH_DIR/. If there is already a technology specified 23 | # in the qflow_vars.sh file, then pass it as the 2nd argument and the 24 | # checkdirs script will only check the other directories. Otherwise, the 25 | # 2nd argument should be an empty string, or may be omitted if the project 26 | # path is also omitted 27 | # 28 | # Optionally, techfiles may be in subdirectory without the 29 | # intervening "tech" directory. i.e., 30 | # 31 | # ----> 32 | # 33 | # Optionally, "tech" may point directly to the directory containing techfile 34 | # data, i.e., 35 | # 36 | # ----> tech/ 37 | # 38 | # If is not specified on the command line, then it is assumed 39 | # to be the current working directory. If any standard subdirectories 40 | # "source", "synthesis", or "layout" are not found, they will be set to 41 | # the project directory. The techfile directory must be found, or 42 | # synthesis cannot proceed. 43 | # 44 | # Source this file using "source" to add variables to the existing shell 45 | # environment. 46 | # 47 | #------------------------------------------------------------------------- 48 | 49 | # Environment variables override everything else: 50 | # QFLOW_TECH_DIR path to technology directory 51 | # QFLOW_TECH name of technology 52 | # QFLOW_PROJECT_ROOT path to project top level directory 53 | # 54 | # The second two are checked before calling this routine so 55 | # that there are known values for the two arguments passed 56 | # to it. 57 | 58 | if ($#argv != 2 && $#argv != 3) then 59 | echo "Usage: checkdirs.sh []" 60 | exit 1 61 | endif 62 | 63 | set techname=${argv[1]} 64 | 65 | if ($#argv >= 2) then 66 | set techdir=${argv[2]} 67 | else 68 | set techdir="" 69 | endif 70 | 71 | # Environment variable overrides the project root path in all cases 72 | # except when the project root path is specified on the command line 73 | # by -p. If the environment variable does not exist, the project 74 | # root directory is assumed to be the current working directory. 75 | 76 | if ($#argv == 3) then 77 | set projectpath=${argv[3]} 78 | else 79 | set projectpath=`pwd` 80 | endif 81 | 82 | #----------------------------------------------------------------- 83 | # For portability, convert the home directory to the tilde escape 84 | # Note that projectpath must be quoted every time to preserve the ~ 85 | #----------------------------------------------------------------- 86 | 87 | set projectpath="`echo $projectpath | sed -e 's,^${HOME},~,'`" 88 | 89 | #---------------------------------------------------- 90 | # Check for standard working directories 91 | #---------------------------------------------------- 92 | 93 | if ( -d ${projectpath}/source ) then 94 | set sourcedir="${projectpath}"/source 95 | else 96 | set sourcedir="${projectpath}" 97 | endif 98 | 99 | if ( -d ${projectpath}/synthesis ) then 100 | set synthdir="${projectpath}"/synthesis 101 | else 102 | set synthdir="${projectpath}" 103 | endif 104 | 105 | if ( -d ${projectpath}/layout ) then 106 | set layoutdir="${projectpath}"/layout 107 | else 108 | set layoutdir="${projectpath}" 109 | endif 110 | 111 | #---------------------------------------------------- 112 | # Set variables from install locations here, so we 113 | # don't have to do it in every script separately. 114 | # Track path to scripts and binaries used by qflow 115 | #---------------------------------------------------- 116 | 117 | set scriptdir=SUBST_SCRIPT_DIR 118 | set bindir=SUBST_BIN_DIR 119 | 120 | #---------------------------------------------------- 121 | # Check for the techfile (see comments at top) 122 | #---------------------------------------------------- 123 | 124 | # The environment variable overrides anything else 125 | set techtest=`printenv QFLOW_TECH_DIR` 126 | if ($techtest != "") then 127 | set techdir=$techtest 128 | endif 129 | 130 | # Check that the technology directory points to a valid path; 131 | # that is, that there is a file .sh in it. 132 | 133 | if ($techdir != "") then 134 | if ( !(-r ${techdir}/${techname}.sh )) then 135 | if ( -d ${techdir}/${techname} ) then 136 | set techdir=${techdir}/${techname} 137 | else 138 | set techdir="" 139 | endif 140 | endif 141 | endif 142 | 143 | if ($techdir != "") then 144 | # Technology directory has been validated, so return with no error 145 | exit 0 146 | endif 147 | 148 | if ( -d ${projectpath}/tech/${techname} ) then 149 | set techdir="${projectpath}"/tech/${techname} 150 | else 151 | if ( -d ${projectpath}/${techname} ) then 152 | set techdir="${projectpath}"/${techname} 153 | else 154 | if ( -d ${projectpath}/tech && -r ${projectpath}/tech/${techname}.sh ) then 155 | set techdir="${projectpath}"/tech 156 | else 157 | if ( -d SUBST_TECH_DIR/${techname} ) then 158 | set techdir=SUBST_TECH_DIR/${techname} 159 | else 160 | echo "Don't know about technology '${techname}'" 161 | echo "Check SUBST_TECH_DIR/ for known technologies" 162 | exit 1 163 | endif 164 | endif 165 | endif 166 | endif 167 | 168 | # Validate the technology directory 169 | if ($techdir != "") then 170 | if ( !(-r ${techdir}/${techname}.sh )) then 171 | if ( -d ${techdir}/${techname} ) then 172 | set techdir=${techdir}/${techname} 173 | if ( !(-r ${techdir}/${techname}.sh )) then 174 | set techdir="" 175 | endif 176 | else 177 | set techdir="" 178 | endif 179 | endif 180 | endif 181 | 182 | if ($techdir != "") then 183 | # Technology directory has been validated, so return with no error 184 | exit 0 185 | endif 186 | 187 | # Technology directory was not found, so fail. 188 | echo "Technology directory not validated" 189 | exit 1 190 | #---------------------------------------------------- 191 | -------------------------------------------------------------------------------- /scripts/getpowerground.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # getpowerground.tcl --- 4 | # 5 | # Read LEF file up to the first macro with a PIN record having 6 | # USE POWER and one having USE GROUND. Return the pin names. 7 | # If the library has tap cells, then there may be multiple 8 | # power and ground pins, and all names should be returned. For 9 | # 4-net power/ground, it is the responsibility of the calling 10 | # script to use the power/ground names in the setup file to 11 | # disambiguate between the actual power buses and the tap 12 | # connections. 13 | # 14 | #--------------------------------------------------------------------------- 15 | namespace path {::tcl::mathop ::tcl::mathfunc} 16 | 17 | if {$argc < 1} { 18 | puts stdout "Usage: getpowerground " 19 | exit 0 20 | } 21 | 22 | puts stdout "Running getpowerground.tcl" 23 | 24 | set lefname [lindex $argv 0] 25 | 26 | set vddnet {} 27 | set gndnet {} 28 | 29 | #----------------------------------------------------------------- 30 | # Open lef file for reading 31 | #----------------------------------------------------------------- 32 | 33 | if [catch {open $lefname r} flef] { 34 | puts stderr "Error: can't open file $lefname for input" 35 | return 36 | } 37 | 38 | #---------------------------------------------------------------- 39 | # Read through a LEF file section that we don't care about. 40 | #---------------------------------------------------------------- 41 | 42 | proc skip_section {leffile sectionname} { 43 | while {[gets $leffile line] >= 0} { 44 | if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] { 45 | if {"$sectiontest" != "$sectionname"} { 46 | puts -nonewline stderr "Unexpected END statement $line " 47 | puts stderr "while reading section $sectionname" 48 | } 49 | break 50 | } 51 | } 52 | } 53 | 54 | #---------------------------------------------------------------- 55 | # Parse the pin contents of the LEF file macro 56 | #---------------------------------------------------------------- 57 | 58 | proc parse_pin {leffile pinname} { 59 | global vddnet 60 | global gndnet 61 | 62 | set portuse "" 63 | while {[gets $leffile line] >= 0} { 64 | if [regexp {[ \t]*USE[ \t]+([^ \t]+)[ \t]*;} $line lmatch portuse] { 65 | set portuse [string toupper $portuse] 66 | if {$portuse == "GROUND"} { 67 | if {[lsearch $gndnet $pinname] < 0} { 68 | lappend gndnet $pinname 69 | } 70 | } elseif {$portuse == "POWER"} { 71 | if {[lsearch $vddnet $pinname] < 0} { 72 | lappend vddnet $pinname 73 | } 74 | } 75 | } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch pintest] { 76 | if {"$pintest" == "$pinname"} { 77 | break 78 | } else { 79 | puts stdout "Unexpected END statement $line while parsing pin $pinname" 80 | } 81 | } 82 | } 83 | } 84 | 85 | #---------------------------------------------------------------- 86 | # Parse the macro contents of the LEF file and retain the information 87 | # about pin use. 88 | #---------------------------------------------------------------- 89 | 90 | proc parse_macro {leffile macroname} { 91 | global vddnet 92 | global gndnet 93 | 94 | while {[gets $leffile line] >= 0} { 95 | if [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] { 96 | parse_pin $leffile $pinname 97 | } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] { 98 | if {"$macrotest" == "$macroname"} { 99 | break 100 | } else { 101 | puts stderr "Unexpected END statement $line while reading macro $macroname" 102 | } 103 | } 104 | } 105 | } 106 | 107 | #----------------------------------------------------------------- 108 | # Read the lef macro file and get the fill cells and their widths 109 | #----------------------------------------------------------------- 110 | 111 | puts stdout "Reading macros from LEF file." 112 | flush stdout 113 | 114 | while {[gets $flef line] >= 0} { 115 | if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] { 116 | # Parse the "macro" statement 117 | parse_macro $flef $macroname 118 | # Probably the power and ground nets will be set after the first 119 | # macro is read. Watch for unbalanced number of vdd net names and 120 | # gnd net names caused by having a single-sided tap cell as the 121 | # first macro. 122 | if {([llength $vddnet] > 1) && ([llength $gndnet] > 1)} { 123 | break 124 | } elseif {([llength $vddnet] == 1) && ([llength $gndnet] == 1)} { 125 | break 126 | } 127 | } elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] { 128 | skip_section $flef $layername 129 | } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] { 130 | skip_section $flef $vianame 131 | } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] { 132 | skip_section $flef $viarulename 133 | } elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] { 134 | skip_section $flef $sitename 135 | } elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] { 136 | skip_section $flef SPACING 137 | } elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] { 138 | skip_section $flef PROPERTYDEFINITIONS 139 | } elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] { 140 | skip_section $flef UNITS 141 | } elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] { 142 | break 143 | } elseif [regexp {^[ \t]*#} $line lmatch] { 144 | # Comment line, ignore. 145 | } elseif ![regexp {^[ \t]*$} $line lmatch] { 146 | # Other things we don't care about 147 | set matches 0 148 | if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] { 149 | incr matches 150 | } elseif [regexp {[ \t]*VERSION} $line lmatch] { 151 | incr matches 152 | } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] { 153 | incr matches 154 | } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] { 155 | incr matches 156 | } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] { 157 | incr matches 158 | } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] { 159 | incr matches 160 | } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] { 161 | incr matches 162 | } 163 | } 164 | } 165 | 166 | close $flef 167 | 168 | # Use a comma to separate multiple power and ground names 169 | puts stdout "vddnet=[join $vddnet ","]" 170 | puts stdout "gndnet=[join $gndnet ","]" 171 | puts stdout "Done with getpowerground.tcl" 172 | -------------------------------------------------------------------------------- /src/lef.h: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------*/ 2 | /* lef.h -- */ 3 | /*--------------------------------------------------------------*/ 4 | 5 | #ifndef _LEF_H 6 | #define _LEF_H 7 | 8 | #ifndef FALSE 9 | #define FALSE 0 10 | #endif 11 | #ifndef TRUE 12 | #define TRUE 1 13 | #endif 14 | 15 | #ifndef _SYS_TYPES_H 16 | #ifndef u_char 17 | typedef unsigned char u_char; 18 | #endif 19 | #ifndef u_short 20 | typedef unsigned short u_short; 21 | #endif 22 | #ifndef u_int 23 | typedef unsigned int u_int; 24 | #endif 25 | #ifndef u_long 26 | typedef unsigned long u_long; 27 | #endif 28 | #endif /* _SYS_TYPES_H */ 29 | 30 | /* Compare functions aren't defined in the Mac's standard library */ 31 | #if defined(__APPLE__) 32 | typedef int (*__compar_fn_t)(const void*, const void*); 33 | #endif 34 | 35 | /* Maximum number of route layers */ 36 | #define MAX_LAYERS 12 37 | 38 | /* Maximum number of all defined layers. Since masterslice and */ 39 | /* overlap types are ignored, this just includes all the cuts. */ 40 | #define MAX_TYPES (MAX_LAYERS * 2 - 1) 41 | 42 | /* Cell name (and other names) max length */ 43 | #define MAX_NAME_LEN 1024 44 | 45 | /* Max reasonable line length */ 46 | #define MAX_LINE_LEN 2048 47 | 48 | // define possible gate orientations 49 | // Basic definitions for flipping in X and Y 50 | #define MNONE 0x00 51 | #define MX 0x01 52 | #define MY 0x02 53 | 54 | // Complete definition from value in DEF file 55 | #define RN 0x04 56 | #define RS 0x08 57 | #define RE 0x10 58 | #define RW 0x20 59 | #define RF 0x40 60 | 61 | // linked list structure for holding a list of char * strings 62 | 63 | typedef struct linkedstring_ *LinkedStringPtr; 64 | 65 | typedef struct linkedstring_ { 66 | char *name; 67 | LinkedStringPtr next; 68 | } LinkedString; 69 | 70 | // structure holding input and output scalefactors 71 | 72 | typedef struct scalerec_ { 73 | int iscale; 74 | int mscale; 75 | double oscale; 76 | } ScaleRec; 77 | 78 | // Linked string list 79 | 80 | typedef struct string_ *STRING; 81 | 82 | struct string_ { 83 | STRING next; 84 | char *name; 85 | }; 86 | 87 | /* DSEG is used for gate node and obstruction positions. */ 88 | 89 | typedef struct dseg_ *DSEG; 90 | 91 | struct dseg_ { 92 | DSEG next; 93 | int layer; 94 | double x1, y1, x2, y2; 95 | }; 96 | 97 | /* POINT is an integer point in three dimensions (layer giving the */ 98 | /* vertical dimension). */ 99 | 100 | typedef struct point_ *POINT; 101 | 102 | struct point_ { 103 | POINT next; 104 | int layer; 105 | int x1, y1; 106 | }; 107 | 108 | /* DPOINT is a point location with coordinates given *both* as an */ 109 | /* integer (for the grid-based routing) and as a physical dimension */ 110 | /* (microns). */ 111 | 112 | typedef struct dpoint_ *DPOINT; 113 | 114 | struct dpoint_ { 115 | DPOINT next; 116 | int layer; 117 | double x, y; 118 | int gridx, gridy; 119 | }; 120 | 121 | /* BUS is used for keep information about pins that are array components */ 122 | 123 | typedef struct bus_ *BUS; 124 | 125 | struct bus_ { 126 | BUS next; 127 | char *busname; 128 | int low; 129 | int high; 130 | }; 131 | 132 | typedef struct node_ *NODE; 133 | 134 | struct node_ { 135 | NODE next; 136 | int nodenum; // node ordering within its net 137 | DPOINT taps; // point position for node taps 138 | DPOINT extend; // point position within halo of the tap 139 | char *netname; // name of net this node belongs to 140 | u_char numtaps; // number of actual reachable taps 141 | int netnum; // number of net this node belongs to 142 | int numnodes; // number of nodes on this net 143 | int branchx; // position of the node branch in x 144 | int branchy; // position of the node branch in y 145 | }; 146 | 147 | // these are instances of gates in the netlist. The description of a 148 | // given gate (the macro) is held in GateInfo. The same structure is 149 | // used for both the macro and the instance records. 150 | 151 | typedef struct gate_ *GATE; 152 | 153 | struct gate_ { 154 | GATE next; 155 | GATE last; // For double-linked list 156 | char *gatename; // Name of instance 157 | GATE gatetype; // Pointer to macro record 158 | u_char gateclass; // LEF class of gate (CORE, PAD, etc.) 159 | u_char gatesubclass; // LEF sub-class of gate (SPACER, TIELOW, etc.) 160 | int nodes; // number of nodes on this gate 161 | char **node; // names of the pins on this gate 162 | int *netnum; // net number connected to each pin 163 | NODE *noderec; // node record for each pin 164 | float *area; // gate area for each pin 165 | u_char *direction; // port direction (input, output, etc.) 166 | u_char *use; // pin use (power, ground, etc.) 167 | DSEG *taps; // list of gate node locations and layers 168 | DSEG obs; // list of obstructions in gate 169 | BUS bus; // linked list of buses in the pin list 170 | double width, height; 171 | double placedX; 172 | double placedY; 173 | int orient; 174 | u_char nomirror; // TRUE if macro cannot be right-left mirrored 175 | void *clientdata; // This space for rent 176 | }; 177 | 178 | // Define record holding information pointing to a gate and the 179 | // index into a specific node of that gate. 180 | 181 | typedef struct gatenode_ *GATENODE; 182 | 183 | struct gatenode_ { 184 | GATE gate; 185 | int idx; 186 | }; 187 | 188 | // Structure for a network 189 | 190 | typedef struct net_ *NET; 191 | 192 | struct net_ { 193 | int netnum; // a unique number for this net 194 | char *netname; 195 | NODE netnodes; // list of nodes connected to the net 196 | int numnodes; // number of nodes connected to the net 197 | char Flags; // See flag field definitions, below 198 | }; 199 | 200 | // Flag definitions for nets 201 | 202 | #define NET_SPECIAL 1 // Indicates a net read from SPECIALNETS 203 | 204 | // List of nets 205 | 206 | typedef struct netlist_ *NETLIST; 207 | 208 | struct netlist_ { 209 | NETLIST next; 210 | NET net; 211 | }; 212 | 213 | // Structure for a row definition 214 | 215 | typedef struct row_ *ROW; 216 | 217 | struct row_ { 218 | char *rowname; 219 | char *sitename; 220 | int x; 221 | int y; 222 | int orient; 223 | int xnum; 224 | int ynum; 225 | int xstep; 226 | int ystep; 227 | }; 228 | 229 | /* external references to global variables */ 230 | 231 | extern GATE GateInfo; // standard cell macro information 232 | extern GATE PinMacro; // macro definition for a pin 233 | extern GATE Nlgates; 234 | extern NET *Nlnets; 235 | extern int Numnets; 236 | extern u_char Verbose; 237 | 238 | /* Function prototypes */ 239 | 240 | #endif /* _LEF_H */ 241 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5 (mit/util/scripts/install.sh). 5 | # 6 | # Copyright 1991 by the Massachusetts Institute of Technology 7 | # 8 | # Permission to use, copy, modify, distribute, and sell this software and its 9 | # documentation for any purpose is hereby granted without fee, provided that 10 | # the above copyright notice appear in all copies and that both that 11 | # copyright notice and this permission notice appear in supporting 12 | # documentation, and that the name of M.I.T. not be used in advertising or 13 | # publicity pertaining to distribution of the software without specific, 14 | # written prior permission. M.I.T. makes no representations about the 15 | # suitability of this software for any purpose. It is provided "as is" 16 | # without express or implied warranty. 17 | # 18 | # Calling this script install-sh is preferred over install.sh, to prevent 19 | # `make' implicit rules from creating a file called install from it 20 | # when there is no Makefile. 21 | # 22 | # This script is compatible with the BSD install script, but was written 23 | # from scratch. It can only install one file at a time, a restriction 24 | # shared with many OS's install programs. 25 | 26 | 27 | # set DOITPROG to echo to test this script 28 | 29 | # Don't use :- since 4.3BSD and earlier shells don't like it. 30 | doit="${DOITPROG-}" 31 | 32 | 33 | # put in absolute paths if you don't have them in your path; or use env. vars. 34 | 35 | mvprog="${MVPROG-mv}" 36 | cpprog="${CPPROG-cp}" 37 | chmodprog="${CHMODPROG-chmod}" 38 | chownprog="${CHOWNPROG-chown}" 39 | chgrpprog="${CHGRPPROG-chgrp}" 40 | stripprog="${STRIPPROG-strip}" 41 | rmprog="${RMPROG-rm}" 42 | mkdirprog="${MKDIRPROG-mkdir}" 43 | 44 | transformbasename="" 45 | transform_arg="" 46 | instcmd="$mvprog" 47 | chmodcmd="$chmodprog 0755" 48 | chowncmd="" 49 | chgrpcmd="" 50 | stripcmd="" 51 | rmcmd="$rmprog -f" 52 | mvcmd="$mvprog" 53 | src="" 54 | dst="" 55 | dir_arg="" 56 | 57 | while [ x"$1" != x ]; do 58 | case $1 in 59 | -c) instcmd="$cpprog" 60 | shift 61 | continue;; 62 | 63 | -d) dir_arg=true 64 | shift 65 | continue;; 66 | 67 | -m) chmodcmd="$chmodprog $2" 68 | shift 69 | shift 70 | continue;; 71 | 72 | -o) chowncmd="$chownprog $2" 73 | shift 74 | shift 75 | continue;; 76 | 77 | -g) chgrpcmd="$chgrpprog $2" 78 | shift 79 | shift 80 | continue;; 81 | 82 | -s) stripcmd="$stripprog" 83 | shift 84 | continue;; 85 | 86 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 87 | shift 88 | continue;; 89 | 90 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 91 | shift 92 | continue;; 93 | 94 | *) if [ x"$src" = x ] 95 | then 96 | src=$1 97 | else 98 | # this colon is to work around a 386BSD /bin/sh bug 99 | : 100 | dst=$1 101 | fi 102 | shift 103 | continue;; 104 | esac 105 | done 106 | 107 | if [ x"$src" = x ] 108 | then 109 | echo "install: no input file specified" 110 | exit 1 111 | else 112 | true 113 | fi 114 | 115 | if [ x"$dir_arg" != x ]; then 116 | dst=$src 117 | src="" 118 | 119 | if [ -d $dst ]; then 120 | instcmd=: 121 | chmodcmd="" 122 | else 123 | instcmd=mkdir 124 | fi 125 | else 126 | 127 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 128 | # might cause directories to be created, which would be especially bad 129 | # if $src (and thus $dsttmp) contains '*'. 130 | 131 | if [ -f $src -o -d $src ] 132 | then 133 | true 134 | else 135 | echo "install: $src does not exist" 136 | exit 1 137 | fi 138 | 139 | if [ x"$dst" = x ] 140 | then 141 | echo "install: no destination specified" 142 | exit 1 143 | else 144 | true 145 | fi 146 | 147 | # If destination is a directory, append the input filename; if your system 148 | # does not like double slashes in filenames, you may need to add some logic 149 | 150 | if [ -d $dst ] 151 | then 152 | dst="$dst"/`basename $src` 153 | else 154 | true 155 | fi 156 | fi 157 | 158 | ## this sed command emulates the dirname command 159 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 160 | 161 | # Make sure that the destination directory exists. 162 | # this part is taken from Noah Friedman's mkinstalldirs script 163 | 164 | # Skip lots of stat calls in the usual case. 165 | if [ ! -d "$dstdir" ]; then 166 | defaultIFS=' 167 | ' 168 | IFS="${IFS-${defaultIFS}}" 169 | 170 | oIFS="${IFS}" 171 | # Some sh's can't handle IFS=/ for some reason. 172 | IFS='%' 173 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 174 | IFS="${oIFS}" 175 | 176 | pathcomp='' 177 | 178 | while [ $# -ne 0 ] ; do 179 | pathcomp="${pathcomp}${1}" 180 | shift 181 | 182 | if [ ! -d "${pathcomp}" ] ; 183 | then 184 | $mkdirprog "${pathcomp}" 185 | else 186 | true 187 | fi 188 | 189 | pathcomp="${pathcomp}/" 190 | done 191 | fi 192 | 193 | if [ x"$dir_arg" != x ] 194 | then 195 | $doit $instcmd $dst && 196 | 197 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && 198 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && 199 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && 200 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi 201 | else 202 | 203 | # If we're going to rename the final executable, determine the name now. 204 | 205 | if [ x"$transformarg" = x ] 206 | then 207 | dstfile=`basename $dst` 208 | else 209 | dstfile=`basename $dst $transformbasename | 210 | sed $transformarg`$transformbasename 211 | fi 212 | 213 | # don't allow the sed command to completely eliminate the filename 214 | 215 | if [ x"$dstfile" = x ] 216 | then 217 | dstfile=`basename $dst` 218 | else 219 | true 220 | fi 221 | 222 | # Make a temp file name in the proper directory. 223 | 224 | dsttmp=$dstdir/#inst.$$# 225 | 226 | # Move or copy the file name to the temp name 227 | 228 | $doit $instcmd $src $dsttmp && 229 | 230 | trap "rm -f ${dsttmp}" 0 && 231 | 232 | # and set any options; do chmod last to preserve setuid bits 233 | 234 | # If any of these fail, we abort the whole thing. If we want to 235 | # ignore errors from any of these, just make sure not to ignore 236 | # errors from the above "$doit $instcmd $src $dsttmp" command. 237 | 238 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && 239 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && 240 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && 241 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && 242 | 243 | # Now rename the file to the real destination. 244 | 245 | $doit $rmcmd -f $dstdir/$dstfile && 246 | $doit $mvcmd $dsttmp $dstdir/$dstfile 247 | 248 | fi && 249 | 250 | 251 | exit 0 252 | -------------------------------------------------------------------------------- /scripts/magic_gds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | #---------------------------------------------------------- 3 | # GDSII output generating script using magic 4 | #---------------------------------------------------------- 5 | # Tim Edwards, 4/23/18, for Open Circuit Design 6 | #---------------------------------------------------------- 7 | 8 | # Split out options from the main arguments 9 | set argline=(`getopt "" $argv[1-]`) 10 | 11 | set options=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $1}'` 12 | set cmdargs=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $2}'` 13 | set argc=`echo $cmdargs | wc -w` 14 | 15 | if ($argc >= 2) then 16 | set argv1=`echo $cmdargs | cut -d' ' -f1` 17 | set argv2=`echo $cmdargs | cut -d' ' -f2` 18 | else 19 | echo "Usage: magic_gds.sh [options] " 20 | echo " where" 21 | echo " is the name of the project directory containing" 22 | echo " a file called qflow_vars.sh." 23 | echo " is the root name of the verilog file" 24 | exit 1 25 | endif 26 | 27 | set projectpath=$argv1 28 | set sourcename=$argv2 29 | set rootname=${sourcename:h} 30 | 31 | # This script is called with the first argument , which should 32 | # have file "qflow_vars.sh". Get all of our standard variable definitions 33 | # from the qflow_vars.sh file. 34 | 35 | if (! -f ${projectpath}/qflow_vars.sh ) then 36 | echo "Error: Cannot find file qflow_vars.sh in path ${projectpath}" 37 | exit 1 38 | endif 39 | 40 | source ${projectpath}/qflow_vars.sh 41 | source ${techdir}/${techname}.sh 42 | cd ${projectpath} 43 | if (-f project_vars.sh) then 44 | source project_vars.sh 45 | endif 46 | 47 | if (! ${?gdsii_options} ) then 48 | set gdsii_options = ${options} 49 | endif 50 | 51 | set gengdsfile="${layoutdir}/generate_gds_${rootname}.tcl" 52 | 53 | if (!($?logdir)) then 54 | set logdir=${projectpath}/log 55 | endif 56 | mkdir -p ${logdir} 57 | set lastlog=${logdir}/drc.log 58 | set synthlog=${logdir}/gdsii.log 59 | rm -f ${synthlog} >& /dev/null 60 | touch ${synthlog} 61 | set date=`date` 62 | echo "Qflow gdsii logfile created on $date" > ${synthlog} 63 | 64 | # Check if last line of drc log file says "error condition" 65 | if ( ! -f ${lastlog} ) then 66 | set lastlog=${logdir}/lvs.log 67 | endif 68 | if ( ! -f ${lastlog} ) then 69 | echo "Warning: No DRC or LVS logfiles found." 70 | else 71 | set errcond = `tail -1 ${lastlog} | grep "error condition" | wc -l` 72 | if ( ${errcond} == 1 ) then 73 | echo "Synthesis flow stopped on error condition. GDSII generation" 74 | echo "will not proceed until error condition is cleared." 75 | exit 1 76 | endif 77 | endif 78 | 79 | # Does variable "gdsfile" exist? 80 | 81 | if (! ${?gdsfile} || ( ${?gdsfile} && ( ${gdsfile} == "" ) ) ) then 82 | echo "GDS generation failure: No gdsfile variable set in technology setup script." \ 83 | |& tee -a ${synthlog} 84 | echo "Premature exit." |& tee -a ${synthlog} 85 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 86 | exit 1 87 | endif 88 | 89 | # Prepend techdir to each gdsfile unless gdsfile begins with "/" 90 | set gdspath="" 91 | foreach f (${gdsfile}) 92 | set abspath=`echo ${f} | cut -c1` 93 | if ( "${abspath}" == "/" ) then 94 | set p=${gdsfile} 95 | else 96 | set p=${techdir}/${gdsfile} 97 | endif 98 | set gdspath="${gdspath} $p" 99 | end 100 | 101 | #---------------------------------------------------------- 102 | # Done with initialization 103 | #---------------------------------------------------------- 104 | 105 | cd ${layoutdir} 106 | 107 | #------------------------------------------------------------------ 108 | # Determine the version number and availability of scripting 109 | #------------------------------------------------------------------ 110 | 111 | set version=`${bindir}/magic --version` 112 | set major=`echo $version | cut -d. -f1` 113 | set minor=`echo $version | cut -d. -f2` 114 | set subv=`echo $version | cut -d. -f3` 115 | 116 | #------------------------------------------------------------------ 117 | # Generate script for input to magic. 118 | #------------------------------------------------------------------ 119 | 120 | if ( !(-r $techfile)) then 121 | if (`echo $techfile | cut -c1` != "/") then 122 | set techfile=${techdir}/${techfile} 123 | endif 124 | endif 125 | if (-r $techfile) then 126 | cat >> ${gengdsfile} << EOF 127 | tech load $techfile -noprompt 128 | EOF 129 | else 130 | touch ${gengdsfile} 131 | endif 132 | 133 | 134 | cat >> ${gengdsfile} << EOF 135 | drc off 136 | box 0 0 0 0 137 | gds readonly true 138 | gds rescale false 139 | EOF 140 | 141 | # Usually "gdsfile" is set to one GDS file for the standard cell set 142 | # but it can be a space-separated list of GDS files to read. This 143 | # is set by reading the .sh file. 144 | 145 | foreach gfile ( ${gdspath} ) 146 | cat >> ${gengdsfile} << EOF 147 | gds read $gfile 148 | EOF 149 | end 150 | 151 | # NOTE: "*hier write disable" and "*array write disable" prevent 152 | # magic from doing an exhaustive search on GDS layer interactions 153 | # between standard cells. This is disabled on the assumption that 154 | # the standard cells are properly designed and do not generate DRC 155 | # spacing errors when abutted. The standard cells will be abstract 156 | # views, anyway, so only a few layers like metal1 are represented. 157 | 158 | cat >> ${gengdsfile} << EOF 159 | load $rootname 160 | select top cell 161 | expand 162 | cif *hier write disable 163 | cif *array write disable 164 | gds write $rootname 165 | quit 166 | EOF 167 | 168 | #------------------------------------------------------------------ 169 | # Run magic in batch mode. 170 | #------------------------------------------------------------------ 171 | 172 | echo "Running magic $version" 173 | echo "magic -dnull -noconsole ${gdsii_options} ${gengdsfile}" |& tee -a ${synthlog} 174 | ${bindir}/magic -dnull -noconsole ${gdsii_options} ${gengdsfile} |& tee -a ${synthlog} 175 | 176 | set errcond = $status 177 | if ( ${errcond} != 0 ) then 178 | echo "magic failed with exit status ${errcond}" |& tee -a ${synthlog} 179 | echo "Premature exit." |& tee -a ${synthlog} 180 | echo "Synthesis flow stopped on error condition." >>& ${synthlog} 181 | exit 1 182 | endif 183 | 184 | #--------------------------------------------------------------------- 185 | # Spot check: Did magic produce file ${rootname}.gds? 186 | #--------------------------------------------------------------------- 187 | 188 | if ( ! -f ${rootname}.gds || ( -M ${rootname}.gds < -M ${rootname}.def )) then 189 | echo "magic failure: No file ${rootname}.gds." |& tee -a ${synthlog} 190 | echo "Premature exit." |& tee -a ${synthlog} 191 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 192 | exit 1 193 | endif 194 | 195 | #------------------------------------------------------------ 196 | # Done! 197 | #------------------------------------------------------------ 198 | 199 | set endtime = `date` 200 | echo "GDS generating script ended on $endtime" >> $synthlog 201 | 202 | exit 0 203 | -------------------------------------------------------------------------------- /scripts/magic_drc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | #---------------------------------------------------------- 3 | # DRC error checking script using magic 4 | #---------------------------------------------------------- 5 | # Tim Edwards, 8/20/18, for Open Circuit Design 6 | #---------------------------------------------------------- 7 | 8 | # Split out options from the main arguments 9 | set argline=(`getopt "" $argv[1-]`) 10 | 11 | set options=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $1}'` 12 | set cmdargs=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $2}'` 13 | set argc=`echo $cmdargs | wc -w` 14 | 15 | if ($argc >= 2) then 16 | set argv1=`echo $cmdargs | cut -d' ' -f1` 17 | set argv2=`echo $cmdargs | cut -d' ' -f2` 18 | else 19 | echo "Usage: magic_drc.sh [options] " 20 | echo " where" 21 | echo " is the name of the project directory containing" 22 | echo " a file called qflow_vars.sh." 23 | echo " is the root name of the verilog file" 24 | exit 1 25 | endif 26 | 27 | set projectpath=$argv1 28 | set sourcename=$argv2 29 | set rootname=${sourcename:h} 30 | 31 | # This script is called with the first argument , which should 32 | # have file "qflow_vars.sh". Get all of our standard variable definitions 33 | # from the qflow_vars.sh file. 34 | 35 | if (! -f ${projectpath}/qflow_vars.sh ) then 36 | echo "Error: Cannot find file qflow_vars.sh in path ${projectpath}" 37 | exit 1 38 | endif 39 | 40 | source ${projectpath}/qflow_vars.sh 41 | source ${techdir}/${techname}.sh 42 | cd ${projectpath} 43 | if (-f project_vars.sh) then 44 | source project_vars.sh 45 | endif 46 | 47 | if (! ${?drc_options} ) then 48 | set drc_options = ${options} 49 | endif 50 | 51 | if (! ${?drc_gdsview} ) then 52 | set drc_gdsview = "" 53 | endif 54 | 55 | set rundrcfile="${layoutdir}/run_drc_${rootname}.tcl" 56 | 57 | if (!($?logdir)) then 58 | set logdir=${projectpath}/log 59 | endif 60 | mkdir -p ${logdir} 61 | set lastlog=${logdir}/lvs.log 62 | set synthlog=${logdir}/drc.log 63 | rm -f ${synthlog} >& /dev/null 64 | rm -f ${logdir}/lvs.log >& /dev/null 65 | rm -f ${logdir}/gdsii.log >& /dev/null 66 | touch ${synthlog} 67 | set date=`date` 68 | echo "Qflow DRC logfile created on $date" > ${synthlog} 69 | 70 | # Check if last line of drc log file says "error condition" 71 | if ( ! -f ${lastlog} ) then 72 | set lastlog=${logdir}/post_sta.log 73 | endif 74 | if ( ! -f ${lastlog} ) then 75 | echo "Warning: No LVS or post-route STA logfiles found." 76 | else 77 | set errcond = `tail -1 ${lastlog} | grep "error condition" | wc -l` 78 | if ( ${errcond} == 1 ) then 79 | echo "Synthesis flow stopped on error condition. DRC check " 80 | echo "will not proceed until error condition is cleared." 81 | exit 1 82 | endif 83 | endif 84 | 85 | # Does variable "gdsfile" exist? If not, then use the LEF views for 86 | # DRC checks. 87 | 88 | set use_gds=1 89 | if (! ${?gdsfile} || ( ${?gdsfile} && ( ${gdsfile} == "" ) ) ) then 90 | set use_gds=0 91 | endif 92 | 93 | # Prepend techdir to each leffile unless leffile begins with "/" 94 | set lefpath="" 95 | foreach f (${leffile}) 96 | set abspath=`echo ${f} | cut -c1` 97 | if ( "${abspath}" == "/" ) then 98 | set p=${leffile} 99 | else 100 | set p=${techdir}/${leffile} 101 | endif 102 | set lefpath="${lefpath} $p" 103 | end 104 | 105 | # Ditto for gdsfile 106 | set gdspath="" 107 | foreach f (${gdsfile}) 108 | set abspath=`echo ${f} | cut -c1` 109 | if ( "${abspath}" == "/" ) then 110 | set p=${gdsfile} 111 | else 112 | set p=${techdir}/${gdsfile} 113 | endif 114 | set gdspath="${gdspath} $p" 115 | end 116 | 117 | #---------------------------------------------------------- 118 | # Done with initialization 119 | #---------------------------------------------------------- 120 | 121 | cd ${layoutdir} 122 | 123 | #------------------------------------------------------------------ 124 | # Determine the version number and availability of scripting 125 | #------------------------------------------------------------------ 126 | 127 | set version=`${bindir}/magic --version` 128 | set major=`echo $version | cut -d. -f1` 129 | set minor=`echo $version | cut -d. -f2` 130 | set subv=`echo $version | cut -d. -f3` 131 | 132 | #------------------------------------------------------------------ 133 | # Generate script for input to magic. 134 | #------------------------------------------------------------------ 135 | 136 | # Usually "gdsfile" is set to one GDS file for the standard cell set 137 | # but it can be a space-separated list of GDS files to read. This 138 | # is set by reading the .sh file. If no gdsfile variable exists, or 139 | # is blank, then GDS generation cannot proceed. 140 | 141 | rm -f ${rundrcfile} 142 | touch ${rundrcfile} 143 | 144 | if (! ($?drc_gdsview)) then 145 | set drc_gdsview=0 146 | endif 147 | 148 | if ( !(-r $techfile)) then 149 | if (`echo $techfile | cut -c1` != "/") then 150 | set techfile=${techdir}/${techfile} 151 | endif 152 | endif 153 | if (-r $techfile) then 154 | cat >> ${rundrcfile} << EOF 155 | tech load $techfile -noprompt 156 | EOF 157 | endif 158 | 159 | if ( $drc_gdsview == 1 ) then 160 | cat >> ${rundrcfile} << EOF 161 | gds readonly true 162 | gds rescale false 163 | EOF 164 | foreach gfile ( ${gdspath} ) 165 | cat >> ${rundrcfile} << EOF 166 | gds read $gfile 167 | EOF 168 | end 169 | else 170 | foreach lfile ( ${lefpath} ) 171 | cat >> ${rundrcfile} << EOF 172 | lef read $lfile 173 | EOF 174 | end 175 | endif 176 | 177 | cat >> ${rundrcfile} << EOF 178 | load $rootname 179 | drc on 180 | select top cell 181 | expand 182 | drc check 183 | drc catchup 184 | set dcount [drc list count total] 185 | puts stdout "drc = \$dcount" 186 | quit 187 | EOF 188 | 189 | #------------------------------------------------------------------ 190 | # Run magic in batch mode. 191 | #------------------------------------------------------------------ 192 | 193 | echo "Running magic $version" 194 | echo "magic -dnull -noconsole ${drc_options} ${rundrcfile}" |& tee -a ${synthlog} 195 | ${bindir}/magic -dnull -noconsole ${drc_options} ${rundrcfile} |& tee -a ${synthlog} 196 | 197 | set errcond = $status 198 | if ( ${errcond} != 0 ) then 199 | echo "magic failed with exit status ${errcond}" |& tee -a ${synthlog} 200 | echo "Premature exit." |& tee -a ${synthlog} 201 | echo "Synthesis flow stopped on error condition." >>& ${synthlog} 202 | exit 1 203 | endif 204 | 205 | #--------------------------------------------------------------------- 206 | # Spot check: Does the last line of the synthlog have "drc = 0"? 207 | #--------------------------------------------------------------------- 208 | 209 | set errors=`tail -10 ${synthlog} | grep "drc =" | cut -d' ' -f3` 210 | if ( $errors > 0 ) then 211 | echo "DRC failure: There are ${errors} DRC errors in the layout." \ 212 | |& tee -a ${synthlog} 213 | echo "Premature exit." |& tee -a ${synthlog} 214 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 215 | exit 1 216 | endif 217 | 218 | #------------------------------------------------------------ 219 | # Done! 220 | #------------------------------------------------------------ 221 | 222 | set endtime = `date` 223 | echo "DRC checking script ended on $endtime" >> $synthlog 224 | 225 | exit 0 226 | -------------------------------------------------------------------------------- /scripts/blif2sim.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | # 3 | # Usage: 4 | # blif2sim.tcl [] 5 | # 6 | # If cel_filename is not specified, then name will be the root name 7 | # of the .blif file with the .sim extension. 8 | # 9 | # "dir" is the directory where .sim views of the standard cells are 10 | # located. If .sim views are not available but .mag files are, the 11 | # .sim files will be generated automatically. 12 | # 13 | #------------------------------------------------------------ 14 | # Written by Tim Edwards February 12, 2007 15 | # MultiGiG, Inc. 16 | #------------------------------------------------------------ 17 | 18 | set bliffile [lindex $argv 0] 19 | set cellname [file rootname $bliffile] 20 | if {"$cellname" == "$bliffile"} { 21 | set bliffile ${cellname}.blif 22 | } 23 | 24 | set prefix "" 25 | if {$argc > 2} { 26 | if {[lindex $argv [expr {$argc - 2}]] == "-prefix"} { 27 | set prefix [lindex $argv [expr {$argc - 1}]]/ 28 | incr argc -2 29 | } 30 | } 31 | 32 | if {$argc > 1} { 33 | set magdir [lindex $argv 1] 34 | } else { 35 | set magdir /home/tim/projects/multigig/digital_flow/layout/digital2 36 | } 37 | 38 | if {$argc == 3} { 39 | set simfile [lindex $argv 2] 40 | } else { 41 | set simfile ${cellname}.sim 42 | } 43 | 44 | set scriptdir [file dirname $argv0] 45 | 46 | #------------------------------------------------------------- 47 | # Open files for read and write 48 | 49 | if [catch {open $bliffile r} fnet] { 50 | puts stderr "Error: can't open file $bliffile for reading!" 51 | exit 0 52 | } 53 | 54 | #---------------------------------------------------------------- 55 | # First, parse the contents of the .blif file and get a list 56 | # of all macro names used. 57 | #---------------------------------------------------------------- 58 | 59 | puts stdout "1st pass of blif file ${bliffile}. . ." 60 | flush stdout 61 | 62 | set macrolist {} 63 | while {[gets $fnet line] >= 0} { 64 | if [regexp {^INSTANCE[ \t]+"([^"]+)"} $line lmatch macro] { 65 | lappend macrolist $macro 66 | } 67 | } 68 | set macrolist [lsort -unique $macrolist] 69 | close $fnet 70 | 71 | set needsims {} 72 | foreach macro $macrolist { 73 | if {[glob -nocomplain ${magdir}/${macro}.sim] == {}} { 74 | lappend needsims ${macro} 75 | } elseif {[file size ${magdir}/${macro}.ext] == 0} { 76 | lappend needsims ${macro} 77 | } 78 | } 79 | 80 | if {$needsims != {}} { 81 | puts stdout "Generating .sim views. . ." 82 | flush stdout 83 | 84 | foreach macro $needsims { 85 | puts stdout "Generating ${macro}.sim" 86 | flush stdout 87 | catch {exec ${scriptdir}/makesim.sh ${magdir}/$macro} 88 | } 89 | } 90 | 91 | if [catch {open $simfile w} fsim] { 92 | puts stderr "Error: can't open file $simfile for writing!" 93 | exit 0 94 | } 95 | 96 | puts $fsim "| SIM file $simfile generated by blif2sim" 97 | 98 | #---------------------------------------------------------------- 99 | # Procedure to dump the contents of a subcircuit .sim file to the 100 | # top-level .sim file, replacing pin names with net names. 101 | #---------------------------------------------------------------- 102 | 103 | proc dump_sim {fsim mode magdir prefix} { 104 | 105 | # Pick up variable definition from top-level 106 | upvar $mode mname 107 | 108 | # Make VDD, VSS, and GND show up as globals 109 | set mname(VDD) VDD 110 | set mname(VDD!) VDD 111 | set mname(VSS) VSS 112 | set mname(VSS!) VSS 113 | set mname(GND) GND 114 | set mname(GND!) GND 115 | 116 | set fsub [open ${magdir}/${mode}.sim r] 117 | while {[gets $fsub line] >= 0} { 118 | set mtype [string index $line 0] 119 | 120 | # Parse .sim file lines. Ignore lumped "R", which is not used by IRSIM. 121 | 122 | switch -exact $mtype { 123 | n - 124 | p { regexp {^[pn] ([^ ]+) ([^ ]+) ([^ ]+) (.*)} $line valid \ 125 | gate drain source rest 126 | puts -nonewline $fsim "$mtype " 127 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${gate}) "}]} { 128 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$gate " 129 | } 130 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${drain}) "}]} { 131 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$drain " 132 | } 133 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${source}) "}]} { 134 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$source " 135 | } 136 | puts $fsim $rest 137 | } 138 | r { regexp {^r ([^ ]+) ([^ ]+) (.*)} $line valid r1 r2 rest 139 | puts -nonewline $fsim "r " 140 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${r1}) "}]} { 141 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$r1 " 142 | } 143 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${r2}) "}]} { 144 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$r2 " 145 | } 146 | puts $fsim $rest 147 | } 148 | C { regexp {^C ([^ ]+) ([^ ]+) (.*)} $line valid top bottom rest 149 | puts -nonewline $fsim "C " 150 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${top}) "}]} { 151 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$top " 152 | } 153 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${bottom}) "}]} { 154 | puts -nonewline $fsim "${prefix}${mode}$mname(count)/$bottom " 155 | } 156 | puts $fsim $rest 157 | } 158 | | { puts $fsim $line } 159 | } 160 | } 161 | close $fsub 162 | } 163 | 164 | #---------------------------------------------------------------- 165 | # Parse the contents of the .blif file again and dump each cell 166 | # instance to the .sim file output. 167 | 168 | puts stdout "2nd pass of blif file. . ." 169 | flush stdout 170 | 171 | set fnet [open $bliffile r] 172 | set mode none 173 | while {[gets $fnet line] >= 0} { 174 | if [regexp {^INSTANCE[ \t]+"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line \ 175 | lmatch macroname macrotype] { 176 | # New instance. First dump the current instance to the sim file 177 | if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix} 178 | 179 | # (There is now a valid mag/ext/sim file for TIELO and TIEHI) 180 | # if [string equal $macroname TIELO] {gets $fnet line; continue} 181 | # if [string equal $macroname TIEHI] {gets $fnet line; continue} 182 | set mode $macroname 183 | if {[catch {incr ${mode}(count)}]} {set ${mode}(count) 0} 184 | } elseif [regexp {^ENDMODEL} $line lmatch] { 185 | # Dump last "mode" output 186 | if {$mode != "pins"} { dump_sim $fsim $mode $magdir $prefix} 187 | } elseif [regexp {^INPUT} $line lmatch] { 188 | set mode "pins" 189 | } elseif [regexp {^OUTPUT} $line lmatch] { 190 | set mode "pins" 191 | } elseif [regexp {^MODEL[ \t]+"([^"]+)"} $line lmatch cellverify] { 192 | if {"$cellname" != "$cellverify"} { 193 | puts -nonewline stderr "WARNING: MODEL name ${cellverify} does not" 194 | puts stderr " match filename ${cellname}!" 195 | } 196 | } elseif {"$mode" == "pins"} { 197 | if [regexp {"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line lmatch pinname netname] { 198 | # Don't do anything with these. 199 | } 200 | } else { 201 | # In the middle of parsing an instance; mode = instance name (in lowercase). 202 | if [regexp {"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line lmatch pinname netname] { 203 | set ${mode}(${pinname}) $netname 204 | } 205 | } 206 | } 207 | # Dump the final instance to the sim file, if there was one. 208 | if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix} 209 | close $fnet 210 | 211 | puts stdout "Done!" 212 | -------------------------------------------------------------------------------- /scripts/getfillcell.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # getfillcell.tcl --- 4 | # 5 | # Read the .par file and find the feedthru width 6 | # Read LEF file and parse for fill cells; find the one that 7 | # corresponds to the feedthru width and return its name 8 | # 9 | # NOTE: The eventual goal is to have the .par file automatically 10 | # generated, in which case we really want to do this process in 11 | # reverse. 12 | # 13 | #--------------------------------------------------------------------------- 14 | namespace path {::tcl::mathop ::tcl::mathfunc} 15 | 16 | if {$argc < 3} { 17 | puts stdout "Usage: getfillcell " 18 | exit 0 19 | } 20 | 21 | puts stdout "Running getfillcell.tcl" 22 | 23 | set topname [file rootname [lindex $argv 0]] 24 | set lefname [lindex $argv 1] 25 | set fillcell [lindex $argv 2] 26 | 27 | set parname ${topname}.par 28 | 29 | set units 100 ;# read micron units from the LEF file 30 | ;# and convert to centimicrons 31 | 32 | #----------------------------------------------------------------- 33 | # Open all files for reading and writing 34 | #----------------------------------------------------------------- 35 | 36 | if [catch {open $lefname r} flef] { 37 | puts stderr "Error: can't open file $lefname for input" 38 | return 39 | } 40 | 41 | if [catch {open $parname r} fpar] { 42 | puts stderr "Error: can't open file $parname for input" 43 | return 44 | } 45 | 46 | #----------------------------------------------------------------- 47 | # Read the .par file and look for "feedThruWidth". 48 | #----------------------------------------------------------------- 49 | 50 | puts stdout "Reading .par file ${parname}. . ." 51 | flush stdout 52 | 53 | set fwidth 0 54 | while {[gets $fpar line] >= 0} { 55 | if {![regexp {[ \t]*#} $line lmatch]} { 56 | if [regexp {feedThruWidth[ \t]*:[ \t]*([0-9]+)} $line lmatch fwidth] { 57 | break 58 | } 59 | } 60 | } 61 | if {$fwidth == 0} { 62 | puts stdout "(no feedthroughs or width defined as zero)" 63 | } 64 | 65 | #---------------------------------------------------------------- 66 | # Read through a LEF file section that we don't care about. 67 | #---------------------------------------------------------------- 68 | 69 | proc skip_section {leffile sectionname} { 70 | while {[gets $leffile line] >= 0} { 71 | if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] { 72 | if {"$sectiontest" != "$sectionname"} { 73 | puts -nonewline stderr "Unexpected END statement $line " 74 | puts stderr "while reading section $sectionname" 75 | } 76 | break 77 | } 78 | } 79 | } 80 | 81 | #---------------------------------------------------------------- 82 | # Parse the macro contents of the LEF file and retain the information 83 | # about cell size and pin positions. 84 | #---------------------------------------------------------------- 85 | 86 | proc parse_macro {leffile macroname} { 87 | global $macroname units 88 | 89 | while {[gets $leffile line] >= 0} { 90 | if [regexp {[ \t]*SYMMETRY[ \t]+(.+)[ \t]*;} $line lmatch symmetry] { 91 | set ${macroname}(symmetry) $symmetry 92 | } elseif [regexp {[ \t]*ORIGIN[ \t]+(.+)[ \t]+(.+)[ \t]*;} $line lmatch x y] { 93 | set x [expr {int($x * $units)}] 94 | set y [expr {int($y * $units)}] 95 | set ${macroname}(x) $x 96 | set ${macroname}(y) $y 97 | } elseif [regexp {[ \t]*SIZE[ \t]+(.+)[ \t]+BY[ \t]+(.+)[ \t]*;} \ 98 | $line lmatch w h] { 99 | set w [expr {int($w * $units)}] 100 | set h [expr {int($h * $units)}] 101 | set ${macroname}(w) $w 102 | set ${macroname}(h) $h 103 | 104 | } elseif [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] { 105 | # The fill cell is not expected to have any usable pins 106 | skip_section $leffile $pinname 107 | } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] { 108 | if {"$macrotest" == "$macroname"} { 109 | break 110 | } else { 111 | puts stderr "Unexpected END statement $line while reading macro $macroname" 112 | } 113 | } 114 | } 115 | } 116 | 117 | #----------------------------------------------------------------- 118 | # Read the lef macro file and get the fill cells and their widths 119 | #----------------------------------------------------------------- 120 | 121 | puts stdout "Reading ${fillcell} macros from LEF file." 122 | flush stdout 123 | 124 | puts stdout "Diagnostic: fill cell width from .par file is $fwidth" 125 | set usefillcell {} 126 | 127 | set feedcellw 0 128 | set feedcellmin {} 129 | while {[gets $flef line] >= 0} { 130 | if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] { 131 | # Parse the "macro" statement 132 | parse_macro $flef $macroname 133 | if {[regexp "^$fillcell" $macroname] == 1} { 134 | # Check width against feedthrough width 135 | set w [subst \$${macroname}(w)] 136 | puts stdout "Diagnostic: macro $macroname width = $w" 137 | if {$w == $fwidth} { 138 | set usefillcell $macroname 139 | } elseif {($w < $feedcellw) || ($feedcellw == 0)} { 140 | set feedcellw $w 141 | set feedcellmin $macroname 142 | } 143 | } 144 | } elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] { 145 | skip_section $flef $layername 146 | } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] { 147 | skip_section $flef $vianame 148 | } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] { 149 | skip_section $flef $viarulename 150 | } elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] { 151 | skip_section $flef $sitename 152 | } elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] { 153 | skip_section $flef SPACING 154 | } elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] { 155 | skip_section $flef UNITS 156 | } elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] { 157 | skip_section $flef PROPERTYDEFINITIONS 158 | } elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] { 159 | break 160 | } elseif [regexp {^[ \t]*#} $line lmatch] { 161 | # Comment line, ignore. 162 | } elseif ![regexp {^[ \t]*$} $line lmatch] { 163 | # Other things we don't care about 164 | set matches 0 165 | if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] { 166 | incr matches 167 | } elseif [regexp {[ \t]*VERSION} $line lmatch] { 168 | incr matches 169 | } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] { 170 | incr matches 171 | } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] { 172 | incr matches 173 | } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] { 174 | incr matches 175 | } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] { 176 | incr matches 177 | } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] { 178 | incr matches 179 | } else { 180 | puts stderr "Unexpected input in LEF file: Only macro defs were expected!" 181 | puts -nonewline stdout "Line is: $line" 182 | flush stdout 183 | } 184 | } 185 | } 186 | 187 | if {$usefillcell == {}} { 188 | if {$feedcellmin != {}} { 189 | puts stderr "Warning: No fill cells correspond to cell width in the .par file." 190 | puts stderr "Using smallest matching fill macro $feedcellmin" 191 | set usefillcell $feedcellmin 192 | } else { 193 | puts stderr "Error: No matching fill cells found in LEF macro file." 194 | } 195 | } 196 | 197 | close $flef 198 | close $fpar 199 | 200 | puts stdout "fill=$usefillcell" 201 | puts stdout "Done with getfillcell.tcl" 202 | -------------------------------------------------------------------------------- /scripts/blifanno.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # blifanno.tcl --- 4 | # 5 | # Read a BLIF file and a post-placement DEF file. The placement stage is 6 | # assumed to have rewired buffer trees for optimal placement, making the 7 | # BLIF file netlist invalid. The contents of the DEF file are used to 8 | # back-annotate the correct buffer tree connections to the BLIF netlist. 9 | # The output is a corrected BLIF netlist. 10 | # 11 | #--------------------------------------------------------------------------- 12 | namespace path {::tcl::mathop ::tcl::mathfunc} 13 | 14 | if {$argc < 2} { 15 | puts stdout "Usage: blifanno.tcl \[\]" 16 | exit 0 17 | } 18 | 19 | puts stdout "Running blifanno.tcl" 20 | 21 | # NOTE: There is no scaling. GrayWolf values are in centimicrons, 22 | # as are DEF values (UNITS DISTANCE MICRONS 100) 23 | 24 | set blifinname [lindex $argv 0] 25 | set defname [lindex $argv 1] 26 | 27 | set units 100 ;# write centimicron units into the DEF file 28 | 29 | #----------------------------------------------------------------- 30 | # Open all files for reading and writing 31 | #----------------------------------------------------------------- 32 | 33 | if [catch {open $defname r} fdef] { 34 | puts stderr "Error: can't open file $defname for input" 35 | return 36 | } 37 | 38 | if [catch {open $blifinname r} fnet] { 39 | puts stderr "Error: can't open file $blifinname for input" 40 | return 41 | } 42 | 43 | if {$argc == 3} { 44 | set blifoutname [lindex $argv 2] 45 | if [catch {open $blifoutname w} fout] { 46 | puts stderr "Error: can't open file $blifoutname for output" 47 | return 48 | } 49 | } else { 50 | set fout stdout 51 | } 52 | 53 | #---------------------------------------------------------------- 54 | # Read through a LEF file section that we don't care about. 55 | #---------------------------------------------------------------- 56 | 57 | proc skip_section {leffile sectionname} { 58 | while {[gets $leffile line] >= 0} { 59 | if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] { 60 | if {"$sectiontest" != "$sectionname"} { 61 | puts -nonewline stderr "Unexpected END statement $line " 62 | puts stderr "while reading section $sectionname" 63 | } 64 | break 65 | } 66 | } 67 | } 68 | 69 | #----------------------------------------------------------------- 70 | # Parse the NETS section of the DEF file 71 | # Assuming this file was generated by place2def, each net 72 | # connection should be on a separate line. 73 | #----------------------------------------------------------------- 74 | 75 | proc parse_nets {deffile nets} { 76 | upvar $nets rdict 77 | set ignore 0 78 | while {[gets $deffile line] >= 0} { 79 | if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t\n]*$} $line lmatch sectiontest] { 80 | if {"$sectiontest" == "NETS"} { 81 | break 82 | } else { 83 | puts -nonewline stderr "Unexpected END statement $line " 84 | puts stderr "while reading section NETS" 85 | } 86 | break 87 | } elseif [regexp {[ \t]*-[ \t]+([^ \t]+)} $line lmatch netname] { 88 | set ignore 0 89 | } elseif [regexp {[ \t]*\+[ \t]+([^ \t]+)} $line lmatch option] { 90 | set ignore 1 91 | } elseif {$ignore == 0} { 92 | if [regexp {[ \t]*\([ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]*\)[ \t\n;]*$} \ 93 | $line lmatch instname pinname] { 94 | dict set rdict ${instname}/${pinname} $netname 95 | } 96 | } 97 | } 98 | } 99 | 100 | #----------------------------------------------------------------- 101 | # Read the DEF file once to get the number of rows and the length 102 | # of each row 103 | #----------------------------------------------------------------- 104 | 105 | puts stdout "Reading DEF file ${defname}. . ." 106 | flush stdout 107 | 108 | while {[gets $fdef line] >= 0} { 109 | if [regexp {[ \t]*COMPONENTS[ \t]+([^ \t]+)[ \t]*;} $line lmatch number] { 110 | skip_section $fdef COMPONENTS 111 | } elseif [regexp {[ \t]*SPECIALNETS[ \t]+([^ \t]+)} $line lmatch netnums] { 112 | skip_section $fdef SPECIALNETS 113 | } elseif [regexp {[ \t]*NETS[ \t]+([^ \t]+)} $line lmatch netnums] { 114 | set nets [dict create] 115 | # Parse the "NETS" section 116 | parse_nets $fdef nets 117 | # puts stdout "Done with NETS section, dict size is [dict size $nets]" 118 | } elseif [regexp {[ \t]*PINS[ \t]+([^ \t]+)} $line lmatch pinnum] { 119 | skip_section $fdef PINS 120 | } elseif [regexp {[ \t]*VIAS[ \t]+(.+)[ \t]*$} $line lmatch number] { 121 | skip_section $fdef VIAS 122 | } elseif [regexp {[ \t]*END[ \t]+DESIGN[ \t]*$} $line lmatch] { 123 | break 124 | } elseif [regexp {^[ \t]*#} $line lmatch] { 125 | # Comment line, ignore. 126 | } elseif ![regexp {^[ \t]*$} $line lmatch] { 127 | # Other things we don't care about 128 | set matches 0 129 | if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] { 130 | incr matches 131 | } elseif [regexp {[ \t]*VERSION} $line lmatch] { 132 | incr matches 133 | } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] { 134 | incr matches 135 | } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] { 136 | incr matches 137 | } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] { 138 | incr matches 139 | } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] { 140 | incr matches 141 | } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] { 142 | incr matches 143 | } elseif [regexp {[ \t]*UNITS} $line lmatch] { 144 | incr matches 145 | } elseif [regexp {[ \t]*DESIGN} $line lmatch] { 146 | incr matches 147 | } elseif [regexp {[ \t]*DIEAREA} $line lmatch] { 148 | incr matches 149 | } elseif [regexp {[ \t]*TRACKS} $line lmatch] { 150 | incr matches 151 | } else { 152 | puts stderr "Unexpected input in DEF file:" 153 | puts stdout "Line is: $line" 154 | } 155 | } 156 | } 157 | 158 | close $fdef 159 | 160 | #----------------------------------------------------------------- 161 | # Now read the BLIF netlist, and rewrite all net connections from 162 | # the list found in the DEF file 163 | #----------------------------------------------------------------- 164 | 165 | set instcount [dict create] 166 | 167 | while {[gets $fnet line] >= 0} { 168 | if [regexp {^[ \t]*\.gate[ \t]+([^ \t]+)[ \t]+(.*)$} \ 169 | $line lmatch macroname rest] { 170 | if {[dict exists $instcount $macroname]} { 171 | set iidx [dict get $instcount $macroname] 172 | incr iidx 173 | dict set instcount $macroname $iidx 174 | } else { 175 | dict set instcount $macroname 1 176 | set iidx 1 177 | } 178 | set gateline ".gate $macroname" 179 | while {[regexp {[ \t]*([^ \t]+)[ \t]*=[ \t]*([^ \t]+)[ \t]*(.*)$} \ 180 | $rest lmatch pinname netname nextconn] > 0} { 181 | if {[catch {set newnet [dict get $nets ${macroname}_${iidx}/${pinname}]}]} { 182 | # NOTE: Dangling buffer outputs (for debug) do not show up in 183 | # graywolf output. They cannot be sorted, so just copy them 184 | # as they are in the original blif file. 185 | set gateline "${gateline} ${pinname}=${netname}" 186 | } else { 187 | set gateline "${gateline} ${pinname}=${newnet}" 188 | } 189 | set rest $nextconn 190 | } 191 | puts $fout "$gateline" 192 | } else { 193 | puts $fout $line 194 | } 195 | } 196 | 197 | #----------------------------------------------------------------- 198 | #----------------------------------------------------------------- 199 | 200 | close $fnet 201 | if {$fout != "stdout"} {close $fout} 202 | 203 | puts stdout "Done with blifanno.tcl" 204 | -------------------------------------------------------------------------------- /scripts/netgen_lvs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/tcsh -f 2 | #---------------------------------------------------------- 3 | # LVS comparison script using netgen 4 | #---------------------------------------------------------- 5 | # Tim Edwards, 8/20/18, for Open Circuit Design 6 | #---------------------------------------------------------- 7 | 8 | # Split out options from the main arguments 9 | set argline=(`getopt "" $argv[1-]`) 10 | 11 | set options=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $1}'` 12 | set cmdargs=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $2}'` 13 | set argc=`echo $cmdargs | wc -w` 14 | 15 | if ($argc >= 2) then 16 | set argv1=`echo $cmdargs | cut -d' ' -f1` 17 | set argv2=`echo $cmdargs | cut -d' ' -f2` 18 | else 19 | echo "Usage: netgen_lvs.sh [options] " 20 | echo " where" 21 | echo " is the name of the project directory containing" 22 | echo " a file called qflow_vars.sh." 23 | echo " is the root name of the verilog file" 24 | exit 1 25 | endif 26 | 27 | set projectpath=$argv1 28 | set sourcename=$argv2 29 | set rootname=${sourcename:h} 30 | 31 | # This script is called with the first argument , which should 32 | # have file "qflow_vars.sh". Get all of our standard variable definitions 33 | # from the qflow_vars.sh file. 34 | 35 | if (! -f ${projectpath}/qflow_vars.sh ) then 36 | echo "Error: Cannot find file qflow_vars.sh in path ${projectpath}" 37 | exit 1 38 | endif 39 | 40 | source ${projectpath}/qflow_vars.sh 41 | source ${techdir}/${techname}.sh 42 | cd ${projectpath} 43 | if (-f project_vars.sh) then 44 | source project_vars.sh 45 | endif 46 | 47 | if (! ${?lvs_options} ) then 48 | set lvs_options=${options} 49 | endif 50 | 51 | if (!($?logdir)) then 52 | set logdir=${projectpath}/log 53 | endif 54 | mkdir -p ${logdir} 55 | set lastlog=${logdir}/migrate.log 56 | set synthlog=${logdir}/lvs.log 57 | rm -f ${synthlog} >& /dev/null 58 | rm -f ${logdir}/gdsii.log >& /dev/null 59 | touch ${synthlog} 60 | set date=`date` 61 | echo "Qflow LVS logfile created on $date" > ${synthlog} 62 | 63 | # Check if last line of migrate log file says "error condition" 64 | if ( ! -f ${lastlog} ) then 65 | echo "Warning: No migration logfile found." 66 | else 67 | set errcond=`tail -1 ${lastlog} | grep "error condition" | wc -l` 68 | if ( ${errcond} == 1 ) then 69 | echo "Synthesis flow stopped on error condition. LVS comparison" 70 | echo "will not proceed until error condition is cleared." 71 | exit 1 72 | endif 73 | endif 74 | 75 | # Check if migration was run. Must have synthesis and layout extracted 76 | # netlists. All netlists must be more recent than the project ".def" file. 77 | 78 | if ( ! -f ${synthdir}/${rootname}.spc || \ 79 | ( -M ${synthdir}/${rootname}.spc < -M ${synthdir}/${rootname}.rtl.v )) then 80 | echo "LVS failure: No schematic netlist found." |& tee -a ${synthlog} 81 | echo "Premature exit." |& tee -a ${synthlog} 82 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 83 | exit 1 84 | endif 85 | 86 | if ( ! -f ${layoutdir}/${rootname}.spice || \ 87 | ( -M ${layoutdir}/${rootname}.spice < -M ${layoutdir}/${rootname}.def )) then 88 | echo "LVS failure: No layout extracted netlist found; migration was not run." \ 89 | |& tee -a ${synthlog} 90 | echo "Premature exit." |& tee -a ${synthlog} 91 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 92 | exit 1 93 | endif 94 | 95 | # If the layout (.mag) file is more recent than the netlist (.spice) file, then 96 | # the layout needs to be re-extracted. 97 | 98 | if ( -M ${layoutdir}/${rootname}.spice < -M ${layoutdir}/${rootname}.mag ) then 99 | echo "Layout post-dates extracted netlist; re-extraction required." \ 100 | |& tee -a ${synthlog} 101 | # Re-extract the netlist. 102 | source ${scriptdir}/migrate.sh -x ${projectpath} ${sourcename} 103 | endif 104 | 105 | # Check for technology setup script. If it is in the qflow technology script 106 | # as variable "netgen_setup", then use that. Otherwise, assume it is in the 107 | # technology directory path. 108 | 109 | if ( ${?netgen_setup} ) then 110 | set setup_script=${netgen_setup} 111 | if ( ! ( -f ${setup_script} )) then 112 | set setup_script=${techdir}/${netgen_setup} 113 | endif 114 | else 115 | set setup_script=${techdir}/${techname}_setup.tcl 116 | endif 117 | 118 | # Check for existence of the netgen setup script in the techfile, and 119 | # alternative setup scripts that may exist in the layout directory. 120 | 121 | if ( ! ( -f ${setup_script} )) then 122 | if ( -f ${layoutdir}/setup.tcl ) then 123 | set setup_script=${layoutdir}/setup.tcl 124 | else if ( -f ${layoutdir}/${rootname}_setup.tcl ) then 125 | set setup_script=${layoutdir}/${rootname}_setup.tcl 126 | else if ( -f ${layoutdir}/${rootname}.tcl ) then 127 | set setup_script=${layoutdir}/${rootname}.tcl 128 | else 129 | echo "LVS failure: No technology setup script for netgen found." \ 130 | |& tee -a ${synthlog} 131 | echo "Premature exit." |& tee -a ${synthlog} 132 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 133 | exit 1 134 | endif 135 | endif 136 | 137 | 138 | #---------------------------------------------------------- 139 | # Done with initialization 140 | #---------------------------------------------------------- 141 | 142 | cd ${layoutdir} 143 | 144 | #------------------------------------------------------------------ 145 | # Run netgen in batch mode. 146 | #------------------------------------------------------------------ 147 | 148 | set outfile=comp.out 149 | 150 | echo "Running netgen" 151 | echo netgen ${lvs_options} -batch lvs \"${rootname}.spice ${rootname}\" \ 152 | \"${synthdir}/${rootname}.spc ${rootname}\" ${setup_script} ${outfile} \ 153 | -json -blackbox |& tee -a ${synthlog} 154 | 155 | ${bindir}/netgen ${lvs_options} -batch lvs "${rootname}.spice ${rootname}" \ 156 | "${synthdir}/${rootname}.spc ${rootname}" ${setup_script} ${outfile} \ 157 | -json -blackbox |& tee -a ${synthlog} 158 | 159 | set errcond=$status 160 | if ( ${errcond} != 0 ) then 161 | echo "netgen failed with exit status ${errcond}" |& tee -a ${synthlog} 162 | echo "Premature exit." |& tee -a ${synthlog} 163 | echo "Synthesis flow stopped on error condition." >>& ${synthlog} 164 | exit 1 165 | endif 166 | 167 | #--------------------------------------------------------------------- 168 | # Spot check: Did netgen produce file comp.out? 169 | #--------------------------------------------------------------------- 170 | 171 | if ( ! -f comp.out || ( -M comp.out < -M ${rootname}.spice )) then 172 | echo "netgen failure: No file comp.out." |& tee -a ${synthlog} 173 | echo "Premature exit." |& tee -a ${synthlog} 174 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 175 | exit 1 176 | endif 177 | 178 | #--------------------------------------------------------------------- 179 | # Check for LVS errors 180 | #--------------------------------------------------------------------- 181 | 182 | echo "Running count_lvs.py" 183 | echo "${scriptdir}/count_lvs.py" |& tee -a ${synthlog} 184 | ${scriptdir}/count_lvs.py |& tee -a ${synthlog} 185 | 186 | set err_total=`tail -1 ${synthlog} | cut -d' ' -f4` 187 | if ( ${err_total} > 0 ) then 188 | echo "Design fails LVS with ${err_total} errors." |& tee -a ${synthlog} 189 | echo "See lvs.log and comp.out for error details." |& tee -a ${synthlog} 190 | echo "Synthesis flow stopped due to error condition." >> ${synthlog} 191 | exit 1 192 | endif 193 | 194 | #------------------------------------------------------------ 195 | # Done! 196 | #------------------------------------------------------------ 197 | 198 | set endtime=`date` 199 | echo "LVS checking script ended on $endtime" >> $synthlog 200 | 201 | exit 0 202 | -------------------------------------------------------------------------------- /scripts/tooltip.py.in: -------------------------------------------------------------------------------- 1 | #!ENV_PATH python3 2 | '''Michael Lange 3 | The ToolTip class provides a flexible tooltip widget for tkinter; it is based on IDLE's ToolTip 4 | module which unfortunately seems to be broken (at least the version I saw). 5 | INITIALIZATION OPTIONS: 6 | anchor : where the text should be positioned inside the widget, must be on of "n", "s", "e", "w", "nw" and so on; 7 | default is "center" 8 | bd : borderwidth of the widget; default is 1 (NOTE: don't use "borderwidth" here) 9 | bg : background color to use for the widget; default is "lightyellow" (NOTE: don't use "background") 10 | delay : time in ms that it takes for the widget to appear on the screen when the mouse pointer has 11 | entered the parent widget; default is 1500 12 | fg : foreground (i.e. text) color to use; default is "black" (NOTE: don't use "foreground") 13 | follow_mouse : if set to 1 the tooltip will follow the mouse pointer instead of being displayed 14 | outside of the parent widget; this may be useful if you want to use tooltips for 15 | large widgets like listboxes or canvases; default is 0 16 | font : font to use for the widget; default is system specific 17 | justify : how multiple lines of text will be aligned, must be "left", "right" or "center"; default is "left" 18 | padx : extra space added to the left and right within the widget; default is 4 19 | pady : extra space above and below the text; default is 2 20 | relief : one of "flat", "ridge", "groove", "raised", "sunken" or "solid"; default is "solid" 21 | state : must be "normal" or "disabled"; if set to "disabled" the tooltip will not appear; default is "normal" 22 | text : the text that is displayed inside the widget 23 | textvariable : if set to an instance of tkinter.StringVar() the variable's value will be used as text for the widget 24 | width : width of the widget; the default is 0, which means that "wraplength" will be used to limit the widgets width 25 | wraplength : limits the number of characters in each line; default is 150 26 | 27 | WIDGET METHODS: 28 | configure(**opts) : change one or more of the widget's options as described above; the changes will take effect the 29 | next time the tooltip shows up; NOTE: follow_mouse cannot be changed after widget initialization 30 | 31 | Other widget methods that might be useful if you want to subclass ToolTip: 32 | enter() : callback when the mouse pointer enters the parent widget 33 | leave() : called when the mouse pointer leaves the parent widget 34 | motion() : is called when the mouse pointer moves inside the parent widget if follow_mouse is set to 1 and the 35 | tooltip has shown up to continually update the coordinates of the tooltip window 36 | coords() : calculates the screen coordinates of the tooltip window 37 | create_contents() : creates the contents of the tooltip window (by default a tkinter.Label) 38 | ''' 39 | # Ideas gleaned from PySol 40 | 41 | import tkinter 42 | 43 | class ToolTip: 44 | def __init__(self, master, text='Your text here', delay=1500, **opts): 45 | self.master = master 46 | self._opts = {'anchor':'center', 'bd':1, 'bg':'lightyellow', 'delay':delay, 'fg':'black',\ 47 | 'follow_mouse':0, 'font':None, 'justify':'left', 'padx':4, 'pady':2,\ 48 | 'relief':'solid', 'state':'normal', 'text':text, 'textvariable':None,\ 49 | 'width':0, 'wraplength':150} 50 | self.configure(**opts) 51 | self._tipwindow = None 52 | self._id = None 53 | self._id1 = self.master.bind("", self.enter, '+') 54 | self._id2 = self.master.bind("", self.leave, '+') 55 | self._id3 = self.master.bind("", self.leave, '+') 56 | self._follow_mouse = 0 57 | if self._opts['follow_mouse']: 58 | self._id4 = self.master.bind("", self.motion, '+') 59 | self._follow_mouse = 1 60 | 61 | def configure(self, **opts): 62 | for key in opts: 63 | if key in self._opts: 64 | self._opts[key] = opts[key] 65 | else: 66 | KeyError = 'KeyError: Unknown option: "%s"' %key 67 | raise KeyError 68 | 69 | ##----these methods handle the callbacks on "", "" and ""---------------## 70 | ##----events on the parent widget; override them if you want to change the widget's behavior--## 71 | 72 | def enter(self, event=None): 73 | self._schedule() 74 | 75 | def leave(self, event=None): 76 | self._unschedule() 77 | self._hide() 78 | 79 | def motion(self, event=None): 80 | if self._tipwindow and self._follow_mouse: 81 | x, y = self.coords() 82 | self._tipwindow.wm_geometry("+%d+%d" % (x, y)) 83 | 84 | ##------the methods that do the work:---------------------------------------------------------## 85 | 86 | def _schedule(self): 87 | self._unschedule() 88 | if self._opts['state'] == 'disabled': 89 | return 90 | self._id = self.master.after(self._opts['delay'], self._show) 91 | 92 | def _unschedule(self): 93 | id = self._id 94 | self._id = None 95 | if id: 96 | self.master.after_cancel(id) 97 | 98 | def _show(self): 99 | if self._opts['state'] == 'disabled': 100 | self._unschedule() 101 | return 102 | if not self._tipwindow: 103 | self._tipwindow = tw = tkinter.Toplevel(self.master) 104 | # hide the window until we know the geometry 105 | tw.withdraw() 106 | tw.wm_overrideredirect(1) 107 | 108 | if tw.tk.call("tk", "windowingsystem") == 'aqua': 109 | tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w, "help", "none") 110 | 111 | self.create_contents() 112 | tw.update_idletasks() 113 | x, y = self.coords() 114 | tw.wm_geometry("+%d+%d" % (x, y)) 115 | tw.deiconify() 116 | tw.lift() 117 | 118 | def _hide(self): 119 | tw = self._tipwindow 120 | self._tipwindow = None 121 | if tw: 122 | tw.destroy() 123 | 124 | ##----these methods might be overridden in derived classes:----------------------------------## 125 | 126 | def coords(self): 127 | # The tip window must be completely outside the master widget; 128 | # otherwise when the mouse enters the tip window we get 129 | # a leave event and it disappears, and then we get an enter 130 | # event and it reappears, and so on forever :-( 131 | # or we take care that the mouse pointer is always outside the tipwindow :-) 132 | tw = self._tipwindow 133 | twx, twy = tw.winfo_reqwidth(), tw.winfo_reqheight() 134 | w, h = tw.winfo_screenwidth(), tw.winfo_screenheight() 135 | # calculate the y coordinate: 136 | if self._follow_mouse: 137 | y = tw.winfo_pointery() + 20 138 | # make sure the tipwindow is never outside the screen: 139 | if y + twy > h: 140 | y = y - twy - 30 141 | else: 142 | y = self.master.winfo_rooty() + self.master.winfo_height() + 3 143 | if y + twy > h: 144 | y = self.master.winfo_rooty() - twy - 3 145 | # we can use the same x coord in both cases: 146 | x = tw.winfo_pointerx() - twx / 2 147 | if x < 0: 148 | x = 0 149 | elif x + twx > w: 150 | x = w - twx 151 | return x, y 152 | 153 | def create_contents(self): 154 | opts = self._opts.copy() 155 | for opt in ('delay', 'follow_mouse', 'state'): 156 | del opts[opt] 157 | label = tkinter.Label(self._tipwindow, **opts) 158 | label.pack() 159 | -------------------------------------------------------------------------------- /scripts/getantennacell.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | #--------------------------------------------------------------------------- 3 | # getantennacell.tcl --- 4 | # 5 | # Read LEF file and parse for antenna cells; find the first one 6 | # that matches the name pattern, and return it along with 7 | # its connecting pin name. 8 | # 9 | #--------------------------------------------------------------------------- 10 | namespace path {::tcl::mathop ::tcl::mathfunc} 11 | 12 | if {$argc < 3} { 13 | puts stdout "Usage: getantennacell " 14 | exit 0 15 | } 16 | 17 | puts stdout "Running getantennacell.tcl" 18 | 19 | set topname [file rootname [lindex $argv 0]] 20 | set lefname [lindex $argv 1] 21 | set antennacell [lindex $argv 2] 22 | 23 | set units 100 ;# read micron units from the LEF file 24 | ;# and convert to centimicrons 25 | 26 | #----------------------------------------------------------------- 27 | # Open LEF file for reading 28 | #----------------------------------------------------------------- 29 | 30 | if [catch {open $lefname r} flef] { 31 | puts stderr "Error: can't open file $lefname for input" 32 | return 33 | } 34 | 35 | #---------------------------------------------------------------- 36 | # Read through a LEF file section that we don't care about. 37 | #---------------------------------------------------------------- 38 | 39 | proc skip_section {leffile sectionname} { 40 | while {[gets $leffile line] >= 0} { 41 | if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] { 42 | if {"$sectiontest" != "$sectionname"} { 43 | puts -nonewline stderr "Unexpected END statement $line " 44 | puts stderr "while reading section $sectionname" 45 | } 46 | break 47 | } 48 | } 49 | } 50 | 51 | #---------------------------------------------------------------- 52 | # Parse the pin contents of the LEF file macro 53 | # 54 | # To cope with LEF macro sets where a signal pin may not have a 55 | # use declared, return the pin name of any pin not having a USE 56 | # instead of true/false. 57 | #---------------------------------------------------------------- 58 | 59 | proc parse_pin {leffile pinname} { 60 | set retval false 61 | set portuse "" 62 | while {[gets $leffile line] >= 0} { 63 | if [regexp {[ \t]*USE[ \t]+([^ \t]+)[ \t]*;} $line lmatch portuse] { 64 | set portuse [string toupper $portuse] 65 | if {$portuse == "SIGNAL"} { 66 | set retval true 67 | } 68 | } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch pintest] { 69 | if {"$pintest" == "$pinname"} { 70 | break 71 | } else { 72 | puts stdout "Unexpected END statement $line while parsing pin $pinname" 73 | } 74 | } 75 | } 76 | if {$portuse == ""} { 77 | set retval $pinname ;# special case 78 | } 79 | return $retval 80 | } 81 | 82 | #---------------------------------------------------------------- 83 | # Parse the macro contents of the LEF file and retain the information 84 | # about cell size and pin positions. 85 | #---------------------------------------------------------------- 86 | 87 | proc parse_macro {leffile macroname} { 88 | global $macroname units 89 | 90 | set savepin "" 91 | while {[gets $leffile line] >= 0} { 92 | if [regexp {[ \t]*SYMMETRY[ \t]+(.+)[ \t]*;} $line lmatch symmetry] { 93 | set ${macroname}(symmetry) $symmetry 94 | } elseif [regexp {[ \t]*ORIGIN[ \t]+(.+)[ \t]+(.+)[ \t]*;} $line lmatch x y] { 95 | set x [expr {int($x * $units)}] 96 | set y [expr {int($y * $units)}] 97 | set ${macroname}(x) $x 98 | set ${macroname}(y) $y 99 | } elseif [regexp {[ \t]*SIZE[ \t]+(.+)[ \t]+BY[ \t]+(.+)[ \t]*;} \ 100 | $line lmatch w h] { 101 | set w [expr {int($w * $units)}] 102 | set h [expr {int($h * $units)}] 103 | set ${macroname}(w) $w 104 | set ${macroname}(h) $h 105 | 106 | } elseif [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] { 107 | # Antenna cell has only one pin, so just set a record "pin" for each macro 108 | set presult [parse_pin $leffile $pinname] 109 | if {$presult == true} { 110 | set ${macroname}(pin) $pinname 111 | } elseif {$presult != false} { 112 | set savepin $pinname 113 | } 114 | } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] { 115 | if {"$macrotest" == "$macroname"} { 116 | break 117 | } else { 118 | puts stderr "Unexpected END statement $line while reading macro $macroname" 119 | } 120 | } 121 | } 122 | 123 | # Check for unmarked signal pin. 124 | if [catch {set ${macroname}(pin)}] { 125 | if {$savepin != ""} { 126 | set ${macroname}(pin) $savepin 127 | } else { 128 | set ${macroname}(pin) ERROR ;# Flag this 129 | } 130 | } 131 | } 132 | 133 | #----------------------------------------------------------------- 134 | # Read the lef macro file and get the fill cells and their widths 135 | #----------------------------------------------------------------- 136 | 137 | puts stdout "Reading ${antennacell} macros from LEF file." 138 | flush stdout 139 | 140 | set useantennacell {} 141 | set useantennapin {} 142 | set useantennaw 0 143 | 144 | while {[gets $flef line] >= 0} { 145 | if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] { 146 | # Parse the "macro" statement 147 | parse_macro $flef $macroname 148 | if {[regexp "^$antennacell" $macroname] == 1} { 149 | set w [subst \$${macroname}(w)] 150 | if {($useantennacell == "") || ($w < $useantennaw)} { 151 | # To do: Check width against feedthrough width 152 | puts stdout "Diagnostic: macro $macroname input [subst \$${macroname}(pin)]" 153 | set useantennacell $macroname 154 | set useantennapin [subst \$${macroname}(pin)] 155 | set useantennaw $w 156 | } 157 | } 158 | } elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] { 159 | skip_section $flef $layername 160 | } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] { 161 | skip_section $flef $vianame 162 | } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] { 163 | skip_section $flef $viarulename 164 | } elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] { 165 | skip_section $flef $sitename 166 | } elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] { 167 | skip_section $flef SPACING 168 | } elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] { 169 | skip_section $flef UNITS 170 | } elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] { 171 | skip_section $flef PROPERTYDEFINITIONS 172 | } elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] { 173 | break 174 | } elseif [regexp {^[ \t]*#} $line lmatch] { 175 | # Comment line, ignore. 176 | } elseif ![regexp {^[ \t]*$} $line lmatch] { 177 | # Other things we don't care about 178 | set matches 0 179 | if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] { 180 | incr matches 181 | } elseif [regexp {[ \t]*VERSION} $line lmatch] { 182 | incr matches 183 | } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] { 184 | incr matches 185 | } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] { 186 | incr matches 187 | } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] { 188 | incr matches 189 | } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] { 190 | incr matches 191 | } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] { 192 | incr matches 193 | } else { 194 | puts stderr "Unexpected input in LEF file: Only macro defs were expected!" 195 | puts -nonewline stdout "Line is: $line" 196 | flush stdout 197 | } 198 | } 199 | } 200 | 201 | close $flef 202 | 203 | puts stdout "antenna=${useantennacell}/${useantennapin}" 204 | puts stdout "Done with getantennacell.tcl" 205 | -------------------------------------------------------------------------------- /scripts/Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # qflow project scripts makefile 3 | # 4 | 5 | # Main compiler arguments 6 | CFLAGS = @CFLAGS@ 7 | DEFS = @DEFS@ 8 | LIBS = @LIBS@ 9 | LDFLAGS = @LDFLAGS@ 10 | INSTALL = @INSTALL@ 11 | 12 | prefix = @prefix@ 13 | exec_prefix = @exec_prefix@ 14 | 15 | VERSION = @VERSION@ 16 | REVISION = @REVISION@ 17 | 18 | QFLOW_LIB_DIR = @QFLOW_LIB_DIR@ 19 | QFLOW_BIN_DIR = @QFLOW_BIN_DIR@ 20 | TCLSH_PATH = @TCLSH_PATH@ 21 | ENV_PATH = @ENV_PATH@ 22 | HAVE_PYTHON3 = @HAVE_PYTHON3@ 23 | 24 | # Flow tools (NOTE: Vesta is part of qflow, so HAVE_VESTA is implicitly true) 25 | HAVE_YOSYS = @HAVE_YOSYS@ 26 | HAVE_OPENTIMER = @HAVE_OPENTIMER@ 27 | HAVE_OPENSTA = @HAVE_OPENSTA@ 28 | HAVE_GRAYWOLF = @HAVE_GRAYWOLF@ 29 | HAVE_REPLACE = @HAVE_REPLACE@ 30 | HAVE_QROUTER = @HAVE_QROUTER@ 31 | HAVE_MAGIC = @HAVE_MAGIC@ 32 | HAVE_NETGEN = @HAVE_NETGEN@ 33 | 34 | DEFAULTPARSER = @QFLOW_DEFAULT_PARSER@ 35 | 36 | TCL_SCRIPTS = blif2cel.tcl place2def.tcl place2lef2.tcl 37 | TCL_SCRIPTS += place2net2.tcl ypostproc.tcl ybuffer.tcl 38 | TCL_SCRIPTS += decongest.tcl addspacers.tcl getfillcell.tcl 39 | TCL_SCRIPTS += getantennacell.tcl blifanno.tcl annotate.tcl 40 | TCL_SCRIPTS += powerbus.tcl getpowerground.tcl arrangepins.tcl 41 | TCL_SCRIPTS += removeblocks.tcl 42 | PYTHON_SCRIPTS = spi2xspice.py consoletext.py pinmanager.py 43 | PYTHON_SCRIPTS += tksimpledialog.py helpwindow.py qflow_manager.py 44 | PYTHON_SCRIPTS += textreport.py tooltip.py count_lvs.py preproc.py 45 | PYTHON_SCRIPTS += migrate.py 46 | HELP_TEXT = qflow_help.txt 47 | 48 | # Master list of synthesis flow scripts to install 49 | # Synthesis scripts: 50 | SHELL_SCRIPTS = yosys.sh 51 | # Placement scripts: 52 | SHELL_SCRIPTS += graywolf.sh replace.sh 53 | # Static timing analysys scripts: 54 | SHELL_SCRIPTS += vesta.sh opentimer.sh opensta.sh 55 | # Router scripts: 56 | SHELL_SCRIPTS += qrouter.sh 57 | # Database migration scripts: 58 | SHELL_SCRIPTS += magic_db.sh 59 | # DRC scripts: 60 | SHELL_SCRIPTS += magic_drc.sh 61 | # LVS scripts: 62 | SHELL_SCRIPTS += netgen_lvs.sh 63 | # GDS scripts: 64 | SHELL_SCRIPTS += magic_gds.sh 65 | # Display scripts: 66 | SHELL_SCRIPTS += magic_view.sh 67 | 68 | SHELL_SCRIPTS += qflow.sh checkdirs.sh 69 | SHELL_SCRIPTS += cleanup.sh 70 | MAIN_SCRIPT = qflow 71 | 72 | SCRIPTINSTALL = ${QFLOW_LIB_DIR}/scripts 73 | TECHINSTALL = ${QFLOW_LIB_DIR}/tech 74 | QFLOWEXECPATH = ${QFLOW_LIB_DIR}/bin 75 | EXECINSTALL = ${QFLOW_BIN_DIR} 76 | 77 | INSTALL_SCRIPTINSTALL = @DIST_DIR@/share/qflow/scripts 78 | INSTALL_TECHINSTALL = @DIST_DIR@/share/qflow/tech 79 | INSTALL_QFLOWEXECPATH = @DIST_DIR@/share/qflow/bin 80 | INSTALL_EXECINSTALL = @DIST_DIR@/bin 81 | 82 | all: $(MAIN_SCRIPT).in qflow.sh 83 | $(MAKE) launcher 84 | 85 | launcher: $(MAIN_SCRIPT).in 86 | sed -e '/QFLOW_SCRIPT_DIR/s#QFLOW_SCRIPT_DIR#$(SCRIPTINSTALL)#' \ 87 | $(MAIN_SCRIPT).in > $(MAIN_SCRIPT) 88 | 89 | checkdirs.sh: checkdirs.sh.in 90 | sed -e '/SUBST_TECH_DIR/s#SUBST_TECH_DIR#$(TECHINSTALL)#' \ 91 | -e '/SUBST_SCRIPT_DIR/s#SUBST_SCRIPT_DIR#$(SCRIPTINSTALL)#' \ 92 | -e '/SUBST_BIN_DIR/s#SUBST_BIN_DIR#$(QFLOWEXECPATH)#' \ 93 | checkdirs.sh.in > checkdirs.sh 94 | 95 | qflow.sh: qflow.sh.in 96 | sed -e '/QFLOW_SCRIPT_DIR/s#QFLOW_SCRIPT_DIR#$(SCRIPTINSTALL)#' \ 97 | -e '/QFLOW_DEFAULT_PARSER/s#QFLOW_DEFAULT_PARSER#$(DEFAULTPARSER)#' \ 98 | -e '/QFLOW_REVISION/s#QFLOW_REVISION#$(REVISION)#' \ 99 | -e '/QFLOW_VERSION/s#QFLOW_VERSION#$(VERSION)#' \ 100 | -e '/HAVE_YOSYS/s#HAVE_YOSYS#$(HAVE_YOSYS)#' \ 101 | -e '/HAVE_GRAYWOLF/s#HAVE_GRAYWOLF#$(HAVE_GRAYWOLF)#' \ 102 | -e '/HAVE_REPLACE/s#HAVE_REPLACE#$(HAVE_REPLACE)#' \ 103 | -e '/HAVE_OPENTIMER/s#HAVE_OPENTIMER#$(HAVE_OPENTIMER)#' \ 104 | -e '/HAVE_OPENSTA/s#HAVE_OPENSTA#$(HAVE_OPENSTA)#' \ 105 | -e '/HAVE_QROUTER/s#HAVE_QROUTER#$(HAVE_QROUTER)#' \ 106 | -e '/HAVE_MAGIC/s#HAVE_MAGIC#$(HAVE_MAGIC)#' \ 107 | -e '/HAVE_NETGEN/s#HAVE_NETGEN#$(HAVE_NETGEN)#' \ 108 | qflow.sh.in > qflow.sh 109 | 110 | count_lvs.py: count_lvs.py.in 111 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 112 | 113 | spi2xspice.py: spi2xspice.py.in 114 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 115 | 116 | consoletext.py: consoletext.py.in 117 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 118 | 119 | pinmanager.py: pinmanager.py.in 120 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 121 | 122 | tksimpledialog.py: tksimpledialog.py.in 123 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 124 | 125 | helpwindow.py: helpwindow.py.in 126 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 127 | 128 | preproc.py: preproc.py.in 129 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 130 | 131 | migrate.py: migrate.py.in 132 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 133 | 134 | qflow_manager.py: qflow_manager.py.in 135 | sed -e '/QFLOW_SCRIPT_DIR/s#QFLOW_SCRIPT_DIR#$(SCRIPTINSTALL)#' \ 136 | -e '/QFLOW_VERSION/s#QFLOW_VERSION#$(VERSION)#' \ 137 | -e '/QFLOW_REVISION/s#QFLOW_REVISION#$(REVISION)#' \ 138 | -e '/SUBST_TECH_DIR/s#SUBST_TECH_DIR#$(TECHINSTALL)#' \ 139 | -e '/SUBST_SCRIPT_DIR/s#SUBST_SCRIPT_DIR#$(SCRIPTINSTALL)#' \ 140 | -e '/SUBST_BIN_DIR/s#SUBST_BIN_DIR#$(QFLOWEXECPATH)#' \ 141 | -e '/SUBST_EXEC_DIR/s#SUBST_EXEC_DIR#$(EXECINSTALL)#' \ 142 | -e '/HAVE_OPENTIMER/s#HAVE_OPENTIMER#$(HAVE_OPENTIMER)#' \ 143 | -e '/HAVE_OPENSTA/s#HAVE_OPENSTA#$(HAVE_OPENSTA)#' \ 144 | -e '/HAVE_GRAYWOLF/s#HAVE_GRAYWOLF#$(HAVE_GRAYWOLF)#' \ 145 | -e '/HAVE_REPLACE/s#HAVE_REPLACE#$(HAVE_REPLACE)#' \ 146 | -e '/HAVE_QROUTER/s#HAVE_QROUTER#$(HAVE_QROUTER)#' \ 147 | -e '/HAVE_MAGIC/s#HAVE_MAGIC#$(HAVE_MAGIC)#' \ 148 | -e '/HAVE_NETGEN/s#HAVE_NETGEN#$(HAVE_NETGEN)#' \ 149 | -e '/HAVE_YOSYS/s#HAVE_YOSYS#$(HAVE_YOSYS)#' \ 150 | -e '/ENV_PATH/s#ENV_PATH#$(ENV_PATH)#' $< > $@ 151 | 152 | textreport.py: textreport.py.in 153 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 154 | 155 | tooltip.py: tooltip.py.in 156 | sed -e 's#ENV_PATH#$(ENV_PATH)#' $< > $@ 157 | 158 | blif2cel.tcl: blif2cel.tcl.in 159 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 160 | 161 | place2def.tcl: place2def.tcl.in 162 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 163 | 164 | place2lef2.tcl: place2lef2.tcl.in 165 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 166 | 167 | place2net2.tcl: place2net2.tcl.in 168 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 169 | 170 | ypostproc.tcl: ypostproc.tcl.in 171 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 172 | 173 | ybuffer.tcl: ybuffer.tcl.in 174 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 175 | 176 | decongest.tcl: decongest.tcl.in 177 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 178 | 179 | powerbus.tcl: powerbus.tcl.in 180 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 181 | 182 | addspacers.tcl: addspacers.tcl.in 183 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 184 | 185 | removeblocks.tcl: removeblocks.tcl.in 186 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 187 | 188 | getpowerground.tcl: getpowerground.tcl.in 189 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 190 | 191 | getfillcell.tcl: getfillcell.tcl.in 192 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 193 | 194 | getantennacell.tcl: getantennacell.tcl.in 195 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 196 | 197 | blifanno.tcl: blifanno.tcl.in 198 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 199 | 200 | annotate.tcl: annotate.tcl.in 201 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 202 | 203 | arrangepins.tcl: arrangepins.tcl.in 204 | sed -e 's#TCLSH_PATH#$(TCLSH_PATH)#' $< > $@ 205 | 206 | install: $(TCL_SCRIPTS) $(PYTHON_SCRIPTS) $(SHELL_SCRIPTS) $(MAIN_SCRIPT) $(HELP_TEXT) 207 | @echo "Installing qflow TCL scripts" 208 | $(INSTALL) -d $(DESTDIR)${INSTALL_SCRIPTINSTALL} 209 | for target in $(TCL_SCRIPTS); do \ 210 | $(INSTALL) $$target $(DESTDIR)${INSTALL_SCRIPTINSTALL} ;\ 211 | done 212 | @echo "Installing qflow shell scripts" 213 | for target in $(SHELL_SCRIPTS); do \ 214 | $(INSTALL) $$target $(DESTDIR)${INSTALL_SCRIPTINSTALL} ;\ 215 | done 216 | @echo "Installing qflow python scripts" 217 | for target in $(PYTHON_SCRIPTS); do \ 218 | $(INSTALL) $$target $(DESTDIR)${INSTALL_SCRIPTINSTALL} ;\ 219 | done 220 | @echo "Installing help text files" 221 | for target in $(HELP_TEXT); do \ 222 | $(INSTALL) $$target $(DESTDIR)${INSTALL_SCRIPTINSTALL} ;\ 223 | done 224 | @echo "Installing qflow executable" 225 | $(INSTALL) -d $(DESTDIR)${INSTALL_EXECINSTALL} 226 | $(INSTALL) ${MAIN_SCRIPT} $(DESTDIR)${INSTALL_EXECINSTALL} 227 | 228 | clean: 229 | $(RM) $(MAIN_SCRIPT) 230 | $(RM) checkdirs.sh 231 | $(RM) qflow.sh 232 | $(RM) $(TCL_SCRIPTS) 233 | $(RM) $(PYTHON_SCRIPTS) 234 | 235 | distclean: 236 | $(RM) $(MAIN_SCRIPT) 237 | $(RM) checkdirs.sh 238 | $(RM) qflow.sh 239 | $(RM) $(TCL_SCRIPTS) 240 | $(RM) $(PYTHON_SCRIPTS) 241 | 242 | uninstall: 243 | $(RM) -rf ${SCRIPTINSTALL} 244 | $(RM) ${EXECINSTALL}/${MAIN_SCRIPT} 245 | -------------------------------------------------------------------------------- /scripts/rtl2sim.tcl.in: -------------------------------------------------------------------------------- 1 | #!TCLSH_PATH 2 | # 3 | # Usage: 4 | # rtl2sim.tcl [] 5 | # 6 | # If cel_filename is not specified, then name will be the root name 7 | # of the verilog RTL file with the .sim extension. 8 | # 9 | # "dir" is the directory where .sim views of the standard cells are 10 | # located. If .sim views are not available but .mag files are, the 11 | # .sim files will be generated automatically. 12 | # 13 | #------------------------------------------------------------ 14 | # Original bdnet2sim.tcl Written by Tim Edwards February 12, 2007 15 | # Modified for Verilog RTL input, Tim Edwards, April 25, 2011 16 | #------------------------------------------------------------ 17 | 18 | set rtlfile [lindex $argv 0] 19 | set cellname [file rootname $rtlfile] 20 | if {"$cellname" == "$rtlfile"} { 21 | set rtlfile ${cellname}.rtl.v 22 | } 23 | 24 | set prefix "" 25 | if {$argc > 2} { 26 | if {[lindex $argv [expr {$argc - 2}]] == "-prefix"} { 27 | set prefix [lindex $argv [expr {$argc - 1}]]/ 28 | incr argc -2 29 | } 30 | } 31 | 32 | if {$argc > 1} { 33 | set magdir [lindex $argv 1] 34 | } else { 35 | set magdir /home/tim/projects/multigig/digital_flow/layout/digital2 36 | } 37 | 38 | if {$argc == 3} { 39 | set simfile [lindex $argv 2] 40 | } else { 41 | set simfile ${cellname}.sim 42 | } 43 | 44 | set scriptdir [file dirname $argv0] 45 | 46 | #------------------------------------------------------------- 47 | # Open files for read and write 48 | 49 | if [catch {open $rtlfile r} fnet] { 50 | puts stderr "Error: can't open file $rtlfile for reading!" 51 | exit 0 52 | } 53 | 54 | #---------------------------------------------------------------- 55 | # First, parse the contents of the RTL file and get a list 56 | # of all macro names used. Use also to get the module name, 57 | # which we will use for the .sim file name. 58 | #---------------------------------------------------------------- 59 | 60 | puts stdout "1st pass of RTL file ${rtlfile}. . ." 61 | flush stdout 62 | 63 | set macrolist {} 64 | while {[gets $fnet line] >= 0} { 65 | if [regexp {^[ \t]*//} $line lmatch] { 66 | # Comment line---do nothing 67 | } elseif [regexp {^module[ \t]+([^ \t]+)[ \t]*\(} $line lmatch cellverify] { 68 | if {"$cellname" != "$cellverify"} { 69 | puts -nonewline stderr "WARNING: MODEL name ${cellverify} does not" 70 | puts stderr " match filename ${cellname}!" 71 | set cellname $cellverify 72 | if {$argc != 3} {set simfile ${cellname}.sim} 73 | } 74 | } elseif [regexp {^[ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]+\(} $line lmatch macro inst] { 75 | if {"$macro" != "module"} { 76 | lappend macrolist $macro 77 | } 78 | } 79 | } 80 | set macrolist [lsort -unique $macrolist] 81 | close $fnet 82 | 83 | set needsims {} 84 | foreach macro $macrolist { 85 | if {[glob -nocomplain ${magdir}/${macro}.sim] == {}} { 86 | lappend needsims ${macro} 87 | } elseif {[file size ${magdir}/${macro}.ext] == 0} { 88 | lappend needsims ${macro} 89 | } 90 | } 91 | 92 | if {$needsims != {}} { 93 | puts stdout "Generating .sim views. . ." 94 | flush stdout 95 | 96 | foreach macro $needsims { 97 | puts stdout "Generating ${macro}.sim" 98 | flush stdout 99 | catch {exec ${scriptdir}/makesim.sh ${magdir}/$macro} 100 | } 101 | } 102 | 103 | if [catch {open $simfile w} fsim] { 104 | puts stderr "Error: can't open file $simfile for writing!" 105 | exit 0 106 | } 107 | 108 | puts $fsim "| SIM file $simfile generated by rtl2sim" 109 | 110 | #---------------------------------------------------------------- 111 | # Procedure to dump the contents of a subcircuit .sim file to the 112 | # top-level .sim file, replacing pin names with net names. 113 | #---------------------------------------------------------------- 114 | 115 | proc dump_sim {fsim mode magdir prefix} { 116 | 117 | # Pick up variable definition from top-level 118 | upvar $mode mname 119 | 120 | # Make VDD, VSS, and GND show up as globals 121 | set mname(VDD) VDD 122 | set mname(VDD!) VDD 123 | set mname(VSS) VSS 124 | set mname(VSS!) VSS 125 | set mname(GND) GND 126 | set mname(GND!) GND 127 | 128 | puts $fsim "| ${mode} $mname(count) = $mname(instance)" 129 | 130 | set fsub [open ${magdir}/${mode}.sim r] 131 | while {[gets $fsub line] >= 0} { 132 | set mtype [string index $line 0] 133 | 134 | # Parse .sim file lines. Ignore lumped "R", which is not used by IRSIM. 135 | 136 | switch -exact $mtype { 137 | n - 138 | p { regexp {^[pn] ([^ ]+) ([^ ]+) ([^ ]+) (.*)} $line valid \ 139 | gate drain source rest 140 | puts -nonewline $fsim "$mtype " 141 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${gate}) "}]} { 142 | puts -nonewline $fsim "${prefix}$mname(instance)/$gate " 143 | } 144 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${drain}) "}]} { 145 | puts -nonewline $fsim "${prefix}$mname(instance)/$drain " 146 | } 147 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${source}) "}]} { 148 | puts -nonewline $fsim "${prefix}$mname(instance)/$source " 149 | } 150 | puts $fsim $rest 151 | } 152 | r { regexp {^r ([^ ]+) ([^ ]+) (.*)} $line valid r1 r2 rest 153 | puts -nonewline $fsim "r " 154 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${r1}) "}]} { 155 | puts -nonewline $fsim "${prefix}$mname(instance)/$r1 " 156 | } 157 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${r2}) "}]} { 158 | puts -nonewline $fsim "${prefix}$mname(instance)/$r2 " 159 | } 160 | puts $fsim $rest 161 | } 162 | C { regexp {^C ([^ ]+) ([^ ]+) (.*)} $line valid top bottom rest 163 | puts -nonewline $fsim "C " 164 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${top}) "}]} { 165 | puts -nonewline $fsim "${prefix}$mname(instance)/$top " 166 | } 167 | if {[catch {puts -nonewline $fsim "${prefix}$mname(${bottom}) "}]} { 168 | puts -nonewline $fsim "${prefix}$mname(instance)/$bottom " 169 | } 170 | puts $fsim $rest 171 | } 172 | | { puts $fsim $line } 173 | } 174 | } 175 | close $fsub 176 | } 177 | 178 | #---------------------------------------------------------------- 179 | # Parse the contents of the RTL file again and dump each cell 180 | # instance to the .sim file output. 181 | 182 | puts stdout "2nd pass of RTL file. . ." 183 | flush stdout 184 | 185 | set fnet [open $rtlfile r] 186 | set mode none 187 | while {[gets $fnet line] >= 0} { 188 | if [regexp {^[ \t]*//} $line lmatch] { 189 | # Comment line---do nothing 190 | } elseif [regexp {^module[ \t]+([^ \t]+)[ \t]*\(} $line lmatch cellverify] { 191 | if {"$cellname" != "$cellverify"} { 192 | puts -nonewline stderr "WARNING: MODEL name ${cellverify} does not" 193 | puts stderr " match filename ${cellname}!" 194 | } 195 | } elseif [regexp {^[ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]+\((.*)$} $line \ 196 | lmatch macroname instname rest] { 197 | # New instance. First dump the current instance to the sim file 198 | if {$mode != "pins" && $mode != "none" && $mode != "wires"} { 199 | dump_sim $fsim $mode $magdir $prefix 200 | } 201 | set mode $macroname 202 | if {[catch {incr ${mode}(count)}]} { 203 | set ${mode}(count) 0 204 | } else { 205 | # Clear pin assignments so that unconnected outputs don't get shorted 206 | # to the last instance 207 | set qcount [set ${mode}(count)] 208 | array unset ${mode} 209 | set ${mode}(count) $qcount 210 | } 211 | set ${mode}(instance) $instname 212 | 213 | # parse "rest" for any pin information on the first line 214 | while {[regexp {[ \t]*.([^(]+)\(([^) \t]+)[ \t]*\),*(.*)$} $rest \ 215 | lmatch pinname netname more] > 0} { 216 | # puts stderr "pin: ${mode}(${pinname}) $netname" 217 | set ${mode}(${pinname}) $netname 218 | set rest $more 219 | } 220 | } elseif [regexp {^endmodule} $line lmatch] { 221 | # Dump last "mode" output 222 | if {$mode != "pins"} { dump_sim $fsim $mode $magdir $prefix} 223 | } elseif [regexp {^[ \t]*input} $line lmatch] { 224 | set mode "pins" 225 | } elseif [regexp {^[ \t]*output} $line lmatch] { 226 | set mode "pins" 227 | } elseif [regexp {^[ \t]*wire} $line lmatch] { 228 | set mode "wires" 229 | } else { 230 | while {[regexp {[ \t]*.([^(]+)\(([^) \t]+)[ \t]*\),*(.*)$} $line \ 231 | lmatch pinname netname rest] > 0} { 232 | # puts stderr "pin: ${mode}(${pinname}) $netname" 233 | set ${mode}(${pinname}) $netname 234 | set line $rest 235 | } 236 | } 237 | } 238 | # Dump the final instance to the sim file, if there was one. 239 | if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix} 240 | close $fnet 241 | 242 | puts stdout "Done!" 243 | --------------------------------------------------------------------------------