├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── examples ├── bsg_concentrate_static │ ├── bsg_concentrate_static.flist │ └── bsg_concentrate_static.v ├── gcd │ ├── gcd.flist │ └── gcd.v └── undefined │ ├── undefined.flist │ └── undefined.v ├── patches ├── pyverilog_add_wirelist_reglist.patch └── pyverilog_sensitivity_comp.patch └── scripts ├── py ├── bsg_ast_add_wrapper_inplace.py ├── bsg_ast_always_at_redux_opt_inplace.py ├── bsg_ast_concat_redux_opt_inplace.py ├── bsg_ast_walk_and_swap_inplace.py ├── bsg_ast_wire_reg_decl_opt_inplace.py ├── bsg_elab_to_rtl.py ├── bsg_generic_modules.py ├── bsg_gtech_modules.py ├── bsg_synthetic_modules.py └── bsg_utility_funcs.py └── tcl ├── filelist_include_to_flist.tcl └── run_dc.tcl /.gitignore: -------------------------------------------------------------------------------- 1 | tools/ 2 | results/ 3 | __pycache__/ 4 | parser.out 5 | parsetab.py 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, The University of Washington 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export TOP_DIR :=$(shell git rev-parse --show-toplevel) 2 | 3 | # Explicitly use bash so we can use the pipefail feature 4 | SHELL :=/bin/bash 5 | 6 | #=============================================================================== 7 | # CAD TOOL SETUP 8 | # 9 | # You can either include a makefile that has the environment setup or you can 10 | # set the variables below to the correct values. The LM_LICENSE_FILE should be 11 | # set to a valid synopsys licenese server and DC_SHELL should point to the 12 | # Synopsys DesignCompiler dc_shell bin. 13 | #=============================================================================== 14 | 15 | # If the machine you are working on is bsg_cadenv complient, then you do not 16 | # need to setup the cad tools, simply put bsg_cadenv in the same root dir. 17 | -include $(TOP_DIR)/../bsg_cadenv/cadenv.mk 18 | 19 | # License file 20 | export LM_LICENSE_FILE ?= 21 | 22 | # DesignCompiler dc_shell binary 23 | export DC_SHELL ?= 24 | export FM_DIR ?= $(FM_RELEASE)/linux64/fm/bin 25 | export FM_SHELL ?= $(FM_DIR)/fm_shell 26 | 27 | #=============================================================================== 28 | # DESIGN SETUP 29 | # 30 | # The DESIGN_NAME variable is used to set the name of the top-level module 31 | # you would like to elaborate in DesignCompiler. 32 | # 33 | # The DESIGN_FILELIST is the path to the filelist object for this design. The 34 | # filelist is responsible for linking all files, include directories, macros 35 | # and top-level parameters for the design. The filelist is a VCS style filelist 36 | # that can contain 5 things: 37 | # 1. Comments -- begging in the # character 38 | # 2. +incdir+ -- adding a search directory for includes 39 | # 3. +define+ -- adding a macro definition at compile time 40 | # 4. -pvalue+ -- top-level parametes 41 | # 5. -- verilog files 42 | # 43 | # The DESIGN_DIRECTORIES_MK is an optional file that is a makefile that gets 44 | # included right before the major steps in the sv2v conversion process. This 45 | # makefile can specify envrionment variables that your DESIGN_FILELIST needs to 46 | # find and link all of the files. 47 | #=============================================================================== 48 | 49 | export DESIGN_NAME ?=gcd 50 | 51 | export DESIGN_FILELIST ?=$(TOP_DIR)/examples/$(DESIGN_NAME)/$(DESIGN_NAME).flist 52 | 53 | export DESIGN_DIRECTORIES_MK ?= 54 | 55 | export DESIGN_CONSTRAINTS_FILE ?= 56 | 57 | export DESIGN_ELAB_NAME ?=$(DESIGN_NAME) 58 | 59 | #=============================================================================== 60 | # ADDITIONAL TOOL SETUP 61 | # 62 | # These are additonal tools that we will need to use this flow. Run 'make 63 | # tools' to download and build these. The additional tools are pretty small 64 | # and should not take to long to build. 65 | #=============================================================================== 66 | 67 | # Additional Tool directories 68 | PYPY3_BUILD_DIR :=$(TOP_DIR)/tools/pypy3 69 | VIRTUALENV_BUILD_DIR :=$(TOP_DIR)/tools/virtual_env 70 | PYVERILOG_BUILD_DIR :=$(TOP_DIR)/tools/pyverilog 71 | IVERILOG_BUILD_DIR :=$(TOP_DIR)/tools/iverilog 72 | 73 | # detect that tools have been built, if our target is not make tools 74 | ifeq (tools,$(MAKECMDGOALS)) 75 | else ifeq (clean,$(MAKECMDGOALS)) 76 | else ifeq (clean_tools,$(MAKECMDGOALS)) 77 | else ifeq (deep_clean,$(MAKECMDGOALS)) 78 | else 79 | ifeq (,$(shell which $(IVERILOG_BUILD_DIR)/ivl)) 80 | $(error "iverilog is missing; see instructions; run make tools") 81 | endif 82 | endif 83 | 84 | # Use these in place for your normal python and pip commands. This will use the 85 | # virtualenv python and pip which has the installed dependancies. 86 | PYTHON :=source $(VIRTUALENV_BUILD_DIR)/bin/activate; python 87 | PIP :=source $(VIRTUALENV_BUILD_DIR)/bin/activate; python -m pip 88 | 89 | # Update path variable as needed 90 | export PATH:=$(PATH):$(IVERILOG_BUILD_DIR)/install/bin 91 | 92 | #=============================================================================== 93 | # MAIN TARGET 94 | #=============================================================================== 95 | 96 | .DEFAULT_GOAL=convert_sv2v 97 | 98 | export OUTPUT_DIR ?=$(CURDIR)/results 99 | export OUTPUT_ELAB_FILE ?=$(OUTPUT_DIR)/$(DESIGN_NAME).elab.v 100 | export OUTPUT_SV2V_FILE ?=$(OUTPUT_DIR)/$(DESIGN_NAME).sv2v.v 101 | 102 | #LOGLVL?=debug 103 | LOGLVL?=info 104 | #LOGLVL?=warning 105 | #LOGLVL?=error 106 | #LOGLVL?=critical 107 | 108 | SV2V_OPTIONS ?= -loglvl $(LOGLVL) 109 | #SV2V_OPTIONS += -no_wire_reg_decl_opt 110 | #SV2V_OPTIONS += -no_always_at_redux_opt 111 | #SV2V_OPTIONS += -no_concat_redux_opt 112 | #SV2V_OPTIONS += -wrapper bsg_top 113 | 114 | convert_sv2v: synth elab_to_rtl 115 | 116 | synth: 117 | mkdir -p $(OUTPUT_DIR) 118 | $(eval -include $(DESIGN_DIRECTORIES_MK)) 119 | set -o pipefail; $(DC_SHELL) -64bit -f $(TOP_DIR)/scripts/tcl/run_dc.tcl 2>&1 | tee -i $(OUTPUT_DIR)/$(DESIGN_NAME).synth.log 120 | touch $(OUTPUT_DIR)/$(DESIGN_NAME).elab.v.sdc 121 | 122 | elab_to_rtl: 123 | mkdir -p $(OUTPUT_DIR) 124 | $(eval -include $(DESIGN_DIRECTORIES_MK)) 125 | $(PYTHON) $(TOP_DIR)/scripts/py/bsg_elab_to_rtl.py -i $(OUTPUT_ELAB_FILE) -o $(OUTPUT_SV2V_FILE) $(SV2V_OPTIONS) 2>&1 | tee -i $(OUTPUT_DIR)/$(DESIGN_NAME).elab_to_rtl.log 126 | cp $(OUTPUT_DIR)/$(DESIGN_NAME).elab.v.sdc $(OUTPUT_DIR)/$(DESIGN_NAME).sv2v.v.sdc 127 | sed -i -e 's/^#.*$$//g' $(OUTPUT_DIR)/$(DESIGN_NAME).sv2v.v.sdc 128 | sed -i -e '/^$$/d' $(OUTPUT_DIR)/$(DESIGN_NAME).sv2v.v.sdc 129 | 130 | help: 131 | $(PYTHON) $(TOP_DIR)/scripts/py/bsg_elab_to_rtl.py -h 132 | 133 | #=============================================================================== 134 | # TOOLS 135 | #=============================================================================== 136 | 137 | tools: $(IVERILOG_BUILD_DIR) $(PYPY3_BUILD_DIR) $(VIRTUALENV_BUILD_DIR) $(PYVERILOG_BUILD_DIR) 138 | 139 | $(IVERILOG_BUILD_DIR): 140 | mkdir -p $(@D) 141 | git clone https://github.com/steveicarus/iverilog.git $@ 142 | cd $@; git checkout v10_3 143 | cd $@; sh autoconf.sh 144 | cd $@; ./configure --prefix=$@/install 145 | cd $@; make -j4 146 | cd $@; make install 147 | 148 | $(PYPY3_BUILD_DIR): 149 | mkdir -p $@/download 150 | #cd $@/download; wget https://downloads.python.org/pypy/pypy3.7-v7.3.2-linux64.tar.bz2 151 | cd $@/download; wget https://downloads.python.org/pypy/pypy3.6-v7.3.2-linux64.tar.bz2 152 | cd $@; tar xvf download/pypy3.6-v7.3.2-linux64.tar.bz2 153 | cd $@; mv pypy3.6-v7.3.2-linux64/* . 154 | cd $@; rmdir pypy3.6-v7.3.2-linux64/ 155 | 156 | $(VIRTUALENV_BUILD_DIR): $(PYPY3_BUILD_DIR) 157 | mkdir -p $(@D) 158 | virtualenv -p $(PYPY3_BUILD_DIR)/bin/pypy3 $@ 159 | $(PIP) install --upgrade setuptools 160 | $(PIP) install jinja2 pytest pytest-pythonpath 161 | 162 | $(PYVERILOG_BUILD_DIR): $(VIRTUALENV_BUILD_DIR) $(IVERILOG_BUILD_DIR) 163 | mkdir -p $(@D) 164 | git clone https://github.com/PyHDI/Pyverilog.git $@ 165 | cd $@; git checkout 1.1.3 166 | cd $@; git apply $(TOP_DIR)/patches/pyverilog_add_wirelist_reglist.patch 167 | cd $@; git apply $(TOP_DIR)/patches/pyverilog_sensitivity_comp.patch 168 | cd $@; $(PYTHON) setup.py install 169 | 170 | clean_tools: 171 | rm -rf $(PYPY3_BUILD_DIR) 172 | rm -rf $(VIRTUALENV_BUILD_DIR) 173 | rm -rf $(PYVERILOG_BUILD_DIR) 174 | rm -rf $(IVERILOG_BUILD_DIR) 175 | 176 | 177 | 178 | # invoke shell which has all of the cad tools active 179 | shell: 180 | PS1="[cadenv> \u \w] " /bin/bash 181 | 182 | # print out makefile variable 183 | %.echo: 184 | @echo $($*) 185 | 186 | # standalone helper rule to run formality against two copies 187 | # TODO: support file list and more deeply integrate 188 | # make @@second file>.formality 189 | # examples: 190 | # make ./examples/div_9/div_9.v@div_9@results/div_9.sv2v.v.formality 191 | # make examples/test_signed/test_signed.v@test_signed@results/test_signed.sv2v.v.formality 192 | %.formality: 193 | echo "read_sverilog -r $(word 1,$(subst @, ,$*)); set_top $(word 2,$(subst @, ,$*)); read_sverilog -i $(word 3,$(subst @, ,$*)); set_top $(word 2,$(subst @, ,$*)); verify" | \ 194 | SYNOPSYS=$(FM_RELEASE) $(FM_SHELL) 195 | 196 | #=============================================================================== 197 | # CLEAN UP 198 | #=============================================================================== 199 | 200 | deep_clean: clean_tools clean 201 | 202 | clean: 203 | rm -rf $(OUTPUT_DIR) 204 | rm -rf __pycache__ 205 | rm -f parser.out parsetab.py 206 | 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BSG SystemVerilog to Verilog (SV2V) 2 | 3 | BSG SV2V takes a hardware design written in SystemVerilog and converts it into 4 | a single HDL file that is Verilog-2005 compliant. The Verilog-2005 standard is 5 | compatible with a much wider variety of CAD tools, thus this converter can help 6 | bridge the gap between code bases employing advanced synthesizable 7 | SystemVerilog features and older or less sophisticated tools. 8 | 9 | The tool uses Synopsys Design Compiler (DC) to perform elaboration of the 10 | design, and then post-processes to map DC's gtech/generic/datapath 11 | representation back to standard Verilog. Thus a DC license is required by the 12 | party running the tool, but is not required to use the converted file. 13 | 14 | This approach maximizes compatibility with code that was written and targets 15 | DC. Of course it would also be neat if somebody wrote a totally open source SV 16 | to V! 17 | 18 | Here is a [Youtube Demo](https://youtu.be/H3p5hwI8WR0). 19 | 20 | ## Setup 21 | 22 | For this converter, you will need Synopsys Design Compiler installed (verified 23 | on version M-2016.12-SP5-5) and access to a valid license file. If you have 24 | access to *bsg_cadenv* and it is setup for the machine you are working on, then 25 | you can simply clone *bsg_sv2v* and *bsg_cadenv* into the same directory and 26 | the CAD tools should be setup automatically to run on our machines. For all 27 | other users, you should open the Makefile in the root of the repository and set 28 | the following two variables: 29 | 30 | ``` 31 | export LM_LICENSE_FILE ?= 32 | ``` 33 | 34 | ``` 35 | export DC_SHELL ?= 36 | ``` 37 | 38 | The BSG SV2V converter also depends on 39 | [Icarus Verilog](http://iverilog.icarus.com/), 40 | [Pyverilog](https://pypi.org/project/pyverilog/), and 41 | [pypy](https://pypy.org/). To download and build these tools, simply run: 42 | 43 | ``` 44 | $ make tools 45 | ``` 46 | 47 | ## Usage 48 | 49 | ### Design Filelist 50 | 51 | To use the BSG SV2V converter flow, first you must first create a filelist. The 52 | filelist is the main way of linking together all of the bits to elaborate the 53 | design. The format of the filelist is fairly basic and is based on Synopsys VCS 54 | filelists. Each line in the filelist can be 1 of 5 things: 55 | 56 | - A comments starting with the `#` character 57 | - A macro definition in the format `+define+NAME=VALUE` 58 | - A top-level parameter definition in the format `-pvalue+NAME=VALUE` 59 | - An include search directory in the format `+incdir+DIRECTORY` 60 | - An HDL file path (no format, just the file path) 61 | 62 | You may also use environment variables inside the filelist by using the `$` 63 | character followed by the name of the environment variable. 64 | 65 | Below is a mock filelist as an example: 66 | 67 | ```bash 68 | ### My Design Filelist 69 | # Macros 70 | +define+SYNTHESIS 71 | +define+DEBUG=0 72 | # Parameters 73 | -pvalue+data_width=32 74 | # Search paths 75 | +incdir+$INCLUDE_DIR/vh/ 76 | +incdir+$INCLUDE_DIR/pkgs/ 77 | # Files 78 | $SRC_DIR/top.v 79 | $SRC_DIR/sub_design/file1.v 80 | $SRC_DIR/sub_design/file2.v 81 | $SRC_DIR/sub_design/file3.v 82 | ``` 83 | 84 | ### Running the Flow 85 | 86 | Now that you have setup the tools and created a design filelist, you are ready 87 | to run the flow! The main target is: 88 | 89 | ``` 90 | $ make convert_sv2v DESIGN_NAME= DESIGN_FILELIST= DESIGN_DIRECTORIES_MK= 91 | ``` 92 | 93 | If you'd prefer, you can modify the Makefile and set `DESIGN_NAME`, 94 | `DESIGN_FILELIST`, and `DESIGN_DIRECTORIES_MK` rather than specifying them as 95 | part of the makefile target. `DESIGN_NAME` should be set to the name of the 96 | toplevel module in the design and `DESIGN_FILELIST` should be the filelist for 97 | the design discussed in the previous section. `DESIGN_DIRECTORIES_MK` is 98 | optional and can point to a makefile fragment that can setup environment 99 | variables for use inside the design filelist. 100 | 101 | This command will first launch Synopsys Design Compiler and elaborate the 102 | design. It will then call a python script that will take the elaborated design 103 | and turn it back into synthesizable RTL that is Verilog-05 compatible. All 104 | output files can be found in the `results` directory. The main converted file 105 | will be in: 106 | 107 | ``` 108 | ./results/${DESIGN_NAME}.sv2v.v 109 | ``` 110 | 111 | ### Example 112 | 113 | A very simple example has been include in the `examples` directory. To test out 114 | the example, run: 115 | 116 | ``` 117 | $ make convert_sv2v DESIGN_NAME=gcd DESIGN_FILELIST=examples/gcd/gcd.flist 118 | ``` 119 | 120 | To see the converted file, run: 121 | 122 | ``` 123 | $ cat ./results/gcd.sv2v.v 124 | ``` 125 | 126 | ### Log Level 127 | 128 | The `bsg_elab_to_rtl.py` script logs various information throughout the process 129 | of converting the DC elaborated netlist to RTL. By default, the logger level is 130 | set to `info` however you can change the log level. Available options are `debug`, 131 | `info`,`warning`,`error`, and `critical`. Inside of the Makefile, you can set the 132 | `LOGLVL` variable to the logging level desired. 133 | 134 | ### Optimization Passes 135 | 136 | As part of the BSG SV2V flow, after all components have been swapped with their RTL 137 | equivalents, additional passes of the netlist are performed to try and cleanup and 138 | optimize the netlist. By default, every optimization pass is enabled, however every 139 | optimization pass can be disabled using flags passed to the `bsg_elab_to_rtl.py` 140 | script. In the Makefile, you can add these flags to the `SV2V_OPTIONS` variable to 141 | disable these optimizations. 142 | 143 | | Optimization Name | Disable Flag | Description | 144 | |:--------------------:|:----------------------:|:-------------------------------------------------------------------------------------------------------------------| 145 | | Wire/Reg Declaration | no_wire_reg_decl_opt | Takes individual wire and reg declarations and combines them into comma separated multi-variable declarations. | 146 | | Always@ Reduction | no_always_at_redux_opt | Squashes always@ blocks based on sensitivity lists and conditional statements. | 147 | | Concat Reduction | no_concat_redux_opt | Squashes bits in large concats that share the same base bus name. | 148 | 149 | ### Adding Wrapper Module 150 | 151 | BSG SV2V supports adding a wrapper module for the toplevel by using the 152 | optional `-wrapper ` flag (where `` is the wrapper module name). 153 | This can be useful when using BSG SV2V in other infrastructure where you would 154 | like to control the toplevel module name. To determine which module is the 155 | toplevel that should be wrapper, the user must define the `DESIGN_NAME` 156 | environment variable. You can also add the `-wrapper` flag to the 157 | `SV2V_OPTIONS` variable inside the Makefile. 158 | 159 | ### Converting Timing Constraints 160 | 161 | BSG SV2V can also take an optional tcl or sdc file that will then be applied to 162 | the design and written back out as an SDC file that has been fully expanded to 163 | the given design (for example: if the folloing timing constraint is applied: 164 | `set_output_delay 10 -clock clk [all_outputs]` the the resulting output SDC 165 | file will expand that constraint such that every output port for the design has 166 | a `set_output_delay` command. To specify a constraint file to convert, set the 167 | `DESIGN_CONSTRAINTS_FILE` variable inside the Makefile or set the variable at 168 | runtime using the following syntax: 169 | 170 | ``` 171 | $ make convert_sv2v DESIGN_CONSTRAINTS_FILE= 172 | ``` 173 | 174 | ### Elaborating a Different Top-level Module 175 | 176 | When dealing with hierarchical designs, it can some be useful to elaborate the 177 | design higher up the logical hierarchy than the point that you are acutally 178 | interested in (ie. the design being converted). This is primarily useful to 179 | push parameters from higher up the hierarchy. To specify a different point to 180 | elaborate, set the `DESIGN_ELAB_NAME` variable inside the Makefile or set the 181 | variable at runtime using the following syntax: 182 | 183 | ``` 184 | $ make convert_sv2v DESIGN_ELAB_NAME= 185 | ``` 186 | 187 | Note: the point that you elaborate from must instantiate an instance of the 188 | `DESIGN_NAME` module. Said another way, it must be higher up the local 189 | hierarchy. Also, every instances of `DESIGN_NAME` must have the same 190 | parameterization as there is no way to disambiguous which parameterization you 191 | are interested in converting. 192 | 193 | -------------------------------------------------------------------------------- /examples/bsg_concentrate_static/bsg_concentrate_static.flist: -------------------------------------------------------------------------------- 1 | # Parameters 2 | 3 | # Verilog Files 4 | $TOP_DIR/examples/bsg_concentrate_static/bsg_concentrate_static.v 5 | -------------------------------------------------------------------------------- /examples/bsg_concentrate_static/bsg_concentrate_static.v: -------------------------------------------------------------------------------- 1 | `ifdef SYNTHESIS 2 | `define BSG_UNDEFINED_IN_SIM(val) (val) 3 | `else 4 | `define BSG_UNDEFINED_IN_SIM(val) ('X) 5 | `endif 6 | 7 | // using C-style shifts instead of a[i] allows the parameter of BSG_GET_BIT to be a parameter subrange 8 | // e.g., parameter[4:1][1], which DC 2016.12 does not allow 9 | 10 | `define BSG_GET_BIT(Y,NUM) (((Y)>>(NUM))&1'b1) 11 | 12 | // this version of countones works in synthesis, but only up to 64 bits 13 | // we do a funny thing where we propagate X's in simulation if it is more than 64 bits 14 | // and in synthesis, we go ahead and use the good function, knowing that it will error if still unsupported 15 | 16 | `define BSG_COUNTONES_SYNTH(y) (($bits(y) < 65) ? 1'b0 : `BSG_UNDEFINED_IN_SIM(1'b0)) + (`BSG_GET_BIT(y,0) +`BSG_GET_BIT(y,1) +`BSG_GET_BIT(y,2) +`BSG_GET_BIT(y,3) +`BSG_GET_BIT(y,4) +`BSG_GET_BIT(y,5) +`BSG_GET_BIT(y,6)+`BSG_GET_BIT(y,7) +`BSG_GET_BIT(y,18)+`BSG_GET_BIT(y,9) \ 17 | +`BSG_GET_BIT(y,10)+`BSG_GET_BIT(y,11)+`BSG_GET_BIT(y,12)+`BSG_GET_BIT(y,13)+`BSG_GET_BIT(y,14)+`BSG_GET_BIT(y,15)+`BSG_GET_BIT(y,16)+`BSG_GET_BIT(y,17)+`BSG_GET_BIT(y,18)+`BSG_GET_BIT(y,19) \ 18 | +`BSG_GET_BIT(y,20)+`BSG_GET_BIT(y,21)+`BSG_GET_BIT(y,22)+`BSG_GET_BIT(y,23)+`BSG_GET_BIT(y,24)+`BSG_GET_BIT(y,25)+`BSG_GET_BIT(y,26)+`BSG_GET_BIT(y,27)+`BSG_GET_BIT(y,28)+`BSG_GET_BIT(y,29) \ 19 | +`BSG_GET_BIT(y,30)+`BSG_GET_BIT(y,31)+`BSG_GET_BIT(y,32)+`BSG_GET_BIT(y,33)+`BSG_GET_BIT(y,34)+`BSG_GET_BIT(y,35)+`BSG_GET_BIT(y,36)+`BSG_GET_BIT(y,37)+`BSG_GET_BIT(y,38)+`BSG_GET_BIT(y,39) \ 20 | +`BSG_GET_BIT(y,40)+`BSG_GET_BIT(y,41)+`BSG_GET_BIT(y,42)+`BSG_GET_BIT(y,43)+`BSG_GET_BIT(y,44)+`BSG_GET_BIT(y,45)+`BSG_GET_BIT(y,46)+`BSG_GET_BIT(y,47)+`BSG_GET_BIT(y,48)+`BSG_GET_BIT(y,49) \ 21 | +`BSG_GET_BIT(y,50)+`BSG_GET_BIT(y,51)+`BSG_GET_BIT(y,52)+`BSG_GET_BIT(y,53)+`BSG_GET_BIT(y,54)+`BSG_GET_BIT(y,55)+`BSG_GET_BIT(y,56)+`BSG_GET_BIT(y,57)+`BSG_GET_BIT(y,58)+`BSG_GET_BIT(y,59) \ 22 | +`BSG_GET_BIT(y,60)+`BSG_GET_BIT(y,61)+`BSG_GET_BIT(y,62)+`BSG_GET_BIT(y,63)) 23 | 24 | 25 | module bsg_concentrate_static #(parameter width_p=3, pattern_els_p=5'b10101) 26 | (input [width_p-1:0] i 27 | ,output [$bits(pattern_els_p)-1:0] o 28 | ); 29 | genvar j; 30 | 31 | if (pattern_els_p[0]) 32 | assign o[0] = i[0]; 33 | else 34 | assign o[0] = 'z; 35 | 36 | for (j = 1; j < $bits(pattern_els_p); j=j+1) 37 | begin: rof 38 | if (pattern_els_p[j]) 39 | assign o[j] = i[`BSG_COUNTONES_SYNTH(pattern_els_p[j-1:0])]; 40 | else 41 | assign o[j] = 'z; 42 | end 43 | 44 | endmodule 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/gcd/gcd.flist: -------------------------------------------------------------------------------- 1 | # Parameters 2 | -pvalue+width_p=32 3 | # Verilog Files 4 | $TOP_DIR/examples/gcd/gcd.v 5 | -------------------------------------------------------------------------------- /examples/gcd/gcd.v: -------------------------------------------------------------------------------- 1 | module gcd #( parameter width_p="inv" ) 2 | (input clk_i 3 | ,input reset_i 4 | ,input en_i 5 | 6 | ,input v_i 7 | ,input [width_p-1:0] a_i 8 | ,input [width_p-1:0] b_i 9 | ,output logic ready_o 10 | 11 | ,output logic v_o 12 | ,output logic [width_p-1:0] data_o 13 | ,input yumi_i 14 | ); 15 | 16 | typedef enum logic [1:0] {eWAIT, eCALC, eDONE} state_e; 17 | 18 | state_e state_n, state_r; 19 | logic [width_p-1:0] a_n, a_r; 20 | logic [width_p-1:0] b_n, b_r; 21 | 22 | wire a_less_than_b = (a_r < b_r); 23 | 24 | wire b_not_equal_zero = (b_r != 0); 25 | 26 | wire [width_p-1:0] a_minus_b = (a_r - b_r); 27 | 28 | always_comb 29 | begin 30 | state_n = state_r; 31 | if ((state_r == eWAIT) & v_i) 32 | state_n = eCALC; 33 | else if ((state_r == eCALC) & ~a_less_than_b & !b_not_equal_zero) 34 | state_n = eDONE; 35 | else if ((state_r == eDONE) & yumi_i) 36 | state_n = eWAIT; 37 | end 38 | 39 | always_ff @(posedge clk_i) 40 | begin 41 | if (reset_i) begin 42 | state_r <= eWAIT; 43 | end else begin 44 | state_r <= state_n; 45 | end 46 | end 47 | 48 | always_comb 49 | begin 50 | if (state_r == eWAIT) begin 51 | a_n = a_i; 52 | b_n = b_i; 53 | end else if ((state_r == eCALC) & a_less_than_b) begin 54 | a_n = b_r; 55 | b_n = a_r; 56 | end else if ((state_r == eCALC) & b_not_equal_zero) begin 57 | a_n = a_minus_b; 58 | b_n = b_r; 59 | end else begin 60 | a_n = a_r; 61 | b_n = b_r; 62 | end 63 | end 64 | 65 | always_ff @(posedge clk_i) 66 | begin 67 | a_r <= a_n; 68 | b_r <= b_n; 69 | end 70 | 71 | assign ready_o = state_r == eWAIT; 72 | assign v_o = state_r == eDONE; 73 | assign data_o = a_r; 74 | 75 | endmodule 76 | 77 | -------------------------------------------------------------------------------- /examples/undefined/undefined.flist: -------------------------------------------------------------------------------- 1 | # Parameters 2 | #-pvalue+val_p=32 3 | # Verilog Files 4 | $TOP_DIR/examples/undefined/undefined.v 5 | -------------------------------------------------------------------------------- /examples/undefined/undefined.v: -------------------------------------------------------------------------------- 1 | `ifdef SYNTHESIS 2 | `define BSG_UNDEFINED_IN_SIM(val) (val) 3 | 4 | `else 5 | `define BSG_UNDEFINED_IN_SIM(val) ('X) 6 | `endif 7 | 8 | module undefined #(val_p=`BSG_UNDEFINED_IN_SIM(7)) (output [31:0] o); 9 | 10 | assign o = val_p; 11 | 12 | endmodule 13 | -------------------------------------------------------------------------------- /patches/pyverilog_add_wirelist_reglist.patch: -------------------------------------------------------------------------------- 1 | From 1821e0d7a39e1eb2caccd425241d22fef316b757 Mon Sep 17 00:00:00 2001 2 | From: Scott Davidson 3 | Date: Fri, 29 Mar 2019 18:27:22 -0700 4 | Subject: [PATCH 1/2] Adding WireList and RegList ast classes. Used for codegen 5 | only, parser does not use them/ 6 | 7 | --- 8 | pyverilog/ast_code_generator/codegen.py | 23 ++++++++++++++++++++ 9 | pyverilog/ast_code_generator/list_ast.txt | 2 ++ 10 | pyverilog/ast_code_generator/template/reglist.txt | 1 + 11 | pyverilog/ast_code_generator/template/wirelist.txt | 1 + 12 | pyverilog/vparser/ast.py | 25 ++++++++++++++++++++++ 13 | 5 files changed, 52 insertions(+) 14 | create mode 100644 pyverilog/ast_code_generator/template/reglist.txt 15 | create mode 100644 pyverilog/ast_code_generator/template/wirelist.txt 16 | 17 | diff --git a/pyverilog/ast_code_generator/codegen.py b/pyverilog/ast_code_generator/codegen.py 18 | index 7158a02..b1a9a4f 100644 19 | --- a/pyverilog/ast_code_generator/codegen.py 20 | +++ b/pyverilog/ast_code_generator/codegen.py 21 | @@ -1022,3 +1022,26 @@ class ASTCodeGenerator(ConvertVisitor): 22 | 23 | def visit_EmbeddedCode(self, node): 24 | return node.code 25 | + 26 | + def visit_WireList(self, node): 27 | + filename = getfilename(node) 28 | + template = self.get_template(filename) 29 | + template_dict = { 30 | + 'name_str' : ','.join([escape(name) for name in node.name_list]), 31 | + 'width' : '' if node.width is None else self.visit(node.width), 32 | + 'signed' : node.signed, 33 | + } 34 | + rslt = template.render(template_dict) 35 | + return rslt 36 | + 37 | + def visit_RefList(self, node): 38 | + filename = getfilename(node) 39 | + template = self.get_template(filename) 40 | + template_dict = { 41 | + 'name_str' : ','.join([escape(name) for name in node.name_list]), 42 | + 'width' : '' if node.width is None else self.visit(node.width), 43 | + 'signed' : node.signed, 44 | + } 45 | + rslt = template.render(template_dict) 46 | + return rslt 47 | + 48 | diff --git a/pyverilog/ast_code_generator/list_ast.txt b/pyverilog/ast_code_generator/list_ast.txt 49 | index 2fd9a6f..f23cfbb 100644 50 | --- a/pyverilog/ast_code_generator/list_ast.txt 51 | +++ b/pyverilog/ast_code_generator/list_ast.txt 52 | @@ -103,3 +103,5 @@ PragmaEntry 53 | Disable 54 | ParallelBlock 55 | SingleStatement 56 | +WireList 57 | +RegList 58 | diff --git a/pyverilog/ast_code_generator/template/reglist.txt b/pyverilog/ast_code_generator/template/reglist.txt 59 | new file mode 100644 60 | index 0000000..016a488 61 | --- /dev/null 62 | +++ b/pyverilog/ast_code_generator/template/reglist.txt 63 | @@ -0,0 +1 @@ 64 | +reg {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str|wordwrap(100) }}; 65 | diff --git a/pyverilog/ast_code_generator/template/wirelist.txt b/pyverilog/ast_code_generator/template/wirelist.txt 66 | new file mode 100644 67 | index 0000000..36423c9 68 | --- /dev/null 69 | +++ b/pyverilog/ast_code_generator/template/wirelist.txt 70 | @@ -0,0 +1 @@ 71 | +wire {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str|wordwrap(100) }}; 72 | diff --git a/pyverilog/vparser/ast.py b/pyverilog/vparser/ast.py 73 | index 9c5a315..98807d4 100644 74 | --- a/pyverilog/vparser/ast.py 75 | +++ b/pyverilog/vparser/ast.py 76 | @@ -840,3 +840,28 @@ class EmbeddedCode(Node): 77 | def children(self): 78 | nodelist = [] 79 | return tuple(nodelist) 80 | + 81 | +class WireList(Node): 82 | + attr_names = ('name_list', 'signed') 83 | + def __init__(self, name_list, width=None, signed=False, lineno=0): 84 | + self.lineno = lineno 85 | + self.name_list = name_list 86 | + self.width = width 87 | + self.signed = signed 88 | + def children(self): 89 | + nodelist = [] 90 | + if self.width: nodelist.append(self.width) 91 | + return tuple(nodelist) 92 | + 93 | +class RegList(Node): 94 | + attr_names = ('name_list', 'signed') 95 | + def __init__(self, name_list, width=None, signed=False, lineno=0): 96 | + self.lineno = lineno 97 | + self.name_list = name_list 98 | + self.width = width 99 | + self.signed = signed 100 | + def children(self): 101 | + nodelist = [] 102 | + if self.width: nodelist.append(self.width) 103 | + return tuple(nodelist) 104 | + 105 | -- 106 | 1.8.3.1 107 | 108 | 109 | From da8f10f6e499c8b3821c89cce4c4f823e5cb310f Mon Sep 17 00:00:00 2001 110 | From: Scott Davidson 111 | Date: Sat, 30 Mar 2019 08:39:52 -0700 112 | Subject: [PATCH 2/2] Bug fixes 113 | 114 | --- 115 | pyverilog/ast_code_generator/codegen.py | 16 +++++++++++++--- 116 | pyverilog/ast_code_generator/template/reglist.txt | 2 +- 117 | pyverilog/ast_code_generator/template/wirelist.txt | 2 +- 118 | 3 files changed, 15 insertions(+), 5 deletions(-) 119 | 120 | diff --git a/pyverilog/ast_code_generator/codegen.py b/pyverilog/ast_code_generator/codegen.py 121 | index b1a9a4f..8de6e20 100644 122 | --- a/pyverilog/ast_code_generator/codegen.py 123 | +++ b/pyverilog/ast_code_generator/codegen.py 124 | @@ -1026,19 +1026,29 @@ class ASTCodeGenerator(ConvertVisitor): 125 | def visit_WireList(self, node): 126 | filename = getfilename(node) 127 | template = self.get_template(filename) 128 | + name_str = ','.join([escape(name) for name in node.name_list]) 129 | + for i in range(int(len(name_str)/80)): 130 | + start_index = (i+1)*80 + i 131 | + comma_index = name_str.rfind(',',0,start_index) 132 | + name_str = name_str[:comma_index+1] + '\n' + name_str[comma_index+1:] 133 | template_dict = { 134 | - 'name_str' : ','.join([escape(name) for name in node.name_list]), 135 | + 'name_str' : name_str, 136 | 'width' : '' if node.width is None else self.visit(node.width), 137 | 'signed' : node.signed, 138 | } 139 | rslt = template.render(template_dict) 140 | return rslt 141 | 142 | - def visit_RefList(self, node): 143 | + def visit_RegList(self, node): 144 | filename = getfilename(node) 145 | template = self.get_template(filename) 146 | + name_str = ','.join([escape(name) for name in node.name_list]) 147 | + for i in range(int(len(name_str)/80)): 148 | + start_index = (i+1)*80 + i 149 | + comma_index = name_str.rfind(',',0,start_index) 150 | + name_str = name_str[:comma_index+1] + '\n' + name_str[comma_index+1:] 151 | template_dict = { 152 | - 'name_str' : ','.join([escape(name) for name in node.name_list]), 153 | + 'name_str' : name_str, 154 | 'width' : '' if node.width is None else self.visit(node.width), 155 | 'signed' : node.signed, 156 | } 157 | diff --git a/pyverilog/ast_code_generator/template/reglist.txt b/pyverilog/ast_code_generator/template/reglist.txt 158 | index 016a488..9e21dcb 100644 159 | --- a/pyverilog/ast_code_generator/template/reglist.txt 160 | +++ b/pyverilog/ast_code_generator/template/reglist.txt 161 | @@ -1 +1 @@ 162 | -reg {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str|wordwrap(100) }}; 163 | +reg {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str }}; 164 | diff --git a/pyverilog/ast_code_generator/template/wirelist.txt b/pyverilog/ast_code_generator/template/wirelist.txt 165 | index 36423c9..8058ff7 100644 166 | --- a/pyverilog/ast_code_generator/template/wirelist.txt 167 | +++ b/pyverilog/ast_code_generator/template/wirelist.txt 168 | @@ -1 +1 @@ 169 | -wire {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str|wordwrap(100) }}; 170 | +wire {% if signed %}signed {% endif %}{% if width != '' %}{{ width }} {% endif %}{{ name_str }}; 171 | -- 172 | 1.8.3.1 173 | 174 | -------------------------------------------------------------------------------- /patches/pyverilog_sensitivity_comp.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pyverilog/vparser/ast.py b/pyverilog/vparser/ast.py 2 | index 9c5a315..a7c9997 100644 3 | --- a/pyverilog/vparser/ast.py 4 | +++ b/pyverilog/vparser/ast.py 5 | @@ -42,6 +42,7 @@ class Node(object): 6 | other_attrs = tuple( [ getattr(other, a) for a in other.attr_names ] ) 7 | if self_attrs != other_attrs: return False 8 | other_children = other.children() 9 | + if len(self.children()) != len(other_children): return False 10 | for i, c in enumerate(self.children()): 11 | if c != other_children[i]: return False 12 | return True 13 | -------------------------------------------------------------------------------- /scripts/py/bsg_ast_add_wrapper_inplace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ast_add_wrapper_inplace.py 3 | 4 | This file contains the ast_add_wrapper_inplace function which walks through an 5 | ast and finds the toplevel module and adds a new module that wraps the 6 | instantiation of that module. This allows you to "rename" the toplevel module. 7 | To determine which module is the toplevel that should be wrapped, the 8 | DESIGN_NAME environment variable must be set. 9 | ''' 10 | 11 | import inspect 12 | import logging 13 | import copy 14 | import os 15 | 16 | from pyverilog.vparser.ast import * 17 | 18 | def ast_add_wrapper_inplace( node, parent, name ): 19 | 20 | ### Check for the design name env var 21 | if 'DESIGN_NAME' not in os.environ: 22 | logging.warning('Must set the DESIGN_NAME environment variable to the toplevel module name to create a wrapper. Skipping!') 23 | return 24 | 25 | ### Handle module definitions (only care for the first one, no recursion here) 26 | if type(node) == ModuleDef and node.name == os.environ['DESIGN_NAME']: 27 | nodeCopy = copy.deepcopy(node) 28 | nodeCopy.name = name 29 | nodeCopy.items = [] 30 | for item in node.items: 31 | if type(item) == Decl: 32 | assert len(item.list) == 1 33 | if type(item.list[0]) == Output or type(item.list[0]) == Input: 34 | nodeCopy.items.append(item.list[0]) 35 | ports = [PortArg(p.name,Rvalue(Value(p.name))) for p in nodeCopy.items] 36 | inst = Instance(node.name, "wrapper", ports, []) 37 | nodeCopy.items.append(InstanceList(node.name, [], [inst])) 38 | parent.definitions = (nodeCopy,) + parent.definitions 39 | 40 | ### Recursivly walk down all other nodes 41 | else: 42 | for c in node.children(): 43 | ast_add_wrapper_inplace(c,node,name) 44 | 45 | -------------------------------------------------------------------------------- /scripts/py/bsg_ast_always_at_redux_opt_inplace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_ast_always_at_redux_opt_inplace.py 3 | 4 | This optimization pass will go through all of the always at statements created 5 | by converting SEQGEN cells to RTL and reduce the AST complexity. Primarily, it 6 | is going to squash always blocks with the same sensitivity lists and merge if 7 | statements within the always block that are based on the same conditions. It 8 | also searches through all the non-blocking assignments in the block and combine 9 | assignments for multi-bit buses. It does so by creating a large concat on the 10 | left and right of the non-blocking assignment. After this pass, it is suggested 11 | to run the concat_redux_pass_inplace optimization to reform buses in the 12 | non-blocking assignments. 13 | ''' 14 | 15 | import logging 16 | 17 | from pyverilog.vparser.ast import * 18 | 19 | # ast_always_at_redux_opt_inplace( node ) 20 | # 21 | # Main optimization pass. This will go through the whole AST and find always 22 | # blocks from SEQGEN cells. It will combine sensitivity lists and if-statements 23 | # within an always block. It will then try and reduce the block complexity 24 | # inside each if-statement case by collapsing non-blocking assignments to the 25 | # same bus into a single non-blocking assignment with a concat on the left and 26 | # right to make for further optimization later (primarily from the 27 | # concat_redux_pass_inplace). 28 | # 29 | def ast_always_at_redux_opt_inplace( node ): 30 | 31 | ### Stop at the module, the items list will have the always blocks 32 | 33 | if type(node) == ModuleDef: 34 | 35 | dont_touch_items = list() 36 | always_blocks = list() 37 | 38 | ### Get all the always blocks 39 | 40 | for item in node.items: 41 | if type(item) == Always: 42 | always_blocks.append(item) 43 | else: 44 | dont_touch_items.append(item) 45 | 46 | ### Combine like sens lists 47 | 48 | top_index = 0 49 | while top_index < len(always_blocks): 50 | a = always_blocks[top_index] 51 | bot_index = top_index + 1 52 | while bot_index < len(always_blocks): 53 | if a.sens_list == always_blocks[bot_index].sens_list: 54 | a.statement.statements.extend(always_blocks.pop(bot_index).statement.statements) 55 | else: 56 | bot_index += 1 57 | top_index += 1 58 | 59 | ### Combine like if statemets and squash them 60 | 61 | for a in always_blocks: 62 | top_index = 0 63 | while top_index < len(a.statement.statements): 64 | bot_index = top_index + 1 65 | while bot_index < len(a.statement.statements): 66 | top_ifstmt = a.statement.statements[top_index] 67 | bot_ifstmt = a.statement.statements[bot_index] 68 | if __if_statement_eq(top_ifstmt, bot_ifstmt): 69 | a.statement.statements[top_index] = __merge_if_statements(top_ifstmt,bot_ifstmt) 70 | a.statement.statements.pop(bot_index) 71 | else: 72 | bot_index += 1 73 | __squash_if_statement_inplace(a.statement.statements[top_index]) 74 | top_index += 1 75 | 76 | node.items = dont_touch_items + always_blocks 77 | 78 | ### Recursivly walk down all other nodes 79 | 80 | else: 81 | for c in node.children(): 82 | ast_always_at_redux_opt_inplace(c) 83 | 84 | # __merge_if_statements( ifstmt1, ifstmt2 ) 85 | # 86 | # Take the ast for two if statements and merge the block for each conditional 87 | # case. We have an invarient which is that ifstmt1 equals ifstmt2 (based on 88 | # the return of __if_statement_eq(...) function). 89 | # 90 | def __merge_if_statements( ifstmt1, ifstmt2 ): 91 | 92 | # Merge false case 93 | if type(ifstmt1.false_statement) == IfStatement: 94 | merged_false = __merge_if_statements(ifstmt1.false_statement, ifstmt2.false_statement) 95 | elif ifstmt1.false_statement: 96 | merged_false = Block(ifstmt1.false_statement.statements + ifstmt2.false_statement.statements) 97 | else: 98 | merged_false = None 99 | 100 | # Merge true case (for SEQGEN true statement will not be a nested if) 101 | if type(ifstmt1.true_statement) == IfStatement: 102 | merged_true = __merge_if_statements(ifstmt1.true_statement, ifstmt2.true_statement) 103 | elif ifstmt1.true_statement: 104 | merged_true = Block(ifstmt1.true_statement.statements + ifstmt2.true_statement.statements) 105 | else: 106 | merged_true = None 107 | 108 | # Return new merged if statement ast 109 | return IfStatement( ifstmt1.cond 110 | , (merged_true if merged_true else None) 111 | , (merged_false if merged_false else None) ) 112 | 113 | # __if_statement_eq( ifstmt1, ifstmt2 ) 114 | # 115 | # Check if the two if-statement objects are considered equal. Equality 116 | # basically means that they have the same nest if structure and that every 117 | # conditional condition is the same. 118 | # 119 | def __if_statement_eq( ifstmt1, ifstmt2 ): 120 | 121 | # Check condition 122 | if ifstmt1.cond != ifstmt2.cond: 123 | return False 124 | 125 | # Check false case 126 | if type(ifstmt1.false_statement) == IfStatement and type(ifstmt2.false_statement) == IfStatement: 127 | if not __if_statement_eq(ifstmt1.false_statement, ifstmt2.false_statement): 128 | return False 129 | else: 130 | if not type(ifstmt1.false_statement) == type(ifstmt2.false_statement): 131 | return False 132 | 133 | # Check true case (for SEQGEN true statement will not be a nested if) 134 | if type(ifstmt1.true_statement) == IfStatement and type(ifstmt2.true_statement) == IfStatement: 135 | if not __if_statement_eq(ifstmt1.true_statement, ifstmt2.true_statement): 136 | return False 137 | else: 138 | if not type(ifstmt1.true_statement) == type(ifstmt2.true_statement): 139 | return False 140 | 141 | # Made it past all checks... we shall call these equal! 142 | return True 143 | 144 | # __squash_if_statement_inplace( ifstmt ) 145 | # 146 | # Take the given if statement and reduce the complexity of the ast by squashing 147 | # all of the block for each of the conditional cases. This is inplace therefore 148 | # it modifies the passed object directly. 149 | # 150 | def __squash_if_statement_inplace( ifstmt ): 151 | 152 | # Squash false case 153 | if type(ifstmt.false_statement) == IfStatement: 154 | __squash_if_statement_inplace( ifstmt.false_statement ) 155 | elif type(ifstmt.false_statement) == Block: 156 | print(type(ifstmt)) 157 | __squash_nonblocking_in_block_inplace( ifstmt.false_statement ) 158 | 159 | # Squash true case 160 | if type(ifstmt.true_statement) == IfStatement: 161 | __squash_if_statement_inplace( ifstmt.true_statement ) 162 | elif type(ifstmt.true_statement) == Block: 163 | __squash_nonblocking_in_block_inplace( ifstmt.true_statement ) 164 | 165 | # __squash_nonblocking_in_block_inplace( block ) 166 | # 167 | # Takes a block object and reduces the complexity of the ast by combining the 168 | # non-blocking assignments. It does so by looking at the names of the LHS 169 | # variables and if they are the same (not including the bit select) this it 170 | # will combine them into a single non-blocking assignment with concats on the 171 | # left and right of the assignment. When combined with the 172 | # concat_redux_pass_inplace optimization this does pretty good at 173 | # reconstructing large bus assignments. 174 | # 175 | def __squash_nonblocking_in_block_inplace( block ): 176 | 177 | new_block_stmts = [] 178 | 179 | while len(block.statements) != 0: 180 | # Grab first in the list 181 | bs = block.statements.pop(0) 182 | # Not a bus, just keep as is 183 | if type(bs.left.var) != Pointer: 184 | new_block_stmts.append(bs) 185 | continue 186 | # Start a left and right concat list 187 | lconcat = [bs.left.var] 188 | rconcat = [bs.right.var] 189 | # Traverse the rest of the list and try and find other parts of the bus 190 | bot_index = 0 191 | while bot_index < len(block.statements): 192 | bbs = block.statements[bot_index] 193 | # Check if they are part of the same bus 194 | if type(bbs.left.var) == Pointer and bbs.left.var.var == bs.left.var.var: 195 | lconcat.append(bbs.left.var) 196 | rconcat.append(bbs.right.var) 197 | block.statements.pop(bot_index) 198 | else: 199 | bot_index += 1 200 | # Order the concat lists from MSB to LSB 201 | lconcat, rconcat = zip(*sorted(zip(lconcat, rconcat), key=lambda x: int(x[0].ptr.value), reverse=True)) 202 | # Add the non-blocking assignment 203 | new_block_stmts.append(NonblockingSubstitution(Lvalue(LConcat(lconcat)), Rvalue(Concat(rconcat)))) 204 | 205 | block.statements = new_block_stmts 206 | 207 | -------------------------------------------------------------------------------- /scripts/py/bsg_ast_concat_redux_opt_inplace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_ast_concat_redux_opt_inplace.py 3 | 4 | This optimization pass will go through all of the concat statements and try and 5 | reduce the complexity of them by finding consecutive bits of the same bus and 6 | collapsing them into a single bus bit-select statement. 7 | ''' 8 | 9 | import logging 10 | 11 | from pyverilog.vparser.ast import * 12 | 13 | # ast_concat_redux_opt_inplace( node ) 14 | # 15 | # Main optimization pass. This will go through the whole AST and find LHS and 16 | # RHS concats and try to reduce the complexity of them by finding consecutive 17 | # bits of the same bus and collapsing them into a single bus bit-select 18 | # statement. 19 | # 20 | def ast_concat_redux_opt_inplace( node ): 21 | 22 | # Find LConcat or regular Concat objects 23 | if type(node) == LConcat or type(node) == Concat: 24 | __squash_concat_inplace(node) 25 | 26 | # Recursivly walk down all other nodes 27 | else: 28 | for c in node.children(): 29 | ast_concat_redux_opt_inplace(c) 30 | 31 | # __squash_concat_inplace( cc ) 32 | # 33 | # Take a concat object and try to reduce the number of items by finding 34 | # consecutive bits of the same bus and collapsing them into a single bus 35 | # bit-select statement. 36 | # 37 | def __squash_concat_inplace( cc ): 38 | 39 | cc_vals = [] 40 | 41 | ptr_var = None 42 | ptr_start = None 43 | ptr_end = None 44 | 45 | for item in cc.list: 46 | if type(item) == Pointer and not ptr_var: 47 | ptr_var = item.var 48 | ptr_start = item.ptr 49 | ptr_end = item.ptr 50 | elif type(item) == Pointer and ptr_var: 51 | if ptr_var == item.var and int(ptr_end.value)-int(item.ptr.value) == 1: 52 | ptr_end = item.ptr 53 | else: 54 | cc_vals.append(Partselect(ptr_var, ptr_start, ptr_end)) 55 | ptr_var = item.var 56 | ptr_start = item.ptr 57 | ptr_end = item.ptr 58 | else: 59 | if ptr_var: 60 | cc_vals.append(Partselect(ptr_var, ptr_start, ptr_end)) 61 | ptr_var = None 62 | ptr_start = None 63 | ptr_end = None 64 | cc_vals.append(item) 65 | 66 | if ptr_var: 67 | cc_vals.append(Partselect(ptr_var, ptr_start, ptr_end)) 68 | 69 | cc.list = cc_vals 70 | 71 | -------------------------------------------------------------------------------- /scripts/py/bsg_ast_walk_and_swap_inplace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ast_walk_and_swap_inplace.py 3 | 4 | This file contains the ast_walk_and_swap_inplace function which recursivly 5 | walks through an AST and performs any modifications that we need. The main 6 | modification is the replacement of GTECH, SYNTHETIC and GENERIC instances back 7 | into RTL. 8 | ''' 9 | 10 | import inspect 11 | import logging 12 | 13 | from pyverilog.vparser.ast import * 14 | 15 | import bsg_gtech_modules 16 | import bsg_synthetic_modules 17 | import bsg_generic_modules 18 | 19 | # Small utility function that helps generate a dictionary with all of the 20 | # functions found in an imported module. This function is used to generate 3 21 | # dicts that hold all of the replacement functions for GTECH, SYNTHETIC and 22 | # GENERIC modules. All utility functions begin with __ so they should not 23 | # collide with any module instances found inside the converted verilog. 24 | def get_all_functions( module ): 25 | funcs = dict() 26 | for n,v in inspect.getmembers( module ): 27 | if inspect.isfunction(v): 28 | funcs[n] = v 29 | return funcs 30 | 31 | gtech_modules_funcs = get_all_functions( bsg_gtech_modules ) 32 | synthetic_modules_funcs = get_all_functions( bsg_synthetic_modules ) 33 | generic_modules_funcs = get_all_functions( bsg_generic_modules ) 34 | 35 | # ast_walk_and_swap_inplace 36 | # 37 | # This function recursivly walks through an AST and performs any modifications 38 | # that we need. These modifications happen in-place (ie. it will modify the AST 39 | # that is passed in and doesn't return a new one). The main modification is 40 | # replacing GTECH, SYNTHETIC and GENERIC constructrs for synthesizable RTL. 41 | def ast_walk_and_swap_inplace( node ): 42 | 43 | gtech_swap_count = 0 44 | synthetic_swap_count = 0 45 | generic_swap_count = 0 46 | 47 | ### Handle module definitions 48 | if type(node) == ModuleDef: 49 | 50 | number_of_items = len(node.items) 51 | 52 | logging.info("Module Name: %s" % node.name) 53 | logging.info("\t Item Count: %d" % number_of_items) 54 | 55 | ports = list() ;# List of all port declarations (input and output statements) 56 | wires = list() ;# List of all wire datatype declarations 57 | regs = list() ;# List of all reg datatype declarations 58 | assigns = list();# List of all new assigns to add to the ast 59 | asts = list() ;# All other ast inside the module (everything else) 60 | 61 | # Go through every AST inside the module definition 62 | for item in node.items: 63 | 64 | # If the item is a declaration 65 | if type(item) == Decl: 66 | for d in item.list: 67 | 68 | # Explict wire declaration for output ports 69 | if type(d) == Output: 70 | wires.append(Wire(d.name, d.width, d.signed)) 71 | 72 | # Split all decl 73 | if type(d) == Wire: 74 | if d not in wires: 75 | wires.append(d) 76 | else: 77 | ports.append(d) 78 | 79 | # If the item is an instance list. For elaborated netlist, every instance 80 | # list has exactly 1 instantiation. 81 | elif type(item) == InstanceList: 82 | 83 | assert len(item.instances) == 1 ;# Assert our assumptions are true 84 | 85 | instance = item.instances[0] 86 | modname = instance.module.replace('*','').replace('\\','') 87 | modline = instance.lineno 88 | 89 | # Perform a GTECH gate replacement 90 | if modname in gtech_modules_funcs: 91 | logging.debug("\t GTECH replacement found -- %s, line: %d" % (modname, modline)) 92 | gtech_swap_count += 1 93 | asts.append(gtech_modules_funcs[modname]( instance )) 94 | 95 | # Perform a SYNTHETIC module replacement 96 | elif modname in synthetic_modules_funcs: 97 | logging.debug("\t SYNTHETIC replacement found -- %s, line: %d" % (modname, modline)) 98 | synthetic_swap_count += 1 99 | asts.append(synthetic_modules_funcs[modname]( instance )) 100 | 101 | # Perform a GENERIC cell replacement 102 | elif modname in generic_modules_funcs: 103 | logging.debug("\t GENERIC replacement found -- %s, line: %d" % (modname, modline)) 104 | generic_swap_count += 1 105 | asts.append(generic_modules_funcs[modname]( instance, wires, regs, assigns )) 106 | 107 | # Instance not found in replacement lists (either a DesignCompiler 108 | # construct we don't know about or a module that is defined earlier in 109 | # the file). Do nothing to this item. 110 | else: 111 | logging.debug("\t No replacement found -- %s, line: %d" % (modname, modline)) 112 | asts.append(item) 113 | 114 | # Keep all other items 115 | else: 116 | asts.append(item) 117 | 118 | # Log some statistics 119 | logging.info("\t GTECH swap Count: %d (%d%%)" % (gtech_swap_count, (gtech_swap_count/number_of_items)*100)) 120 | logging.info("\t SYNTHETIC swap Count: %d (%d%%)" % (synthetic_swap_count, (synthetic_swap_count/number_of_items)*100)) 121 | logging.info("\t GENERIC swap Count: %d (%d%%)" % (generic_swap_count, (generic_swap_count/number_of_items)*100)) 122 | 123 | # Compose a new items list for the module definition 124 | node.items = [Decl([p]) for p in ports if p] \ 125 | + [Decl([w]) for w in wires if w] \ 126 | + [Decl([r]) for r in regs if r] \ 127 | + [a for a in assigns if a] \ 128 | + [a for a in asts if a] 129 | 130 | ### Recursivly walk down all other nodes 131 | else: 132 | for c in node.children(): 133 | (gtech,synth,generic) = ast_walk_and_swap_inplace(c) 134 | gtech_swap_count += gtech 135 | synthetic_swap_count += synth 136 | generic_swap_count += generic 137 | 138 | return (gtech_swap_count, synthetic_swap_count, generic_swap_count) 139 | 140 | -------------------------------------------------------------------------------- /scripts/py/bsg_ast_wire_reg_decl_opt_inplace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_ast_wire_reg_decl_opt_inplace.py 3 | 4 | This optimization pass takes all the wires and regs defined in a module and 5 | consolodates them into a WireList or RegList respectfully. WireList and RegList 6 | is a new pyverilog AST that represent a comma separated collection of wire 7 | and reg declarations. 8 | ''' 9 | 10 | import logging 11 | 12 | from pyverilog.vparser.ast import * 13 | 14 | # ast_wire_reg_decl_opt_inplace( node ) 15 | # 16 | # This optimization pass takes all the wires and regs in the module definition 17 | # and consolodates them into WireLists and RegLists. This will make the codegen 18 | # printout the wire are reg declarations as a comma separated collection of 19 | # wires and regs making the outputed netlist much cleaner. 20 | # 21 | def ast_wire_reg_decl_opt_inplace( node ): 22 | 23 | # Find modules definitions 24 | if type(node) == ModuleDef: 25 | 26 | ports = list() ;# List of all port declarations (input and output statements) 27 | wires = list() ;# List of all wire datatype declarations 28 | regs = list() ;# List of all reg datatype declarations 29 | asts = list() ;# All other ast inside the module (everything else) 30 | 31 | # Split up all items into lists of ports, wires, regs and other asts 32 | for item in node.items: 33 | if type(item) == Decl: 34 | assert len(item.list) == 1 35 | if type(item.list[0]) == Output or type(item.list[0]) == Input: 36 | ports.append(item.list[0]) 37 | elif type(item.list[0]) == Wire: 38 | wires.append(item.list[0]) 39 | elif type(item.list[0]) == Reg: 40 | regs.append(item.list[0]) 41 | else: 42 | asts.append(item.list[0]) 43 | else: 44 | asts.append(item) 45 | 46 | # Group wires based on width and sign 47 | wire_groups = [] 48 | 49 | top_index = 0 50 | while top_index < len(wires): 51 | ref_wire = wires[top_index] 52 | group = [ref_wire] 53 | bot_index = top_index + 1 54 | while bot_index < len(wires): 55 | if ref_wire.signed == wires[bot_index].signed and ref_wire.width == wires[bot_index].width: 56 | group.append(wires.pop(bot_index)) 57 | else: 58 | bot_index += 1 59 | wire_groups.append(group) 60 | top_index += 1 61 | 62 | # Create a WireList for each group of wires 63 | wire_lists = [] 64 | for group in wire_groups: 65 | wire_lists.append( WireList( [w.name for w in group], group[0].width, group[0].signed ) ) 66 | 67 | # Group regs based on width and sign 68 | reg_groups = [] 69 | 70 | top_index = 0 71 | while top_index < len(regs): 72 | ref_reg = regs[top_index] 73 | group = [ref_reg] 74 | bot_index = top_index + 1 75 | while bot_index < len(regs): 76 | if ref_reg.signed == regs[bot_index].signed and ref_reg.width == regs[bot_index].width: 77 | group.append(regs.pop(bot_index)) 78 | else: 79 | bot_index += 1 80 | reg_groups.append(group) 81 | top_index += 1 82 | 83 | # Create a RegList for each group of regs 84 | reg_lists = [] 85 | for group in reg_groups: 86 | reg_lists.append( RegList( [w.name for w in group], group[0].width, group[0].signed ) ) 87 | 88 | # Reconstruct the new items for the module 89 | node.items = [Decl([p]) for p in ports if p] \ 90 | + [Decl([w]) for w in wire_lists if w] \ 91 | + [Decl([r]) for r in reg_lists if r] \ 92 | + [a for a in asts if a] 93 | 94 | # Recursivly walk down all other nodes 95 | else: 96 | for c in node.children(): 97 | ast_wire_reg_decl_opt_inplace(c) 98 | 99 | -------------------------------------------------------------------------------- /scripts/py/bsg_elab_to_rtl.py: -------------------------------------------------------------------------------- 1 | ''' 2 | usage: bsg_elab_to_rtl.py [-h] -i file -o file 3 | [-loglvl {debug,info,warning,error,critical}] 4 | [-no_wire_reg_decl_opt] [-no_always_at_redux_opt] 5 | [-no_concat_redux_opt] 6 | 7 | This script takes an elaborated netlest from Synopsys DesignCompiler and 8 | converts it back into a RTL verilog netlist. 9 | 10 | optional arguments: 11 | -h, --help show this help message and exit 12 | -i file Input file 13 | -o file Output file 14 | -loglvl {debug,info,warning,error,critical} 15 | Set the logging level 16 | -no_wire_reg_decl_opt 17 | Prevent the wire and reg declaration optimization 18 | pass. 19 | -no_always_at_redux_opt 20 | Prevent the always@ reduction optimization pass. 21 | -no_concat_redux_opt Prevent the concatination reduction optimization pass. 22 | ''' 23 | 24 | import sys 25 | import argparse 26 | import logging 27 | 28 | from pyverilog.vparser import parser as vparser 29 | from pyverilog.ast_code_generator.codegen import ASTCodeGenerator 30 | 31 | from bsg_ast_walk_and_swap_inplace import ast_walk_and_swap_inplace 32 | 33 | from bsg_ast_wire_reg_decl_opt_inplace import ast_wire_reg_decl_opt_inplace 34 | from bsg_ast_always_at_redux_opt_inplace import ast_always_at_redux_opt_inplace 35 | from bsg_ast_concat_redux_opt_inplace import ast_concat_redux_opt_inplace 36 | 37 | from bsg_ast_add_wrapper_inplace import ast_add_wrapper_inplace 38 | 39 | # Update recursion depth (default 1000) 40 | sys.setrecursionlimit(1500) 41 | 42 | ### Setup the argument parsing 43 | 44 | desc = ''' 45 | This script takes an elaborated netlest from Synopsys DesignCompiler and converts it 46 | back into a RTL verilog netlist. 47 | ''' 48 | 49 | log_levels = ['debug','info','warning','error','critical'] 50 | 51 | parser = argparse.ArgumentParser(description=desc) 52 | parser.add_argument('-i', metavar='file', dest='infile', required=True, type=str, help='Input file') 53 | parser.add_argument('-o', metavar='file', dest='outfile', required=True, type=str, help='Output file') 54 | parser.add_argument('-loglvl', choices=log_levels, default='info', dest='log_level', required=False, type=str, help='Set the logging level') 55 | 56 | parser.add_argument('-wrapper', metavar='name', dest='wrapper', required=False, type=str, help='Toplevel Wrapper Name') 57 | 58 | # Turn on/off optimization passes 59 | parser.add_argument('-no_wire_reg_decl_opt', dest='wire_reg_decl_opt', action='store_false', help='Prevent the wire and reg declaration optimization pass.') 60 | parser.add_argument('-no_always_at_redux_opt', dest='always_at_redux_opt', action='store_false', help='Prevent the always@ reduction optimization pass.') 61 | parser.add_argument('-no_concat_redux_opt', dest='concat_redux_opt', action='store_false', help='Prevent the concatination reduction optimization pass.') 62 | 63 | args = parser.parse_args() 64 | 65 | ### Configure the logger 66 | 67 | if args.log_level == 'debug': logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) 68 | elif args.log_level == 'info': logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) 69 | elif args.log_level == 'warning': logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) 70 | elif args.log_level == 'error': logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) 71 | elif args.log_level == 'critical': logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.CRITICAL) 72 | 73 | ### Parse the input file 74 | 75 | logging.info('Parsing file input file: %s' % args.infile) 76 | ast, directives = vparser.parse([args.infile]) 77 | 78 | ### Walk the AST and replace DesignCompiler constructs with RTL 79 | 80 | logging.info('Performing AST replacements.') 81 | (gtech, synth, generics) = ast_walk_and_swap_inplace( ast ) 82 | total = gtech + synth + generics 83 | if total == 0: 84 | logging.info('No GTECH, SYNTHETIC, or GENERICS instances found!') 85 | else: 86 | logging.info('Total Number of Replacements = %d' % total) 87 | logging.info("\t GTECH swap Count: %d (%d%%)" % (gtech, (gtech/total)*100)) 88 | logging.info("\t SYNTHETIC swap Count: %d (%d%%)" % (synth, (synth/total)*100)) 89 | logging.info("\t GENERICS swap Count: %d (%d%%)" % (generics, (generics/total)*100)) 90 | 91 | ### Perform various optimization passes 92 | 93 | # Wire / Reg Declartion Optimization 94 | if args.wire_reg_decl_opt: 95 | logging.info('Performing wire/reg declartion optimizations.') 96 | ast_wire_reg_decl_opt_inplace( ast ) 97 | else: 98 | logging.info('Wire/reg declartion optimizations have been disabled.') 99 | 100 | # Always@ Reduction Optimization 101 | if args.always_at_redux_opt: 102 | logging.info('Performing always@ reduction optimizations.') 103 | ast_always_at_redux_opt_inplace( ast ) 104 | else: 105 | logging.info('Always@ reduction optimizations have been disabled.') 106 | 107 | # Concatination Reduction Optimization 108 | if args.concat_redux_opt: 109 | logging.info('Performing concatination reduction optimizations.') 110 | ast_concat_redux_opt_inplace( ast ) 111 | else: 112 | logging.info('Concatination reduction optimizations have been disabled.') 113 | 114 | # Add toplevel wrapper 115 | if args.wrapper: 116 | ast_add_wrapper_inplace( ast, None, args.wrapper ) 117 | 118 | ### Output RTL 119 | 120 | logging.info('Writing RTL to output file: %s' % args.outfile) 121 | with open(args.outfile, 'w') as fid: 122 | fid.write( ASTCodeGenerator().visit( ast ) ) 123 | 124 | ### Finish 125 | 126 | logging.info('Finished!') 127 | sys.exit() 128 | 129 | -------------------------------------------------------------------------------- /scripts/py/bsg_generic_modules.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_generic_modules.py 3 | 4 | This file contains the replacement functioun for generic sequential cells that 5 | DesignCompiler will use for elaboration. During the conversion phase, if a 6 | generic cell is found, the instance will be replaced with the AST returned from 7 | the generic's function. For SEQGEN, the configuration is determined based on if 8 | the ports are tied low. Not every configuration has been implemented. If an 9 | unknown configuration is found, and ERROR is logged. 10 | ''' 11 | 12 | import sys 13 | import logging 14 | from pyverilog.vparser.ast import * 15 | from bsg_utility_funcs import __get_instance_ports 16 | 17 | # generic sequential cell 18 | def SEQGEN( instance, wires, regs, assigns ): 19 | 20 | p = __get_instance_ports(instance) 21 | 22 | # Get configuration booleans 23 | has_clock = (p['clocked_on'] != IntConst('1\'b0')) 24 | has_async_reset = (p['clear'] != IntConst('1\'b0')) 25 | has_async_set = (p['preset'] != IntConst('1\'b0')) 26 | has_async_enable = (p['enable'] != IntConst('1\'b0')) 27 | has_async_data = (p['data_in'] != IntConst('1\'b0')) 28 | has_sync_reset = (p['synch_clear'] != IntConst('1\'b0')) 29 | has_sync_set = (p['synch_preset'] != IntConst('1\'b0')) 30 | has_sync_enable = (p['synch_enable'] != IntConst('1\'b0')) 31 | has_sync_data = (p['next_state'] != IntConst('1\'b0')) 32 | has_sync_toggle = (p['synch_toggle'] != IntConst('1\'b0')) 33 | has_noninverted_output = ('Q' in p) 34 | has_inverted_output = ('QN' in p) 35 | 36 | sync_enable_hi = (p['synch_enable'] == IntConst('1\'b1')) 37 | 38 | # Log configuration 39 | logging.debug('SEQGEN Configuration:') 40 | logging.debug(('\t %s: '+('\t'*3)+'%s') % ('has_clock', str(has_clock))) 41 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_async_reset', str(has_async_reset))) 42 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_async_set', str(has_async_set))) 43 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_async_enable', str(has_async_enable))) 44 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_async_data', str(has_async_data))) 45 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_sync_reset', str(has_sync_reset))) 46 | logging.debug(('\t %s: '+('\t'*3)+'%s') % ('has_sync_set', str(has_sync_set))) 47 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_sync_enable', str(has_sync_enable))) 48 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_sync_data', str(has_sync_data))) 49 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_sync_toggle', str(has_sync_toggle))) 50 | logging.debug(('\t %s: '+('\t'*1)+'%s') % ('has_noninverted_output', str(has_noninverted_output))) 51 | logging.debug(('\t %s: '+('\t'*2)+'%s') % ('has_inverted_output', str(has_inverted_output))) 52 | 53 | # Assert all assumptions before moving on to early catch unexpected configurations 54 | assert not ( has_async_reset and has_sync_reset ) 55 | assert not ( has_async_set and has_sync_set ) 56 | assert not ( has_async_enable and has_sync_enable and has_async_data ) 57 | assert not ( has_async_data and has_sync_data ) 58 | assert not ( has_clock and has_async_data ) 59 | assert (has_noninverted_output or has_inverted_output) 60 | 61 | # Not sure what to do with the synchronous toggle pin (couldn't find the RTL 62 | # that synthesizes this configuration pin, could be rare / unused?) 63 | if has_sync_toggle: 64 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 65 | return InstanceList(instance.module, [], [instance]) 66 | 67 | # EN pin 68 | if has_sync_enable: EN = p['synch_enable'] 69 | elif has_async_enable: EN = p['enable'] 70 | else: EN = None 71 | 72 | # RESET pin 73 | if has_sync_reset: RESET = p['synch_clear'] 74 | elif has_async_reset: RESET = p['clear'] 75 | # Special case, it seems that async reset can be represented with a 76 | # async enable without async data 77 | elif has_async_enable and not has_async_data: RESET = p['enable'] 78 | else: RESET = None 79 | 80 | # SET pin 81 | if has_sync_set: SET = p['synch_preset'] 82 | elif has_async_set: SET = p['preset'] 83 | else: SET = None 84 | 85 | # DATA pin 86 | DATA = p['data_in'] if has_async_data else p['next_state'] 87 | 88 | # OUTPUT pins 89 | if has_noninverted_output and type(p['Q']) == Pointer: 90 | name = p['Q'].var.name + "_%d_sv2v_reg" % int(p['Q'].ptr.value) 91 | regs.append(Reg(name,None)) 92 | Q = Identifier(name) 93 | assigns.append(Assign(Lvalue(p['Q']), Rvalue(Q))) 94 | elif has_noninverted_output and type(p['Q']) == Identifier: 95 | name = p['Q'].name + "_sv2v_reg" 96 | regs.append(Reg(name,None)) 97 | Q = Identifier(name) 98 | assigns.append(Assign(Lvalue(p['Q']), Rvalue(Q))) 99 | else: 100 | Q = None 101 | 102 | if has_inverted_output and type(p['QN']) == Pointer: 103 | name = p['QN'].var.name + "_%d_sv2v_reg" % int(p['QN'].ptr.value) 104 | regs.append(Reg(name,None)) 105 | QN = Identifier(name) 106 | assigns.append(Assign(Lvalue(p['QN']), Rvalue(QN))) 107 | elif has_inverted_output and type(p['QN']) == Identifier: 108 | name = p['QN'].name + "_sv2v_reg" 109 | regs.append(Reg(name,None)) 110 | QN = Identifier(name) 111 | assigns.append(Assign(Lvalue(p['QN']), Rvalue(QN))) 112 | else: 113 | QN = None 114 | 115 | # Main data assign block 116 | assigns = [] 117 | if Q: assigns.append(NonblockingSubstitution(Lvalue(Q), Rvalue(DATA))) 118 | if QN: assigns.append(NonblockingSubstitution(Lvalue(QN), Rvalue(Unot(DATA)))) 119 | stmt = Block(assigns) 120 | 121 | # Add enable if it exists 122 | if EN: 123 | stmt = IfStatement(EN, stmt, None) 124 | 125 | # Add set if it exists 126 | if SET: 127 | assigns = [] 128 | if Q: assigns.append(NonblockingSubstitution(Lvalue(Q), Rvalue(IntConst('1\'b1')))) 129 | if QN: assigns.append(NonblockingSubstitution(Lvalue(QN), Rvalue(IntConst('1\'b0')))) 130 | stmt = IfStatement(SET, Block(assigns), stmt) 131 | 132 | # Add reset if it exists 133 | if RESET: 134 | assigns = [] 135 | if Q: assigns.append(NonblockingSubstitution(Lvalue(Q), Rvalue(IntConst('1\'b0')))) 136 | if QN: assigns.append(NonblockingSubstitution(Lvalue(QN), Rvalue(IntConst('1\'b1')))) 137 | stmt = IfStatement(RESET, Block(assigns), stmt) 138 | 139 | # Create the sensitivity list 140 | sens = [] 141 | if has_clock: sens.append( Sens(p['clocked_on'], type='posedge') ) 142 | if has_async_data: sens.append( Sens(p['data_in'], type='level') ) 143 | if has_async_enable: sens.append( Sens(p['enable'], type='level') ) 144 | if has_async_reset: sens.append( Sens(p['clear'], type='level') ) 145 | if has_async_set: sens.append( Sens(p['preset'], type='level') ) 146 | 147 | # Return always block AST 148 | return Always(SensList(sens), stmt if type(stmt) == Block else Block([stmt])) 149 | 150 | # generic tristate cell 151 | def TSGEN( instance, wires, regs, assigns ): 152 | p = __get_instance_ports(instance) 153 | rval = Cond(p['three_state'], IntConst('1\'bz'), p['function']) 154 | return Assign(Lvalue(p['output']), Rvalue(rval)) 155 | 156 | -------------------------------------------------------------------------------- /scripts/py/bsg_gtech_modules.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_gtech_modules.py 3 | 4 | This file contains a list of ~all the GTECH cells that DesignCompiler will use 5 | for elaboration. During the conversion phase, if a GTECH cell is found, the 6 | instance will be replaced with the AST returned from the function of the same 7 | name found in this file. There are a number of GTECH cells that are not yet 8 | implemented. In the event that one of these cells is found, an ERROR will be 9 | thrown. 10 | ''' 11 | 12 | import sys 13 | import logging 14 | from pyverilog.vparser.ast import * 15 | from bsg_utility_funcs import __get_instance_ports 16 | 17 | # Tie-low cell 18 | def GTECH_ZERO( instance ): 19 | p = __get_instance_ports(instance) 20 | if 'Z' not in p: return None 21 | return Assign(Lvalue(p['Z']), Rvalue(IntConst('1\'b0'))) 22 | 23 | # Tie-high cell 24 | def GTECH_ONE( instance ): 25 | p = __get_instance_ports(instance) 26 | if 'Z' not in p: return None 27 | return Assign(Lvalue(p['Z']), Rvalue(IntConst('1\'b1'))) 28 | 29 | # Non-inverting buffer cell 30 | def GTECH_BUF( instance ): 31 | p = __get_instance_ports(instance) 32 | if 'Z' not in p: return None 33 | return Assign(Lvalue(p['Z']), Rvalue(p['A'])) 34 | 35 | # Inverting buffer cell 36 | def GTECH_NOT( instance ): 37 | p = __get_instance_ports(instance) 38 | if 'Z' not in p: return None 39 | return Assign(Lvalue(p['Z']), Rvalue(Unot(p['A']))) 40 | 41 | # 2-input and cell 42 | def GTECH_AND2( instance ): 43 | p = __get_instance_ports(instance) 44 | if 'Z' not in p: return None 45 | rval = And(p['A'], p['B']) 46 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 47 | 48 | # 3-input and cell 49 | def GTECH_AND3( instance ): 50 | p = __get_instance_ports(instance) 51 | if 'Z' not in p: return None 52 | rval = And(And(p['A'], p['B']), p['C']) 53 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 54 | 55 | # 4-input and cell 56 | def GTECH_AND4( instance ): 57 | p = __get_instance_ports(instance) 58 | if 'Z' not in p: return None 59 | rval = And(And(p['A'], p['B']), And(p['C'], p['D'])) 60 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 61 | 62 | # 5-input and cell 63 | def GTECH_AND5( instance ): 64 | p = __get_instance_ports(instance) 65 | if 'Z' not in p: return None 66 | rval = And(And(And(p['A'], p['B']), And(p['C'], p['D'])), p['E']) 67 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 68 | 69 | # 8-input and cell 70 | def GTECH_AND8( instance ): 71 | p = __get_instance_ports(instance) 72 | if 'Z' not in p: return None 73 | rval = And(And(And(p['A'], p['B']), And(p['C'], p['D'])), 74 | And(And(p['E'], p['F']), And(p['G'], p['H']))) 75 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 76 | 77 | # 2-input nand cell 78 | def GTECH_NAND2( instance ): 79 | p = __get_instance_ports(instance) 80 | if 'Z' not in p: return None 81 | rval = Unot(And(p['A'], p['B'])) 82 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 83 | 84 | # 3-input nand cell 85 | def GTECH_NAND3( instance ): 86 | p = __get_instance_ports(instance) 87 | if 'Z' not in p: return None 88 | rval = Unot(And(And(p['A'], p['B']), p['C'])) 89 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 90 | 91 | # 4-input nand cell 92 | def GTECH_NAND4( instance ): 93 | p = __get_instance_ports(instance) 94 | if 'Z' not in p: return None 95 | rval = Unot(And(And(p['A'], p['B']), And(p['C'], p['D']))) 96 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 97 | 98 | # 5-input nand cell 99 | def GTECH_NAND5( instance ): 100 | p = __get_instance_ports(instance) 101 | if 'Z' not in p: return None 102 | rval = Unot(And(And(And(p['A'], p['B']), And(p['C'], p['D'])), p['E'])) 103 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 104 | 105 | # 8-input nand cell 106 | def GTECH_NAND8( instance ): 107 | p = __get_instance_ports(instance) 108 | if 'Z' not in p: return None 109 | rval = Unot(And(And(And(p['A'], p['B']), And(p['C'], p['D'])), 110 | And(And(p['E'], p['F']), And(p['G'], p['H'])))) 111 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 112 | 113 | # 2-input or cell 114 | def GTECH_OR2( instance ): 115 | p = __get_instance_ports(instance) 116 | if 'Z' not in p: return None 117 | rval = Or(p['A'], p['B']) 118 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 119 | 120 | # 3-input or cell 121 | def GTECH_OR3( instance ): 122 | p = __get_instance_ports(instance) 123 | if 'Z' not in p: return None 124 | rval = Or(Or(p['A'], p['B']), p['C']) 125 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 126 | 127 | # 4-input or cell 128 | def GTECH_OR4( instance ): 129 | p = __get_instance_ports(instance) 130 | if 'Z' not in p: return None 131 | rval = Or(Or(p['A'], p['B']), Or(p['C'], p['D'])) 132 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 133 | 134 | # 5-input or cell 135 | def GTECH_OR5( instance ): 136 | p = __get_instance_ports(instance) 137 | if 'Z' not in p: return None 138 | rval = Or(Or(Or(p['A'], p['B']), Or(p['C'], p['D'])), p['E']) 139 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 140 | 141 | # 8-input or cell 142 | def GTECH_OR8( instance ): 143 | p = __get_instance_ports(instance) 144 | if 'Z' not in p: return None 145 | rval = Or(Or(Or(p['A'], p['B']), Or(p['C'], p['D'])), 146 | Or(Or(p['E'], p['F']), Or(p['G'], p['H']))) 147 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 148 | 149 | # 2-input nor cell 150 | def GTECH_NOR2( instance ): 151 | p = __get_instance_ports(instance) 152 | if 'Z' not in p: return None 153 | rval = Unot(Or(p['A'], p['B'])) 154 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 155 | 156 | # 3-input nor cell 157 | def GTECH_NOR3( instance ): 158 | p = __get_instance_ports(instance) 159 | if 'Z' not in p: return None 160 | rval = Unot(Or(Or(p['A'], p['B']), p['C'])) 161 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 162 | 163 | # 4-input nor cell 164 | def GTECH_NOR4( instance ): 165 | p = __get_instance_ports(instance) 166 | if 'Z' not in p: return None 167 | rval = Unot(Or(Or(p['A'], p['B']), Or(p['C'], p['D']))) 168 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 169 | 170 | # 5-input nor cell 171 | def GTECH_NOR5( instance ): 172 | p = __get_instance_ports(instance) 173 | if 'Z' not in p: return None 174 | rval = Unot(Or(Or(Or(p['A'], p['B']), Or(p['C'], p['D'])), p['E'])) 175 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 176 | 177 | # 8-input nor cell 178 | def GTECH_NOR8( instance ): 179 | p = __get_instance_ports(instance) 180 | if 'Z' not in p: return None 181 | rval = Unot(Or(Or(Or(p['A'], p['B']), Or(p['C'], p['D'])), 182 | Or(Or(p['E'], p['F']), Or(p['G'], p['H'])))) 183 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 184 | 185 | # 2-input xor cell 186 | def GTECH_XOR2( instance ): 187 | p = __get_instance_ports(instance) 188 | if 'Z' not in p: return None 189 | rval = Xor(p['A'], p['B']) 190 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 191 | 192 | # 3-input xor cell 193 | def GTECH_XOR3( instance ): 194 | p = __get_instance_ports(instance) 195 | if 'Z' not in p: return None 196 | rval = Xor(Xor(p['A'], p['B']), p['C']) 197 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 198 | 199 | # 4-input xor cell 200 | def GTECH_XOR4( instance ): 201 | p = __get_instance_ports(instance) 202 | if 'Z' not in p: return None 203 | rval = Xor(Xor(p['A'], p['B']), Xor(p['C'], p['D'])) 204 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 205 | 206 | # 2-input xnor cell 207 | def GTECH_XNOR2( instance ): 208 | p = __get_instance_ports(instance) 209 | if 'Z' not in p: return None 210 | rval = Unot(Xor(p['A'], p['B'])) 211 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 212 | 213 | # 3-input xnor cell 214 | def GTECH_XNOR3( instance ): 215 | p = __get_instance_ports(instance) 216 | if 'Z' not in p: return None 217 | rval = Unot(Xor(Xor(p['A'], p['B']), p['C'])) 218 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 219 | 220 | # 4-input xnor cell 221 | def GTECH_XNOR4( instance ): 222 | p = __get_instance_ports(instance) 223 | if 'Z' not in p: return None 224 | rval = Unot(Xor(Xor(p['A'], p['B']), Xor(p['C'], p['D']))) 225 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 226 | 227 | # 2-input a-and-not-b cell 228 | def GTECH_AND_NOT( instance ): 229 | p = __get_instance_ports(instance) 230 | if 'Z' not in p: return None 231 | rval = And(p['A'], Unot(p['B'])) 232 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 233 | 234 | # 2-input a-or-not-b cell 235 | def GTECH_OR_NOT( instance ): 236 | p = __get_instance_ports(instance) 237 | if 'Z' not in p: return None 238 | rval = Or(p['A'], Unot(p['B'])) 239 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 240 | 241 | # 3-input ao21 cell 242 | def GTECH_AO21( instance ): 243 | p = __get_instance_ports(instance) 244 | if 'Z' not in p: return None 245 | rval = Or(And(p['A'], p['B']), p['C']) 246 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 247 | 248 | # 3-input oa21 cell 249 | def GTECH_OA21( instance ): 250 | p = __get_instance_ports(instance) 251 | if 'Z' not in p: return None 252 | rval = And(Or(p['A'], p['B']), p['C']) 253 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 254 | 255 | # 4-input oa22 cell 256 | def GTECH_OA22( instance ): 257 | p = __get_instance_ports(instance) 258 | if 'Z' not in p: return None 259 | rval = And(Or(p['A'], p['B']), Or(p['C'], p['D'])) 260 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 261 | 262 | # 4-input ao22 cell 263 | def GTECH_AO22( instance ): 264 | p = __get_instance_ports(instance) 265 | if 'Z' not in p: return None 266 | rval = Or(And(p['A'], p['B']), And(p['C'], p['D'])) 267 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 268 | 269 | # 3-input aoi21 cell 270 | def GTECH_AOI21( instance ): 271 | p = __get_instance_ports(instance) 272 | if 'Z' not in p: return None 273 | rval = Unot(Or(And(p['A'], p['B']), p['C'])) 274 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 275 | 276 | # 4-input aoi22 cell 277 | def GTECH_AOI22( instance ): 278 | p = __get_instance_ports(instance) 279 | if 'Z' not in p: return None 280 | rval = Unot(Or(And(p['A'], p['B']), And(p['C'], p['D']))) 281 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 282 | 283 | # 6-input aoi222 cell 284 | def GTECH_AOI222( instance ): 285 | p = __get_instance_ports(instance) 286 | if 'Z' not in p: return None 287 | rval = Unot(Or(Or(And(p['A'], p['B']), And(p['C'], p['D'])), And(p['E'], p['F']))) 288 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 289 | 290 | # 4-input aoi2n2 cell 291 | def GTECH_AOI2N2( instance ): 292 | p = __get_instance_ports(instance) 293 | if 'Z' not in p: return None 294 | rval = Unot(Or(And(p['A'], p['B']), Unot(Or(p['C'], p['D'])))) 295 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 296 | 297 | # 3-input oai21 cell 298 | def GTECH_OAI21( instance ): 299 | p = __get_instance_ports(instance) 300 | if 'Z' not in p: return None 301 | rval = Unot(And(Or(p['A'], p['B']), p['C'])) 302 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 303 | 304 | # 4-input oai22 cell 305 | def GTECH_OAI22( instance ): 306 | p = __get_instance_ports(instance) 307 | if 'Z' not in p: return None 308 | rval = Unot(And(Or(p['A'], p['B']), Or(p['C'], p['D']))) 309 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 310 | 311 | # 4-input oai2n2 cell 312 | def GTECH_OAI2N2( instance ): 313 | p = __get_instance_ports(instance) 314 | if 'Z' not in p: return None 315 | rval = Unot(And(Or(p['A'], p['B']), Unot(And(p['C'], p['D'])))) 316 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 317 | 318 | # 3-input majority cell 319 | def GTECH_MAJ23( instance ): 320 | p = __get_instance_ports(instance) 321 | if 'Z' not in p: return None 322 | rval = Or(Or(And(p['A'], p['B']), And(p['A'], p['C'])), And(p['B'], p['C'])) 323 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 324 | 325 | # 2-input multiplexer cell 326 | def GTECH_MUX2( instance ): 327 | p = __get_instance_ports(instance) 328 | if 'Z' not in p: return None 329 | rval = Cond(p['S'], p['B'], p['A']) 330 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 331 | 332 | # 2-input inverting multiplexer cell 333 | def GTECH_MUXI2( instance ): 334 | p = __get_instance_ports(instance) 335 | if 'Z' not in p: return None 336 | rval = Unot(Cond(p['S'], p['B'], p['A'])) 337 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 338 | 339 | # 4-input multiplexer cell 340 | def GTECH_MUX4( instance ): 341 | p = __get_instance_ports(instance) 342 | if 'Z' not in p: return None 343 | rval = Cond(p['B'], 344 | Cond(p['A'], p['D3'], p['D2']), 345 | Cond(p['A'], p['D1'], p['D0'])) 346 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 347 | 348 | # 8-input multiplexer cell 349 | def GTECH_MUX8( instance ): 350 | p = __get_instance_ports(instance) 351 | if 'Z' not in p: return None 352 | rval = Cond(p['C'], 353 | Cond(p['B'], 354 | Cond(p['A'], p['D7'], p['D6']), 355 | Cond(p['A'], p['D5'], p['D4'])), 356 | Cond(p['B'], 357 | Cond(p['A'], p['D3'], p['D2']), 358 | Cond(p['A'], p['D1'], p['D0']))) 359 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 360 | 361 | # half-adder cell 362 | def GTECH_ADD_AB( instance ): 363 | p = __get_instance_ports(instance) 364 | if 'Z' not in p: return None 365 | rval1 = Xor(p['A'], p['B']) 366 | rval2 = And(p['A'], p['B']) 367 | return Assign(Lvalue(LConcat([p['S'], p['COUT']])), Rvalue(Concat([rval1, rval2]))) 368 | 369 | # full-adder cell 370 | def GTECH_ADD_ABC( instance ): 371 | p = __get_instance_ports(instance) 372 | if 'Z' not in p: return None 373 | rval1 = Xor(Xor(p['A'], p['B']), p['C']) 374 | rval2 = Or(Or(And(p['A'], p['B']), And(p['A'], p['C'])), And(p['B'], p['C'])) 375 | return Assign(Lvalue(LConcat([p['S'], p['COUT']])), Rvalue(Concat([rval1, rval2]))) 376 | 377 | # tri-state buffer cell 378 | def GTECH_TBUF( instance ): 379 | p = __get_instance_ports(instance) 380 | if 'Z' not in p: return None 381 | rval = Cond(p['E'], p['A'], IntConst('1\'bz')) 382 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 383 | 384 | ################################################################################ 385 | # The following GTECH cells have not been implemented yet. An ERROR will be 386 | # thrown if any of these cells are found in the verilog file being converted. 387 | # In the event that one of these is found, you should implement said cell and 388 | # move it above. 389 | ################################################################################ 390 | 391 | def GTECH_ISO1_EN0( instance ): 392 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 393 | return InstanceList(instance.module, [], [instance]) 394 | 395 | def GTECH_ISO1_EN1( instance ): 396 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 397 | return InstanceList(instance.module, [], [instance]) 398 | 399 | def GTECH_ISO0_EN0( instance ): 400 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 401 | return InstanceList(instance.module, [], [instance]) 402 | 403 | def GTECH_ISO0_EN1( instance ): 404 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 405 | return InstanceList(instance.module, [], [instance]) 406 | 407 | def GTECH_ISOLATCH_EN0( instance ): 408 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 409 | return InstanceList(instance.module, [], [instance]) 410 | 411 | def GTECH_ISOLATCH_EN1( instance ): 412 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 413 | return InstanceList(instance.module, [], [instance]) 414 | 415 | def GTECH_INBUF( instance ): 416 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 417 | return InstanceList(instance.module, [], [instance]) 418 | 419 | def GTECH_OUTBUF( instance ): 420 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 421 | return InstanceList(instance.module, [], [instance]) 422 | 423 | def GTECH_INOUTBUF( instance ): 424 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 425 | return InstanceList(instance.module, [], [instance]) 426 | 427 | def GTECH_FD1( instance ): 428 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 429 | return InstanceList(instance.module, [], [instance]) 430 | 431 | def GTECH_FD14( instance ): 432 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 433 | return InstanceList(instance.module, [], [instance]) 434 | 435 | def GTECH_FD18( instance ): 436 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 437 | return InstanceList(instance.module, [], [instance]) 438 | 439 | def GTECH_FD1S( instance ): 440 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 441 | return InstanceList(instance.module, [], [instance]) 442 | 443 | def GTECH_FD2( instance ): 444 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 445 | return InstanceList(instance.module, [], [instance]) 446 | 447 | def GTECH_FD24( instance ): 448 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 449 | return InstanceList(instance.module, [], [instance]) 450 | 451 | def GTECH_FD28( instance ): 452 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 453 | return InstanceList(instance.module, [], [instance]) 454 | 455 | def GTECH_FD2S( instance ): 456 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 457 | return InstanceList(instance.module, [], [instance]) 458 | 459 | def GTECH_FD3( instance ): 460 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 461 | return InstanceList(instance.module, [], [instance]) 462 | 463 | def GTECH_FD34( instance ): 464 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 465 | return InstanceList(instance.module, [], [instance]) 466 | 467 | def GTECH_FD38( instance ): 468 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 469 | return InstanceList(instance.module, [], [instance]) 470 | 471 | def GTECH_FD3S( instance ): 472 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 473 | return InstanceList(instance.module, [], [instance]) 474 | 475 | def GTECH_FD4( instance ): 476 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 477 | return InstanceList(instance.module, [], [instance]) 478 | 479 | def GTECH_FD44( instance ): 480 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 481 | return InstanceList(instance.module, [], [instance]) 482 | 483 | def GTECH_FD48( instance ): 484 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 485 | return InstanceList(instance.module, [], [instance]) 486 | 487 | def GTECH_FD4S( instance ): 488 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 489 | return InstanceList(instance.module, [], [instance]) 490 | 491 | def GTECH_FJK1( instance ): 492 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 493 | return InstanceList(instance.module, [], [instance]) 494 | 495 | def GTECH_FJK1S( instance ): 496 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 497 | return InstanceList(instance.module, [], [instance]) 498 | 499 | def GTECH_FJK2( instance ): 500 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 501 | return InstanceList(instance.module, [], [instance]) 502 | 503 | def GTECH_FJK2S( instance ): 504 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 505 | return InstanceList(instance.module, [], [instance]) 506 | 507 | def GTECH_FJK3( instance ): 508 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 509 | return InstanceList(instance.module, [], [instance]) 510 | 511 | def GTECH_FJK3S( instance ): 512 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 513 | return InstanceList(instance.module, [], [instance]) 514 | 515 | def GTECH_FJK4( instance ): 516 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 517 | return InstanceList(instance.module, [], [instance]) 518 | 519 | def GTECH_FJK4S( instance ): 520 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 521 | return InstanceList(instance.module, [], [instance]) 522 | 523 | def GTECH_LD1( instance ): 524 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 525 | return InstanceList(instance.module, [], [instance]) 526 | 527 | def GTECH_LD2( instance ): 528 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 529 | return InstanceList(instance.module, [], [instance]) 530 | 531 | def GTECH_LD2_1( instance ): 532 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 533 | return InstanceList(instance.module, [], [instance]) 534 | 535 | def GTECH_LD3( instance ): 536 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 537 | return InstanceList(instance.module, [], [instance]) 538 | 539 | def GTECH_LD4( instance ): 540 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 541 | return InstanceList(instance.module, [], [instance]) 542 | 543 | def GTECH_LD4_1( instance ): 544 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 545 | return InstanceList(instance.module, [], [instance]) 546 | 547 | def GTECH_LSR0( instance ): 548 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 549 | return InstanceList(instance.module, [], [instance]) 550 | 551 | -------------------------------------------------------------------------------- /scripts/py/bsg_synthetic_modules.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_synthetic_modules.py 3 | 4 | This file contains a list of ~all the synthetic modules that DesignCompiler 5 | will use for elaboration. During the conversion phase, if a synthetic module is 6 | found, the instance will be replaced with the AST returned from the function of 7 | the same name found in this file. There are a number of synthetic modules that 8 | are not yet implemented. In the event that one of these modules is found, an 9 | ERROR will be thrown. 10 | ''' 11 | 12 | import sys 13 | import logging 14 | from pyverilog.vparser.ast import * 15 | from bsg_utility_funcs import __get_instance_ports 16 | 17 | # Unsigned addition operation 18 | def ADD_UNS_OP( instance ): 19 | p = __get_instance_ports(instance) 20 | rval = Plus(p['A'], p['B']) 21 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 22 | 23 | # Signed addition operation 24 | def ADD_TC_OP( instance ): 25 | p = __get_instance_ports(instance) 26 | rval = Plus(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 27 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 28 | 29 | # Unsigned subtraction operation 30 | def SUB_UNS_OP( instance ): 31 | p = __get_instance_ports(instance) 32 | rval = Minus(p['A'], p['B']) 33 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 34 | 35 | # Signed subtraction operation 36 | def SUB_TC_OP( instance ): 37 | p = __get_instance_ports(instance) 38 | rval = Minus(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 39 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 40 | 41 | # Unsigned multiplication operation 42 | def MULT_UNS_OP( instance ): 43 | p = __get_instance_ports(instance) 44 | rval = Times(p['A'], p['B']) 45 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 46 | 47 | # Signed multiplication operation 48 | def MULT_TC_OP( instance ): 49 | p = __get_instance_ports(instance) 50 | rval = Times(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 51 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 52 | 53 | # Unsigned less-than operation 54 | def LT_UNS_OP( instance ): 55 | p = __get_instance_ports(instance) 56 | rval = LessThan(p['A'], p['B']) 57 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 58 | 59 | # Signed less-than operation 60 | def LT_TC_OP( instance ): 61 | p = __get_instance_ports(instance) 62 | rval = LessThan(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 63 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 64 | 65 | # Unsigned greater-than operation 66 | def GT_UNS_OP( instance ): 67 | p = __get_instance_ports(instance) 68 | rval = GreaterThan(p['A'], p['B']) 69 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 70 | 71 | # Signed greater-than operation 72 | def GT_TC_OP( instance ): 73 | p = __get_instance_ports(instance) 74 | rval = GreaterThan(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 75 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 76 | 77 | # Unsigned less-than-or-equal operation 78 | def LEQ_UNS_OP( instance ): 79 | p = __get_instance_ports(instance) 80 | rval = LessEq(p['A'], p['B']) 81 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 82 | 83 | # Signed less-than-or-equal operation 84 | def LEQ_TC_OP( instance ): 85 | p = __get_instance_ports(instance) 86 | rval = LessEq(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 87 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 88 | 89 | # Unsigned greater-than-or-equal operation 90 | def GEQ_UNS_OP( instance ): 91 | p = __get_instance_ports(instance) 92 | rval = GreaterEq(p['A'], p['B']) 93 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 94 | 95 | # Signed greater-than-or-equal operation 96 | def GEQ_TC_OP( instance ): 97 | p = __get_instance_ports(instance) 98 | rval = GreaterEq(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 99 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 100 | 101 | # Unsigned division operation 102 | def DIV_UNS_OP( instance ): 103 | p = __get_instance_ports(instance) 104 | rval = Divide(p['A'], p['B']) 105 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 106 | 107 | # Signed division operation 108 | def DIV_TC_OP( instance ): 109 | p = __get_instance_ports(instance) 110 | rval = Divide(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 111 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 112 | 113 | # Unsigned remainder operation 114 | def REM_UNS_OP( instance ): 115 | p = __get_instance_ports(instance) 116 | rval = Mod(p['A'], p['B']) 117 | return Assign(Lvalue(p['REMAINDER']), Rvalue(rval)) 118 | 119 | # Signed remainder operation 120 | def REM_TC_OP( instance ): 121 | p = __get_instance_ports(instance) 122 | rval = Mod(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 123 | return Assign(Lvalue(p['REMAINDER']), Rvalue(rval)) 124 | 125 | # Unsigned equals operation 126 | def EQ_UNS_OP( instance ): 127 | p = __get_instance_ports(instance) 128 | rval = Eq(p['A'], p['B']) 129 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 130 | 131 | # Signed equals operation 132 | def EQ_TC_OP( instance ): 133 | p = __get_instance_ports(instance) 134 | rval = Eq(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 135 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 136 | 137 | # Unsigned not-equals operation 138 | def NE_UNS_OP( instance ): 139 | p = __get_instance_ports(instance) 140 | rval = NotEq(p['A'], p['B']) 141 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 142 | 143 | # Signed not-equals operation 144 | def NE_TC_OP( instance ): 145 | p = __get_instance_ports(instance) 146 | rval = NotEq(SystemCall('signed', [p['A']]), SystemCall('signed',[p['B']])) 147 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 148 | 149 | # Unsigned shift (left) operation 150 | def ASH_UNS_UNS_OP( instance ): 151 | p = __get_instance_ports(instance) 152 | rval = Sll(p['A'], p['SH']) 153 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 154 | 155 | # Unsigned shift (right) operation 156 | def ASHR_UNS_UNS_OP( instance ): 157 | p = __get_instance_ports(instance) 158 | rval = Srl(p['A'], p['SH']) 159 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 160 | 161 | # Signed shift (right) operation 162 | def ASHR_TC_UNS_OP( instance ): 163 | p = __get_instance_ports(instance) 164 | rval = Sra(SystemCall('signed', [p['A']]), p['SH']) 165 | return Assign(Lvalue(p['Z']), Rvalue(rval)) 166 | 167 | # Select operation. Each select_op synthetic module has a Z output port, and 168 | # pairs of DATAn and CONTROLn ports where n is a number starting with 1. When 169 | # CONTROLn is hot, Z=DATAn. At any given point, one-and-only-one of the 170 | # CONTROLn ports is hot. 171 | def SELECT_OP( instance ): 172 | p = __get_instance_ports(instance) 173 | control_count = int((len(p)-1) / 2) 174 | cond_stmt = IntConst('1\'b0') 175 | for i in range(control_count, 0, -1): 176 | cond_stmt = Cond(p['CONTROL%d' % i], p['DATA%d' % i], cond_stmt) 177 | return Assign(Lvalue(p['Z']), Rvalue(cond_stmt)) 178 | 179 | # multiplexing operation 180 | def MUX_OP( instance ): 181 | p = __get_instance_ports(instance) 182 | 183 | for c in range(32): 184 | if len(p) == 1 + c + 2**c: 185 | break 186 | 187 | cond_stmt = IntConst('1\'b0') 188 | for i in range(control_count, 0, -1): 189 | cond_stmt = Cond(p['CONTROL%d' % i], p['DATA%d' % i], cond_stmt) 190 | return Assign(Lvalue(p['Z']), Rvalue(cond_stmt)) 191 | 192 | ################################################################################ 193 | # The following SYNTHETIC modules have not been implemented yet. An ERROR will 194 | # be thrown if any of these modules are found in the verilog file being 195 | # converted. In the event that one of these is found, you should implement said 196 | # cell and move it above. 197 | ################################################################################ 198 | 199 | def ADD_UNS_CI_OP( instance ): 200 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 201 | return InstanceList(instance.module, [], [instance]) 202 | 203 | def ADD_TC_CI_OP( instance ): 204 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 205 | return InstanceList(instance.module, [], [instance]) 206 | 207 | def SUB_UNS_CI_OP( instance ): 208 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 209 | return InstanceList(instance.module, [], [instance]) 210 | 211 | def SUB_TC_CI_OP( instance ): 212 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 213 | return InstanceList(instance.module, [], [instance]) 214 | 215 | def MOD_UNS_OP( instance ): 216 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 217 | return InstanceList(instance.module, [], [instance]) 218 | 219 | def DIVREM_UNS_OP( instance ): 220 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 221 | return InstanceList(instance.module, [], [instance]) 222 | 223 | def DIVMOD_UNS_OP( instance ): 224 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 225 | return InstanceList(instance.module, [], [instance]) 226 | 227 | def MOD_TC_OP( instance ): 228 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 229 | return InstanceList(instance.module, [], [instance]) 230 | 231 | def DIVREM_TC_OP( instance ): 232 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 233 | return InstanceList(instance.module, [], [instance]) 234 | 235 | def DIVMOD_TC_OP( instance ): 236 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 237 | return InstanceList(instance.module, [], [instance]) 238 | 239 | def ASH_UNS_TC_OP( instance ): 240 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 241 | return InstanceList(instance.module, [], [instance]) 242 | 243 | def ASH_TC_UNS_OP( instance ): 244 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 245 | return InstanceList(instance.module, [], [instance]) 246 | 247 | def ASH_TC_TC_OP( instance ): 248 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 249 | return InstanceList(instance.module, [], [instance]) 250 | 251 | def ASHR_UNS_TC_OP( instance ): 252 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 253 | return InstanceList(instance.module, [], [instance]) 254 | 255 | def ASHR_TC_TC_OP( instance ): 256 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 257 | return InstanceList(instance.module, [], [instance]) 258 | 259 | def BSH_UNS_OP( instance ): 260 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 261 | return InstanceList(instance.module, [], [instance]) 262 | 263 | def BSH_TC_OP( instance ): 264 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 265 | return InstanceList(instance.module, [], [instance]) 266 | 267 | def BSHL_TC_OP( instance ): 268 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 269 | return InstanceList(instance.module, [], [instance]) 270 | 271 | def BSHR_UNS_OP( instance ): 272 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 273 | return InstanceList(instance.module, [], [instance]) 274 | 275 | def BSHR_TC_OP( instance ): 276 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 277 | return InstanceList(instance.module, [], [instance]) 278 | 279 | def SLA_UNS_OP( instance ): 280 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 281 | return InstanceList(instance.module, [], [instance]) 282 | 283 | def SLA_TC_OP( instance ): 284 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 285 | return InstanceList(instance.module, [], [instance]) 286 | 287 | def SRA_UNS_OP( instance ): 288 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 289 | return InstanceList(instance.module, [], [instance]) 290 | 291 | def SRA_TC_OP( instance ): 292 | logging.error('No implementation defined for %s replacement!' % sys._getframe().f_code.co_name) 293 | return InstanceList(instance.module, [], [instance]) 294 | 295 | -------------------------------------------------------------------------------- /scripts/py/bsg_utility_funcs.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bsg_utility_funcs.py 3 | 4 | This file contains commonly used utility functions. 5 | ''' 6 | 7 | import logging 8 | from pyverilog.vparser.ast import * 9 | 10 | ################################################################################ 11 | # Utility function that get's all the ports from an instance and creates a 12 | # simple dictionary where the key is the name of the port and the value is the 13 | # AST for that port. 14 | ################################################################################ 15 | 16 | def __get_instance_ports( instance ): 17 | ports = {} 18 | for port in instance.portlist: 19 | ports[port.portname.replace('\\','')] = port.argname 20 | return ports 21 | 22 | ################################################################################ 23 | # Utility function that will take a port and make sure that it is declared as a 24 | # reg. By default, everything is a wire because the elaborated netlist is just 25 | # a bunch of module instantiations. Here we will swap those wires to regs. 26 | ################################################################################ 27 | 28 | def __convert_pin_to_reg_DEPRICATED( pin, wires, regs ): 29 | 30 | if type(pin) == Pointer: 31 | name = pin.var.name 32 | else: 33 | name = pin.name 34 | 35 | # We first check if it is already a reg. Typically, the reg list is much 36 | # smaller than the wire list and it is very common that the net is already a 37 | # reg (most common for large multibit registers) therefore this actually has 38 | # a significant speedup! 39 | for i,reg in enumerate(regs): 40 | if name == reg.name: 41 | return 42 | 43 | for i,wire in enumerate(wires): 44 | if name == wire.name: 45 | logging.debug('Swapping %s to reg' % name) 46 | wires.pop(i) 47 | regs.append(Reg(wire.name, wire.width, wire.signed)) 48 | return 49 | 50 | -------------------------------------------------------------------------------- /scripts/tcl/filelist_include_to_flist.tcl: -------------------------------------------------------------------------------- 1 | 2 | set DESIGN_DIR $::env(DESIGN_DIR) 3 | set PROCESS $::env(PROCESS) 4 | 5 | source ${DESIGN_DIR}/tcl/filelist.tcl 6 | source ${DESIGN_DIR}/tcl/include.tcl 7 | 8 | if { [file exists ${DESIGN_DIR}/tcl/hard/${PROCESS}/filelist_deltas.tcl] } { 9 | source ${DESIGN_DIR}/tcl/hard/${PROCESS}/filelist_deltas.tcl 10 | } else { 11 | set HARD_SWAP_FILELIST [join ""] 12 | set NETLIST_SOURCE_FILES [join ""] 13 | set NEW_SVERILOG_SOURCE_FILES [join ""] 14 | } 15 | 16 | set hard_swap_module_list [list] 17 | foreach f $HARD_SWAP_FILELIST { 18 | lappend hard_swap_module_list [file rootname [file tail $f]] 19 | } 20 | 21 | set sverilog_source_files [list] 22 | foreach f $SVERILOG_SOURCE_FILES { 23 | set module_name [file rootname [file tail $f]] 24 | set idx [lsearch $hard_swap_module_list $module_name] 25 | if {$idx == -1} { 26 | lappend sverilog_source_files $f 27 | } else { 28 | lappend sverilog_source_files [lindex $HARD_SWAP_FILELIST $idx] 29 | } 30 | } 31 | 32 | set final_netlist_source_files $NETLIST_SOURCE_FILES 33 | set final_sverilog_source_files [concat $sverilog_source_files $NEW_SVERILOG_SOURCE_FILES] 34 | set all_final_source_files [concat $final_netlist_source_files $final_sverilog_source_files] 35 | 36 | set final_sverilog_include_paths [list] 37 | foreach incdir $SVERILOG_INCLUDE_PATHS { 38 | # replace 'portable' directories with the target process 39 | # TODO: for now, no replacements are done to the packaging directory 40 | #lappend final_sverilog_include_paths [regsub -all portable $incdir $::env(BSG_PACKAGING_FOUNDRY)] 41 | lappend final_sverilog_include_paths $incdir 42 | } 43 | 44 | set final_sverilog_include_paths [join "$final_sverilog_include_paths"] 45 | 46 | foreach i $final_sverilog_include_paths { 47 | puts "+incdir+$i" 48 | } 49 | 50 | foreach i $all_final_source_files { 51 | puts "$i" 52 | } 53 | 54 | -------------------------------------------------------------------------------- /scripts/tcl/run_dc.tcl: -------------------------------------------------------------------------------- 1 | # run_dc.tcl 2 | # 3 | # This is the main DesignCompiler script for the bsg_sv2v flow. The goal of 4 | # this script is to read in the design and elaborate the top-level and output 5 | # the elaborated netlist. Because we do not compile, there is no need for any 6 | # technology files to be linked. 7 | 8 | ### Grab required ENV variables for the flow 9 | 10 | set DESIGN_NAME $::env(DESIGN_NAME) ;# Top-level module 11 | set DESIGN_FILELIST $::env(DESIGN_FILELIST) ;# Filelist path 12 | set DESIGN_ELAB_NAME $::env(DESIGN_ELAB_NAME) ;# Design name to elaborate 13 | set OUTPUT_DIR $::env(OUTPUT_DIR) ;# Output directory 14 | set OUTPUT_FILE $::env(OUTPUT_ELAB_FILE) ;# Output filename 15 | 16 | ### Application setup 17 | 18 | set_svf -off ;# No need to svf file (for fomality) 19 | set_app_var link_library "" ;# Empty link library 20 | set_app_var target_library "*" ;# Default target library 21 | set_app_var hdlin_infer_mux none ;# Use SELCT_OP over MUX_OP synthetic module 22 | set_app_var sh_command_log_file $OUTPUT_DIR/command.log ;# Redirect command.log file 23 | set_app_var verilogout_no_tri true ;# Make unknown port connections wires not tris 24 | set_app_var hdlin_ff_always_sync_set_reset true ;# Try to infer synchronous set/reset logic 25 | set_app_var hdlin_ff_always_async_set_reset false ;# Don't try to infer asynchronous set/reset logic 26 | 27 | ### Read in the filelist 28 | 29 | # Here we read in the filelist. For our designs, we often use VCS filelists to 30 | # link the whole design together. Inside these filelists are 5 main items: 31 | # 32 | # 1. Comments -- begging in the # character 33 | # 2. +incdir+ -- adding a search directory for includes 34 | # 3. +define+ -- adding a macro definition at compile time 35 | # 4. -pvalue+ -- top-level parametes 36 | # 5. -- verilog files 37 | # 38 | set bsg_incdirs [list] 39 | set bsg_macros [list] 40 | set bsg_params [list] 41 | set bsg_filelist [list] 42 | 43 | set fid [open $DESIGN_FILELIST r] 44 | while { [gets $fid line] >= 0 } { 45 | if { [regexp {^#.*} $line] } { 46 | continue 47 | } elseif { [regexp {^\+incdir\+(.*)} $line match sub] } { 48 | set incdir [regsub -all {\$(\w+)} $sub "\$::env\(\\1)"] 49 | puts "INFO: Adding $incdir to search path!" 50 | eval "lappend bsg_incdirs $incdir" 51 | } elseif { [regexp {^\+define\+(.*)} $line match sub] } { 52 | set macro [regsub -all {\$(\w+)} $sub "\$::env\(\\1)"] 53 | puts "INFO: Adding $macro to macros!" 54 | eval "lappend bsg_macros $macro" 55 | } elseif { [regexp {^\-pvalue\+(.*)} $line match sub] } { 56 | set param [regsub -all {\$(\w+)} $sub "\$::env\(\\1)"] 57 | puts "INFO: Adding $param to parameters!" 58 | eval "lappend bsg_params $param" 59 | } elseif { [regexp {^(.*)} $line match sub] } { 60 | set f [regsub -all {\$(\w+)} $sub "\$::env\(\\1)"] 61 | puts "INFO: Adding $f to filelist!" 62 | eval "lappend bsg_filelist $f" 63 | } 64 | } 65 | 66 | ### Setup the search path with the include directories 67 | 68 | set_app_var search_path "$search_path [join $bsg_incdirs]" 69 | 70 | ### Perform analysis 71 | 72 | define_design_lib WORK -path $OUTPUT_DIR/${DESIGN_NAME}_WORK 73 | if { ![analyze -format sverilog -define $bsg_macros [join $bsg_filelist]] } { 74 | exit 1 75 | } 76 | 77 | ### Perform elaboration 78 | 79 | if { $DESIGN_ELAB_NAME == "" } { 80 | set DESIGN_ELAB_NAME $DESIGN_NAME 81 | } 82 | 83 | if { ![elaborate -param [join $bsg_params ","] $DESIGN_ELAB_NAME] } { 84 | exit 1 85 | } 86 | 87 | ### Rename and set the real top-level design 88 | 89 | if { [sizeof_collection [get_designs -quiet $DESIGN_NAME]] == 0 } { 90 | set designs [get_designs -quiet -filter "@hdl_template == $DESIGN_NAME"] 91 | if { [sizeof_collection $designs] > 1 } { 92 | puts "Error: Toplevel design has multiple instances post-elaboration. This" 93 | puts "usually indicates that there are multiple parameterizations of the design." 94 | puts "This flow does not support different parameterizations of the top-level" 95 | puts "compile target, consider using a wrapper to uniqify the hierarchy for each" 96 | puts "parameter." 97 | exit 1 98 | } else { 99 | rename_design $designs $DESIGN_NAME 100 | } 101 | } 102 | 103 | ### Make sure the current design is correct 104 | 105 | current_design $DESIGN_NAME 106 | 107 | ### Cleanup some of the netlist 108 | 109 | define_name_rules rules \ 110 | -special verilog \ 111 | -dummy_net_prefix "sv2v_dc_%d" \ 112 | -flatten_multi_dimension_busses \ 113 | -remove_irregular_net_bus \ 114 | -remove_irregular_port_bus \ 115 | -restricted {!@#$%^&*()\\-[]} 116 | change_names -hier -rules rules 117 | 118 | ### Read in the constraints file if it exists 119 | 120 | if {[file exists $::env(DESIGN_CONSTRAINTS_FILE)]} { 121 | if {[file extension $::env(DESIGN_CONSTRAINTS_FILE)] == ".sdc"} { 122 | read_sdc -echo $::env(DESIGN_CONSTRAINTS_FILE) 123 | } else { 124 | source -echo -verbose $::env(DESIGN_CONSTRAINTS_FILE) 125 | } 126 | } 127 | 128 | ### Output the elaborated netlist 129 | 130 | write_file -format verilog -hier -output $OUTPUT_FILE 131 | 132 | ### Output the sdc constraints 133 | 134 | if {[file exists $::env(DESIGN_CONSTRAINTS_FILE)]} { 135 | write_sdc -nosplit $OUTPUT_FILE.sdc 136 | } 137 | 138 | ### Finished! 139 | 140 | exit 0 141 | 142 | --------------------------------------------------------------------------------