3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-06-23 01:00:29 +00:00

Merge branch 'YosysHQ:main' into master

This commit is contained in:
Eder Monteiro 2025-09-04 09:15:26 -03:00 committed by GitHub
commit d563d3974f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
97 changed files with 7962 additions and 4848 deletions

View file

@ -8,14 +8,13 @@ runs:
shell: bash
run: |
sudo apt-get update
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
- name: Install macOS Dependencies
if: runner.os == 'macOS'
shell: bash
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld || true
brew bundle
- name: Linux runtime environment
if: runner.os == 'Linux'
@ -29,7 +28,7 @@ runs:
shell: bash
run: |
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH
echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH
echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install deps
run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev
run: sudo apt-get install bison flex libfl-dev libreadline-dev tcl-dev libffi-dev
- name: Checkout repository
uses: actions/checkout@v4

View file

@ -27,19 +27,20 @@ jobs:
with:
submodules: true
persist-credentials: false
- run: sudo apt-get install libfl-dev
- name: Build
run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4
with:
name: vcxsrc
path: yosys-win32-vcxsrc-latest.zip
vs-build:
name: Visual Studio build
runs-on: windows-latest
needs: [vs-prep, pre_job]
if: needs.pre_job.outputs.should_skip != 'true'
steps:
steps:
- uses: actions/download-artifact@v4
with:
name: vcxsrc
@ -50,7 +51,7 @@ jobs:
uses: microsoft/setup-msbuild@v2
- name: MSBuild
working-directory: yosys-win32-vcxsrc-latest
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.26100.0
wasi-build:
name: WASI build
@ -68,9 +69,20 @@ jobs:
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
FLEX_VER=2.6.4
FLEX=flex-${FLEX_VER}
FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz
if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi
mkdir -p flex-build
(cd flex-build &&
../${FLEX}/configure --prefix=$(pwd)/../flex-prefix &&
make &&
make install)
mkdir -p build
cat > build/Makefile.conf <<END
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH}
export PATH := $(pwd)/${WASI_SDK}/bin:$(pwd)/flex-prefix/bin:${PATH}
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
CONFIG := wasi
@ -80,6 +92,8 @@ jobs:
ENABLE_READLINE := 0
ENABLE_PLUGINS := 0
ENABLE_ZLIB := 0
CXXFLAGS += -I$(pwd)/flex-prefix/include
END
make -C build -f ../Makefile CXX=clang -j$(nproc)
@ -98,7 +112,7 @@ jobs:
with:
submodules: true
persist-credentials: false
- uses: cachix/install-nix-action@v26
- uses: cachix/install-nix-action@v31
with:
install_url: https://releases.nixos.org/nix/nix-2.18.1/install
install_url: https://releases.nixos.org/nix/nix-2.30.0/install
- run: nix build .?submodules=1 -L

View file

@ -161,6 +161,44 @@ jobs:
run: |
find tests/**/*.err -print -exec cat {} \;
test-cells:
name: Run test_cell
runs-on: ${{ matrix.os }}
needs: [build-yosys, pre_job]
if: needs.pre_job.outputs.should_skip != 'true'
env:
CC: clang
strategy:
matrix:
os: [ubuntu-latest]
sanitizer: [undefined]
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.os }}-${{ matrix.sanitizer }}
- name: Uncompress build
shell: bash
run:
tar -xvf build.tar
- name: test_cell
shell: bash
run: |
./yosys -p 'test_cell -n 20 -s 1 all'
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $pow $pmux'
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $eqx $nex $bweqx'
./yosys -p 'test_cell -n 20 -s 1 -aigmap $buf'
test-docs:
name: Run docs tests
runs-on: ${{ matrix.os }}

View file

@ -36,9 +36,12 @@ jobs:
- 'clang-19'
- 'gcc-13'
include:
# macOS
# macOS x86
- os: macos-13
compiler: 'clang'
compiler: 'clang-19'
# macOS arm
- os: macos-latest
compiler: 'clang-19'
fail-fast: false
steps:
- name: Checkout Yosys

View file

@ -4,7 +4,7 @@ name: Build Wheels for PyPI
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * 0'
- cron: "0 10 * * 0"
jobs:
build_wheels:
@ -54,9 +54,6 @@ jobs:
fetch-depth: 0
submodules: true
persist-credentials: false
- if: ${{ matrix.os.family == 'linux' }}
name: "[Linux] Set up QEMU"
uses: docker/setup-qemu-action@v3
- uses: actions/setup-python@v5
- name: Get Boost Source
shell: bash
@ -68,14 +65,19 @@ jobs:
run: |
mkdir -p ffi
curl -L https://github.com/libffi/libffi/releases/download/v3.4.6/libffi-3.4.6.tar.gz | tar --strip-components=1 -xzC ffi
- if: ${{ matrix.os.family == 'linux' }}
name: "[Linux] Bison 3.8.2"
shell: bash
run: |
mkdir -p bison
curl -L https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz | tar --strip-components=1 -xzC bison
## Software installed by default in GitHub Action Runner VMs:
## https://github.com/actions/runner-images
- if: ${{ matrix.os.family == 'macos' }}
name: "[macOS] Flex/Bison"
run: |
brew install flex bison
echo "PATH=$(brew --prefix flex)/bin:$PATH" >> $GITHUB_ENV
echo "PATH=$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
echo "PATH=$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
- if: ${{ matrix.os.family == 'windows' }}
name: "[Windows] Flex/Bison"
run: |
@ -100,16 +102,20 @@ jobs:
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh
CIBW_ENVIRONMENT: >
OPTFLAGS=-O3
CXXFLAGS=-I./boost/pfx/include
LINKFLAGS=-L./boost/pfx/lib
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a'
PATH="$PWD/bison/src:$PATH"
CIBW_ENVIRONMENT_MACOS: >
OPTFLAGS=-O3
CXXFLAGS=-I./boost/pfx/include
LINKFLAGS=-L./boost/pfx/lib
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
MACOSX_DEPLOYMENT_TARGET=11
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang'
PATH="$PWD/bison/src:$PATH"
CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh
CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py
- uses: actions/upload-artifact@v4

View file

@ -20,11 +20,19 @@ import os
import yaml
import platform
import subprocess
from pathlib import Path
__dir__ = os.path.dirname(os.path.abspath(__file__))
__yosys_root__ = Path(__file__).absolute().parents[3]
for source in ["boost", "ffi", "bison"]:
if not (__yosys_root__ / source).is_dir():
print(
"You need to download boost, ffi and bison in a similar manner to wheels.yml first."
)
exit(-1)
workflow = yaml.safe_load(open(os.path.join(os.path.dirname(__dir__), "wheels.yml")))
with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f:
workflow = yaml.safe_load(f)
env = os.environ.copy()
@ -40,5 +48,5 @@ for key, value in cibw_step["env"].items():
continue
env[key] = value
env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS") or platform.machine()
env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine())
subprocess.check_call(["cibuildwheel"], env=env)

View file

@ -1,23 +1,37 @@
set -e
set -x
#!/bin/bash
set -e -x
# Build-time dependencies
## Linux Docker Images
if command -v yum &> /dev/null; then
yum install -y flex bison
yum install -y flex # manylinux's bison versions are hopelessly out of date
fi
if command -v apk &> /dev/null; then
apk add flex bison
fi
if ! printf '%s\n' '%require "3.8"' '%%' 'start: ;' | bison -o /dev/null /dev/stdin ; then
(
set -e -x
cd bison
./configure
make clean
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
)
fi
## macOS/Windows -- installed in GitHub Action itself, not container
# Build Static FFI (platform-dependent but not Python version dependent)
cd ffi
## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries
CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx
## Without this, SHELL has a space in its path which breaks the makefile
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
## Forces static library to be used in all situations
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc
# Runtime Dependencies
## Build Static FFI (platform-dependent but not Python version dependent)
(
set -e -x
cd ffi
## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries
CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx
make clean
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
## Forces static library to be used in all situations
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc
)

1
.gitignore vendored
View file

@ -47,6 +47,7 @@
/kernel/python_wrappers.cc
/boost
/ffi
/bison
/venv
/*.whl
/*.egg-info

View file

@ -6,9 +6,8 @@ brew "git"
brew "graphviz"
brew "pkg-config"
brew "python3"
brew "tcl-tk"
brew "xdot"
brew "bash"
brew "boost-python3"
brew "llvm"
brew "llvm@20"
brew "lld"

View file

@ -2,9 +2,24 @@
List of major changes and improvements between releases
=======================================================
Yosys 0.56 .. Yosys 0.57-dev
Yosys 0.57 .. Yosys 0.58-dev
--------------------------
Yosys 0.56 .. Yosys 0.57
--------------------------
* New commands and options
- Added "-initstates" option to "abstract" pass.
- Added "-set-assumes" option to "equiv_induct"
and "equiv_simple" passes.
- Added "-always" option to "raise_error" pass.
- Added "-hierarchy" option to "stat" pass.
- Added "-noflatten" option to "synth_quicklogic" pass.
* Various
- smtbmc: Support skipping steps in cover mode.
- write_btor: support $buf.
- read_verilog: support package import.
Yosys 0.55 .. Yosys 0.56
--------------------------
* New commands and options

View file

@ -132,8 +132,8 @@ ifeq ($(ENABLE_PYOSYS),1)
CXXFLAGS += -I$(BREW_PREFIX)/boost/include
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib
CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
@ -159,7 +159,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE
endif
YOSYS_VER := 0.56+0
YOSYS_VER := 0.57+0
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
@ -182,7 +182,7 @@ endif
OBJS = kernel/version_$(GIT_REV).o
bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c447ad.. | wc -l`/;" Makefile
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 3aca860.. | wc -l`/;" Makefile
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
@ -745,9 +745,9 @@ $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
ifeq ($(OS), Darwin)
$(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
$(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
else
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
endif
%.o: %.cc

View file

@ -80,10 +80,10 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
For example on Ubuntu Linux 16.04 LTS the following commands will install all
For example on Ubuntu Linux 22.04 LTS the following commands will install all
prerequisites for building yosys:
$ sudo apt-get install build-essential clang lld bison flex \
$ sudo apt-get install build-essential clang lld bison flex libfl-dev \
libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev

2
abc

@ -1 +1 @@
Subproject commit fa7fa163dacdf81bdcb72b2d2713fbe9984b62bb
Subproject commit 8827bafb7f288de6749dc6e30fa452f2040949c0

View file

@ -129,7 +129,7 @@ struct BtorWorker
std::replace(src.begin(), src.end(), ' ', '_');
if (srcsymbols.count(src) || module->count_id("\\" + src)) {
for (int i = 1;; i++) {
string s = stringf("%s-%d", src.c_str(), i);
string s = stringf("%s-%d", src, i);
if (!srcsymbols.count(s) && !module->count_id("\\" + s)) {
src = s;
break;
@ -192,7 +192,7 @@ struct BtorWorker
void btorf_push(const string &id)
{
if (verbose) {
f << indent << stringf(" ; begin %s\n", id.c_str());
f << indent << stringf(" ; begin %s\n", id);
indent += " ";
}
}
@ -201,7 +201,7 @@ struct BtorWorker
{
if (verbose) {
indent = indent.substr(4);
f << indent << stringf(" ; end %s\n", id.c_str());
f << indent << stringf(" ; end %s\n", id);
}
}
@ -509,7 +509,7 @@ struct BtorWorker
goto okay;
}
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos)))
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_)))
{
string btor_op;
if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not";
@ -521,9 +521,9 @@ struct BtorWorker
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
SigSpec sig = sigmap(cell->getPort(ID::Y));
// the $pos cell just passes through, all other cells need an actual operation applied
// the $pos/$buf cells just pass through, all other cells need an actual operation applied
int nid = nid_a;
if (cell->type != ID($pos))
if (!cell->type.in(ID($pos), ID($buf), ID($_BUF_)))
{
log_assert(!btor_op.empty());
int sid = get_bv_sid(width);

View file

@ -253,7 +253,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
const std::string extmoduleFileinfo = getFileinfo(cell);
// Emit extmodule header.
f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str());
f << stringf(" extmodule %s: %s\n", exported_name, extmoduleFileinfo);
// Emit extmodule ports.
for (auto wire : mod_instance->wires())
@ -280,7 +280,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
// Emit extmodule "defname" field. This is the name of the verilog blackbox
// that is used when verilog is emitted, so we use the name of mod_instance
// here.
f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str());
f << stringf("%sdefname = %s\n", indent, blackbox_name);
// Emit extmodule generic parameters.
for (const auto &p : cell->parameters)
@ -301,7 +301,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
param_name.end()
);
f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str());
f << stringf("%sparameter %s = %s\n", indent, param_name, param_value);
}
f << "\n";
@ -417,7 +417,7 @@ struct FirrtlWorker
else
{
string wire_id = make_id(chunk.wire->name);
new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset);
new_expr = stringf("bits(%s, %d, %d)", wire_id, chunk.offset + chunk.width - 1, chunk.offset);
}
if (expr.empty())
@ -477,7 +477,7 @@ struct FirrtlWorker
instanceOf;
std::string cellFileinfo = getFileinfo(cell);
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.c_str()));
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent, cell_name, cell_name_comment, instanceName, cellFileinfo));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
@ -518,7 +518,7 @@ struct FirrtlWorker
// as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig);
} else {
wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str()));
wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent, sinkExpr, sourceExpr, cellFileinfo));
}
}
}
@ -535,7 +535,7 @@ struct FirrtlWorker
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
// Deal with the difference in semantics between FIRRTL and verilog
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr, max_shift_string, max_shift_string, b_expr, max_shift_width_bits - 1);
}
return result;
}
@ -543,7 +543,7 @@ struct FirrtlWorker
void emit_module()
{
std::string moduleFileinfo = getFileinfo(module);
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo);
vector<string> port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs;
std::vector<Mem> memories = Mem::get_all_memories(module);
@ -602,7 +602,7 @@ struct FirrtlWorker
if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
{
string a_expr = make_expr(cell->getPort(ID::A));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
@ -610,7 +610,7 @@ struct FirrtlWorker
// Don't use the results of logical operations (a single bit) to control padding
if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
}
// Assume the FIRRTL width is a single bit.
@ -622,27 +622,27 @@ struct FirrtlWorker
firrtl_width = a_width;
} else if (cell->type == ID($logic_not)) {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
a_expr = stringf("%s, UInt(0)", a_expr);
}
else if (cell->type == ID($reduce_and)) primop = "andr";
else if (cell->type == ID($reduce_or)) primop = "orr";
else if (cell->type == ID($reduce_xor)) primop = "xorr";
else if (cell->type == ID($reduce_xnor)) {
primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str());
a_expr = stringf("xorr(%s)", a_expr);
}
else if (cell->type == ID($reduce_bool)) {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
a_expr = stringf("%s, %cInt<%d>(0)", a_expr, a_signed ? 'S' : 'U', a_width);
}
string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
string expr = stringf("%s(%s)", primop, a_expr);
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
expr = stringf("asUInt(%s)", expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@ -654,13 +654,13 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B));
std::string cellFileinfo = getFileinfo(cell);
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
// Expand the "A" operand to the result width
if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
a_width = y_width;
}
}
@ -670,7 +670,7 @@ struct FirrtlWorker
b_expr = "asSInt(" + b_expr + ")";
// Expand the "B" operand to the result width
if (b_width < y_width) {
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
b_expr = stringf("pad(%s, %d)", b_expr, y_width);
b_width = y_width;
}
}
@ -680,11 +680,11 @@ struct FirrtlWorker
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_)))
{
if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
a_width = y_width;
}
if (b_width < y_width) {
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
b_expr = stringf("pad(%s, %d)", b_expr, y_width);
b_width = y_width;
}
}
@ -856,23 +856,23 @@ struct FirrtlWorker
string expr;
// Deal with $xnor == ~^ (not xor)
if (primop == "xnor") {
expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
expr = stringf("not(xor(%s, %s))", a_expr, b_expr);
} else {
expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
expr = stringf("%s(%s, %s)", primop, a_expr, b_expr);
}
// Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
// If the operation is signed, the FIRRTL width will be 1 one bit larger.
if (extract_y_bits) {
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
expr = stringf("bits(%s, %d, 0)", expr, y_width - 1);
} else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
expr = stringf("pad(%s, %d)", expr.c_str(), y_width);
expr = stringf("pad(%s, %d)", expr, y_width);
}
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
expr = stringf("asUInt(%s)", expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@ -887,9 +887,9 @@ struct FirrtlWorker
string s_expr = make_expr(cell->getPort(ID::S));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str()));
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
string expr = stringf("mux(%s, %s, %s)", s_expr, b_expr, a_expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@ -911,9 +911,9 @@ struct FirrtlWorker
string expr = make_expr(cell->getPort(ID::D));
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str()));
wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent, y_id, width, clk_expr, cellFileinfo));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
continue;
@ -934,7 +934,7 @@ struct FirrtlWorker
int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1;
b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
}
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
string expr = stringf("dshr(%s, %s)", a_expr, b_expr);
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
@ -973,7 +973,7 @@ struct FirrtlWorker
// Verilog appears to treat the result as signed, so if the result is wider than "A",
// we need to pad.
if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
}
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str()));

View file

@ -172,7 +172,7 @@ struct IntersynthBackend : public Backend {
if (sig.size() != 0) {
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first));
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str());
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig));
}
}
for (auto &param : cell->parameters) {
@ -199,13 +199,13 @@ struct IntersynthBackend : public Backend {
if (!flag_notypes) {
*f << stringf("### Connection Types\n");
for (auto code : conntypes_code)
*f << stringf("%s", code.c_str());
*f << stringf("%s", code);
*f << stringf("\n### Cell Types\n");
for (auto code : celltypes_code)
*f << stringf("%s", code.c_str());
*f << stringf("%s", code);
}
*f << stringf("\n### Netlists\n");
*f << stringf("%s", netlists_code.c_str());
*f << stringf("%s", netlists_code);
for (auto lib : libs)
delete lib;

View file

@ -218,8 +218,8 @@ struct SimplecWorker
s[i] -= 'a' - 'A';
util_declarations.push_back("");
util_declarations.push_back(stringf("#ifndef %s", s.c_str()));
util_declarations.push_back(stringf("#define %s", s.c_str()));
util_declarations.push_back(stringf("#ifndef %s", s));
util_declarations.push_back(stringf("#define %s", s));
}
string util_get_bit(const string &signame, int n, int idx)
@ -232,33 +232,33 @@ struct SimplecWorker
if (generated_utils.count(util_name) == 0)
{
util_ifdef_guard(util_name);
util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str()));
util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name, sigtype(n)));
util_declarations.push_back(stringf("{"));
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset));
util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name, word_offset));
util_declarations.push_back(stringf("}"));
util_declarations.push_back(stringf("#endif"));
generated_utils.insert(util_name);
}
return stringf("%s(&%s)", util_name.c_str(), signame.c_str());
return stringf("%s(&%s)", util_name, signame);
}
string util_set_bit(const string &signame, int n, int idx, const string &expr)
{
if (n == 1 && idx == 0)
return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str());
return stringf(" %s.value_0_0 = %s;", signame, expr);
string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n);
if (generated_utils.count(util_name) == 0)
{
util_ifdef_guard(util_name);
util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str()));
util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name, sigtype(n)));
util_declarations.push_back(stringf("{"));
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
@ -266,9 +266,9 @@ struct SimplecWorker
#if 0
util_declarations.push_back(stringf(" if (value)"));
util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset));
util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name, word_offset));
util_declarations.push_back(stringf(" else"));
util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset));
util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name, word_offset));
#else
util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);",
value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset));
@ -279,7 +279,7 @@ struct SimplecWorker
generated_utils.insert(util_name);
}
return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str());
return stringf(" %s(&%s, %s);", util_name, signame, expr);
}
void create_module_struct(Module *mod)
@ -339,38 +339,38 @@ struct SimplecWorker
for (int i = 0; i < GetSize(topo.sorted); i++)
topoidx[mod->cell(topo.sorted[i])] = i;
string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str());
string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name));
for (int i = 0; i < GetSize(ifdef_name); i++)
if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z')
ifdef_name[i] -= 'a' - 'A';
struct_declarations.push_back("");
struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str()));
struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str()));
struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str()));
struct_declarations.push_back(stringf("#ifndef %s", ifdef_name));
struct_declarations.push_back(stringf("#define %s", ifdef_name));
struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name)));
struct_declarations.push_back("{");
struct_declarations.push_back(" // Input Ports");
for (Wire *w : mod->wires())
if (w->port_input)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
struct_declarations.push_back("");
struct_declarations.push_back(" // Output Ports");
for (Wire *w : mod->wires())
if (!w->port_input && w->port_output)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
struct_declarations.push_back("");
struct_declarations.push_back(" // Internal Wires");
for (Wire *w : mod->wires())
if (!w->port_input && !w->port_output)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
for (Cell *c : mod->cells())
if (design->module(c->type))
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c)));
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c)));
struct_declarations.push_back(stringf("};"));
struct_declarations.push_back("#endif");
@ -407,14 +407,14 @@ struct SimplecWorker
string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
string expr;
if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str());
if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr, b_expr);
if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr, b_expr);
if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr, b_expr);
if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr, b_expr);
if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr, b_expr);
if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr, b_expr);
if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr, b_expr);
if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr, b_expr);
log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -436,8 +436,8 @@ struct SimplecWorker
string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
string expr;
if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr, b_expr, c_expr);
if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr, b_expr, c_expr);
log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -461,8 +461,8 @@ struct SimplecWorker
string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
string expr;
if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr, b_expr, c_expr, d_expr);
if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr, b_expr, c_expr, d_expr);
log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -484,9 +484,9 @@ struct SimplecWorker
string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
// casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(),
cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(),
cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str());
string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr,
cell->type == ID($_NMUX_) ? "!" : "", b_expr,
cell->type == ID($_NMUX_) ? "!" : "", a_expr);
log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -518,7 +518,7 @@ struct SimplecWorker
continue;
if (verbose)
log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk)));
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk)));
}
for (SigBit bit : dirtysig)
@ -636,7 +636,7 @@ struct SimplecWorker
reactivated_cells.clear();
funct_declarations.push_back("");
funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name, cid(work->module->name)));
funct_declarations.push_back("{");
for (auto &line : preamble)
funct_declarations.push_back(line);

View file

@ -1875,6 +1875,11 @@ elif covermode:
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step))
smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
if step < skip_steps:
print_msg("Skipping step %d.." % (step))
step += 1
continue
while "1" in cover_mask:
print_msg("Checking cover reachability in step %d.." % (step))
smt_push()

View file

@ -51,16 +51,16 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg,
if (s.wire->port_id)
use_inames = true;
if (s.wire->width > 1)
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset);
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums), s.offset);
else
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str());
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums));
} else {
if (s == RTLIL::State::S0)
f << stringf(" %s", neg.c_str());
f << stringf(" %s", neg);
else if (s == RTLIL::State::S1)
f << stringf(" %s", pos.c_str());
f << stringf(" %s", pos);
else
f << stringf(" %s%d", ncpf.c_str(), nc_counter++);
f << stringf(" %s%d", ncpf, nc_counter++);
}
}
@ -119,7 +119,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
}
}
f << stringf(" %s\n", spice_id2str(cell->type).c_str());
f << stringf(" %s\n", spice_id2str(cell->type));
}
for (auto &conn : module->connections())
@ -127,7 +127,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++));
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str()));
f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf));
}
}
@ -242,18 +242,18 @@ struct SpiceBackend : public Backend {
ports.at(wire->port_id-1) = wire;
}
*f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str());
*f << stringf(".SUBCKT %s", spice_id2str(module->name));
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
if (wire->width > 1) {
for (int i = 0; i < wire->width; i++)
*f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i);
*f << stringf(" %s.%d", spice_id2str(wire->name), big_endian ? wire->width - 1 - i : i);
} else
*f << stringf(" %s", spice_id2str(wire->name).c_str());
*f << stringf(" %s", spice_id2str(wire->name));
}
*f << stringf("\n");
print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames);
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str());
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name));
}
if (!top_module_name.empty()) {

View file

@ -2374,8 +2374,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
}
for (auto w : module->wires())
// first dump input / output according to their order in module->ports
for (auto port : module->ports)
dump_wire(f, indent + " ", module->wire(port));
for (auto w : module->wires()) {
// avoid duplication
if (w->port_id)
continue;
dump_wire(f, indent + " ", w);
}
for (auto &mem : Mem::get_all_memories(module))
dump_memory(f, indent + " ", mem);

View file

@ -6,7 +6,7 @@ import os
project = 'YosysHQ Yosys'
author = 'YosysHQ GmbH'
copyright ='2025 YosysHQ GmbH'
yosys_ver = "0.56"
yosys_ver = "0.57"
# select HTML theme
html_theme = 'furo-ys'

View file

@ -88,18 +88,18 @@ Build prerequisites
^^^^^^^^^^^^^^^^^^^
A C++ compiler with C++17 support is required as well as some standard tools
such as GNU Flex, GNU Bison, Make and Python. Some additional tools: readline,
libffi, Tcl and zlib; are optional but enabled by default (see
such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional
tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
`show` command to display schematics.
Installing all prerequisites for Ubuntu 20.04:
Installing all prerequisites for Ubuntu 22.04:
.. code:: console
sudo apt-get install gperf build-essential bison flex \
libreadline-dev gawk tcl-dev libffi-dev git graphviz \
xdot pkg-config python3 libboost-system-dev \
sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \
libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev
Installing all prerequisites for macOS 13 (with Homebrew):
@ -137,8 +137,9 @@ For Cygwin use the following command to install all prerequisites, or select the
minimum required version of Python is 3.11. This means that Cygwin is not
compatible with many of the Python-based frontends. While this does not
currently prevent Yosys itself from working, no guarantees are made for
continued support. It is instead recommended to use Windows Subsystem for
Linux (WSL) and follow the instructions for Ubuntu.
continued support. You may also need to specify `CXXSTD=gnu++17` to resolve
missing `strdup` function when using gcc. It is instead recommended to use
Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu.
..
For MSYS2 (MINGW64):

View file

@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree.
The lexer does little more than identifying all keywords and literals recognised
by the Yosys Verilog frontend.
The lexer keeps track of the current location in the Verilog source code using
some global variables. These variables are used by the constructor of AST nodes
to annotate each node with the source code location it originated from.
The lexer keeps track of the current location in the Verilog source code with
a ``VerilogLexer::out_loc`` and uses it to construct parser-defined
symbol objects.
Finally the lexer identifies and handles special comments such as "``// synopsys
translate_off``" and "``// synopsys full_case``". (It is recommended to use
@ -178,21 +178,22 @@ properties:
- | Source code location
| Each ``AST::AstNode`` is automatically annotated with the current source
code location by the ``AST::AstNode`` constructor. It is stored in the
``std::string filename`` and ``int linenum`` member variables.
code location by the ``AST::AstNode`` constructor. The ``location`` type
is a manual reimplementation of the bison-provided location type. This
type is defined at ``frontends/verilog/verilog_location.h``.
The ``AST::AstNode`` constructor can be called with up to two child nodes that
are automatically added to the list of child nodes for the new object. This
The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This
simplifies the creation of AST nodes for simple expressions a bit. For example
the bison code for parsing multiplications:
.. code:: none
:number-lines:
:number-lines:
basic_expr '*' attr basic_expr {
$$ = new AstNode(AST_MUL, $1, $4);
append_attr($$, $3);
} |
basic_expr TOK_ASTER attr basic_expr {
$$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4);
append_attr($$.get(), $3);
} |
The generated AST data structure is then passed directly to the AST frontend
that performs the actual conversion to RTLIL.
@ -204,7 +205,7 @@ tree respectively.
Transforming AST to RTLIL
-------------------------
The AST Frontend converts a set of modules in AST representation to modules in
The AST frontend converts a set of modules in AST representation to modules in
RTLIL representation and adds them to the current design. This is done in two
steps: simplification and RTLIL generation.

View file

@ -38,9 +38,7 @@ using namespace AST_INTERNAL;
// instantiate global variables (public API)
namespace AST {
std::string current_filename;
void (*set_line_num)(int) = NULL;
int (*get_line_num)() = NULL;
bool sv_mode_but_global_and_used_for_literally_one_condition;
unsigned long long astnodes = 0;
unsigned long long astnode_count() { return astnodes; }
}
@ -174,6 +172,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_MODPORT)
X(AST_MODPORTMEMBER)
X(AST_PACKAGE)
X(AST_IMPORT)
X(AST_WIRETYPE)
X(AST_TYPEDEF)
X(AST_STRUCT)
@ -192,7 +191,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
if (attributes.count(id) == 0)
return false;
AstNode *attr = attributes.at(id);
auto& attr = attributes.at(id);
if (attr->type != AST_CONSTANT)
attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str());
@ -201,7 +200,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// create new node (AstNode constructor)
// (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4)
AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4)
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
@ -209,7 +208,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
astnodes++;
this->type = type;
filename = current_filename;
location = loc;
is_input = false;
is_output = false;
is_reg = false;
@ -239,56 +238,73 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
in_param = false;
if (child1)
children.push_back(child1);
children.push_back(std::move(child1));
if (child2)
children.push_back(child2);
children.push_back(std::move(child2));
if (child3)
children.push_back(child3);
children.push_back(std::move(child3));
if (child4)
children.push_back(child4);
children.push_back(std::move(child4));
fixup_hierarchy_flags();
}
// create a (deep recursive) copy of a node
AstNode *AstNode::clone() const
std::unique_ptr<AstNode> AstNode::clone() const
{
AstNode *that = new AstNode;
*that = *this;
for (auto &it : that->children)
it = it->clone();
for (auto &it : that->attributes)
it.second = it.second->clone();
that->set_in_lvalue_flag(false);
that->set_in_param_flag(false);
that->fixup_hierarchy_flags(); // fixup to set flags on cloned children
auto that = std::make_unique<AstNode>(this->location, this->type);
cloneInto(*that.get());
return that;
}
// create a (deep recursive) copy of a node use 'other' as target root node
void AstNode::cloneInto(AstNode *other) const
void AstNode::cloneInto(AstNode &other) const
{
AstNode *tmp = clone();
tmp->in_lvalue_from_above = other->in_lvalue_from_above;
tmp->in_param_from_above = other->in_param_from_above;
other->delete_children();
*other = *tmp;
tmp->children.clear();
tmp->attributes.clear();
other->fixup_hierarchy_flags();
delete tmp;
other.type = type;
other.str = str;
other.bits = bits;
other.is_input = is_input;
other.is_output = is_output;
other.is_reg = is_reg;
other.is_logic = is_logic;
other.is_signed = is_signed;
other.is_string = is_string;
other.is_wand = is_wand;
other.is_wor = is_wor;
other.range_valid = range_valid;
other.range_swapped = range_swapped;
other.was_checked = was_checked;
other.is_unsized = is_unsized;
other.is_custom_type = is_custom_type;
other.port_id = port_id,
other.range_left = range_left,
other.range_right = range_right;
other.integer = integer;
other.realvalue = realvalue;
other.is_enum = is_enum;
other.dimensions = dimensions;
other.unpacked_dimensions = unpacked_dimensions;
other.id2ast = id2ast;
other.basic_prep = basic_prep;
other.lookahead = lookahead;
other.location = location;
other.in_lvalue = in_lvalue;
other.in_param = in_param;
// Keep in_lvalue_from_above and in_param_from_above untouched
other.delete_children();
for (auto& child : this->children)
other.children.push_back(child->clone());
for (auto& [key, val] : this->attributes)
other.attributes[key] = (val->clone());
// fixup to set flags on cloned children
other.fixup_hierarchy_flags();
}
// delete all children in this node
void AstNode::delete_children()
{
for (auto &it : children)
delete it;
children.clear();
for (auto &it : attributes)
delete it.second;
attributes.clear();
}
@ -423,18 +439,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
{
case AST_MODULE:
fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str());
for (auto child : children)
for (const auto& child : children)
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str());
first = false;
}
fprintf(f, ");\n");
for (auto child : children)
for (const auto& child : children)
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM)
child->dumpVlog(f, indent + " ");
else
rem_children1.push_back(child);
rem_children1.push_back(child.get());
for (auto child : rem_children1)
if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY)
@ -470,7 +486,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str());
if (is_signed)
fprintf(f, " signed");
for (auto child : children) {
for (const auto& child : children) {
fprintf(f, " ");
child->dumpVlog(f, "");
}
@ -486,7 +502,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "%s" "memory", indent.c_str());
if (is_signed)
fprintf(f, " signed");
for (auto child : children) {
for (const auto& child : children) {
fprintf(f, " ");
child->dumpVlog(f, "");
if (first)
@ -500,7 +516,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
if (0) { case AST_MEMINIT: txt = "@meminit@"; }
if (0) { case AST_MEMWR: txt = "@memwr@"; }
fprintf(f, "%s%s", indent.c_str(), txt.c_str());
for (auto child : children) {
for (const auto& child : children) {
fprintf(f, first ? "(" : ", ");
child->dumpVlog(f, "");
first = false;
@ -517,7 +533,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
else
fprintf(f, "[%d:%d]", range_left, range_right);
} else {
for (auto child : children) {
for (const auto& child : children) {
fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, "");
first = false;
@ -527,13 +543,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break;
case AST_MULTIRANGE:
for (auto child : children)
for (const auto& child : children)
child->dumpVlog(f, "");
break;
case AST_ALWAYS:
fprintf(f, "%s" "always @", indent.c_str());
for (auto child : children) {
for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
continue;
fprintf(f, first ? "(" : ", ");
@ -541,7 +557,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
first = false;
}
fprintf(f, first ? "*\n" : ")\n");
for (auto child : children) {
for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
child->dumpVlog(f, indent + " ");
}
@ -549,7 +565,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_INITIAL:
fprintf(f, "%s" "initial\n", indent.c_str());
for (auto child : children) {
for (const auto& child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
child->dumpVlog(f, indent + " ");
}
@ -562,7 +578,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, "posedge ");
if (type == AST_NEGEDGE)
fprintf(f, "negedge ");
for (auto child : children)
for (const auto& child : children)
child->dumpVlog(f, "");
break;
@ -574,7 +590,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
else
fprintf(f, "%s", id2vl(str).c_str());
}
for (auto child : children)
for (const auto& child : children)
child->dumpVlog(f, "");
break;
@ -602,7 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
children[0]->dumpVlog(f, indent);
} else {
fprintf(f, "%s" "begin\n", indent.c_str());
for (auto child : children)
for (const auto& child : children)
child->dumpVlog(f, indent + " ");
fprintf(f, "%s" "end\n", indent.c_str());
}
@ -618,7 +634,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
children[0]->dumpVlog(f, "");
fprintf(f, ")\n");
for (size_t i = 1; i < children.size(); i++) {
AstNode *child = children[i];
const auto& child = children[i];
child->dumpVlog(f, indent + " ");
}
fprintf(f, "%s" "endcase\n", indent.c_str());
@ -627,7 +643,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_COND:
case AST_CONDX:
case AST_CONDZ:
for (auto child : children) {
for (const auto& child : children) {
if (child->type == AST_BLOCK) {
fprintf(f, ":\n");
child->dumpVlog(f, indent + " ");
@ -663,7 +679,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT:
fprintf(f, "{");
for (int i = GetSize(children)-1; i >= 0; i--) {
auto child = children[i];
const auto& child = children[i];
if (!first)
fprintf(f, ", ");
child->dumpVlog(f, "");
@ -818,16 +834,16 @@ bool AstNode::contains(const AstNode *other) const
{
if (this == other)
return true;
for (auto child : children)
for (const auto& child : children)
if (child->contains(other))
return true;
return false;
}
// create an AST node for a constant (using a 32 bit int as value)
AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
std::unique_ptr<AstNode> AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width)
{
AstNode *node = new AstNode(AST_CONSTANT);
auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->integer = v;
node->is_signed = is_signed;
for (int i = 0; i < width; i++) {
@ -841,9 +857,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
}
// create an AST node for a constant (using a bit vector as value)
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{
AstNode *node = new AstNode(AST_CONSTANT);
auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->is_signed = is_signed;
node->bits = v;
for (size_t i = 0; i < 32; i++) {
@ -859,15 +875,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
return node;
}
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed)
{
return mkconst_bits(v, is_signed, false);
return mkconst_bits(loc, v, is_signed, false);
}
// create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v)
{
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
auto node = mkconst_str(loc, RTLIL::Const(v).decode_string());
while (GetSize(node->bits) < GetSize(v))
node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v);
@ -875,14 +891,14 @@ AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
}
// create an AST node for a constant (using a string as value)
AstNode *AstNode::mkconst_str(const std::string &str)
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::string &str)
{
AstNode *node;
std::unique_ptr<AstNode> node;
// LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered
// equivalent to the ASCII NUL ("\0")
if (str.empty()) {
node = AstNode::mkconst_int(0, false, 8);
node = AstNode::mkconst_int(loc, 0, false, 8);
} else {
std::vector<RTLIL::State> data;
data.reserve(str.size() * 8);
@ -893,7 +909,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
ch = ch >> 1;
}
}
node = AstNode::mkconst_bits(data, false);
node = AstNode::mkconst_bits(loc, data, false);
}
node->is_string = true;
@ -902,18 +918,19 @@ AstNode *AstNode::mkconst_str(const std::string &str)
}
// create a temporary register
AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
std::unique_ptr<AstNode> AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
{
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true)));
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
auto wire_owned = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true)));
auto* wire = wire_owned.get();
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
if (nosync)
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false));
wire->is_signed = is_signed;
wire->is_logic = true;
mod->children.push_back(wire);
mod->children.push_back(std::move(wire_owned));
while (wire->simplify(true, 1, -1, false)) { }
AstNode *ident = new AstNode(AST_IDENTIFIER);
auto ident = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ident->str = wire->str;
ident->id2ast = wire;
@ -967,10 +984,9 @@ RTLIL::Const AstNode::asParaConst() const
{
if (type == AST_REALVALUE)
{
AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue));
auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue));
RTLIL::Const val = strnode->asAttrConst();
val.flags |= RTLIL::CONST_FLAG_REAL;
delete strnode;
return val;
}
@ -1070,7 +1086,7 @@ RTLIL::Const AstNode::realAsConst(int width)
std::string AstNode::loc_string() const
{
return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);
return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column);
}
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
@ -1078,7 +1094,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
obj->attributes[ID::src] = ast->loc_string();
}
static bool param_has_no_default(const AstNode *param) {
static bool param_has_no_default(const AstNode* param) {
const auto &children = param->children;
log_assert(param->type == AST_PARAMETER);
log_assert(children.size() <= 2);
@ -1086,7 +1102,7 @@ static bool param_has_no_default(const AstNode *param) {
(children.size() == 1 && children[0]->type == AST_RANGE);
}
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false)
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr<AstNode> original_ast = NULL, bool quiet = false)
{
log_assert(current_scope.empty());
log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
@ -1100,15 +1116,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
AstModule *module = new AstModule;
current_module = module;
module->ast = NULL;
module->ast = nullptr;
module->name = ast->str;
set_src_attr(module, ast);
module->set_bool_attribute(ID::cells_not_processed);
current_ast_mod = ast;
AstNode *ast_before_simplify;
std::unique_ptr<AstNode> ast_before_simplify;
if (original_ast != NULL)
ast_before_simplify = original_ast;
ast_before_simplify = std::move(original_ast);
else
ast_before_simplify = ast->clone();
@ -1125,15 +1141,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
if (!defer)
{
for (const AstNode *node : ast->children)
if (node->type == AST_PARAMETER && param_has_no_default(node))
for (auto& node : ast->children)
if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str());
bool blackbox_module = flag_lib;
if (!blackbox_module && !flag_noblackbox) {
blackbox_module = true;
for (auto child : ast->children) {
for (const auto& child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output))
continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
@ -1163,36 +1179,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (flag_nowb && ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox);
}
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (ast->attributes.count(ID::lib_whitebox)) {
if (!flag_lib || flag_nowb) {
delete ast->attributes.at(ID::lib_whitebox);
ast->attributes.erase(ID::lib_whitebox);
} else {
if (ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox);
}
AstNode *n = ast->attributes.at(ID::lib_whitebox);
ast->set_attribute(ID::whitebox, n);
ast->attributes.erase(ID::lib_whitebox);
if (flag_lib && !flag_nowb) {
ast->attributes[ID::whitebox] = std::move(
ast->attributes[ID::lib_whitebox]
);
}
ast->attributes.erase(ID::lib_whitebox);
}
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (!blackbox_module && ast->attributes.count(ID::blackbox)) {
AstNode *n = ast->attributes.at(ID::blackbox);
auto& n = ast->attributes.at(ID::blackbox);
if (n->type != AST_CONSTANT)
ast->input_error("Got blackbox attribute with non-constant value!\n");
blackbox_module = n->asBool();
}
if (blackbox_module && ast->attributes.count(ID::whitebox)) {
AstNode *n = ast->attributes.at(ID::whitebox);
auto& n = ast->attributes.at(ID::whitebox);
if (n->type != AST_CONSTANT)
ast->input_error("Got whitebox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
@ -1200,62 +1213,59 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
if (ast->attributes.count(ID::noblackbox)) {
if (blackbox_module) {
AstNode *n = ast->attributes.at(ID::noblackbox);
auto& n = ast->attributes.at(ID::noblackbox);
if (n->type != AST_CONSTANT)
ast->input_error("Got noblackbox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
}
delete ast->attributes.at(ID::noblackbox);
ast->attributes.erase(ID::noblackbox);
}
for (auto &attr: ast->attributes)
log_assert((bool)attr.second.get());
if (blackbox_module)
{
if (ast->attributes.count(ID::whitebox)) {
delete ast->attributes.at(ID::whitebox);
ast->attributes.erase(ID::whitebox);
}
if (ast->attributes.count(ID::lib_whitebox)) {
delete ast->attributes.at(ID::lib_whitebox);
ast->attributes.erase(ID::lib_whitebox);
}
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
std::vector<std::unique_ptr<AstNode>> new_children;
for (auto& child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
new_children.push_back(child);
new_children.push_back(std::move(child));
} else if (child->type == AST_PARAMETER) {
new_children.push_back(child);
new_children.push_back(std::move(child));
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else {
delete child;
new_children.push_back(std::move(child));
}
}
ast->children.swap(new_children);
if (ast->attributes.count(ID::blackbox) == 0) {
ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false));
ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false));
}
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
for (auto &attr : ast->attributes) {
log_assert((bool)attr.second.get());
if (attr.second->type != AST_CONSTANT)
ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
const auto& node = ast->children[i];
if (node->type == AST_WIRE || node->type == AST_MEMORY)
node->genRTLIL();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
const auto& node = ast->children[i];
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
node->genRTLIL();
}
@ -1263,7 +1273,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ignoreThisSignalsInInitial.sort_and_unify();
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
const auto& node = ast->children[i];
if (node->type == AST_INITIAL)
node->genRTLIL();
}
@ -1277,14 +1287,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
continue;
module->attributes[attr.first] = attr.second->asAttrConst();
}
for (const AstNode *node : ast->children)
for (const auto& node : ast->children)
if (node->type == AST_PARAMETER)
current_module->avail_parameters(node->str);
}
if (ast->type == AST_INTERFACE)
module->set_bool_attribute(ID::is_interface);
module->ast = ast_before_simplify;
module->ast = std::move(ast_before_simplify);
module->nolatches = flag_nolatches;
module->nomeminit = flag_nomeminit;
module->nomem2reg = flag_nomem2reg;
@ -1311,8 +1321,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
RTLIL::Module *
AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
RTLIL::Module *old_module,
AstNode *new_ast,
AstNode *original_ast)
AST::AstNode *new_ast,
std::unique_ptr<AstNode> original_ast)
{
// The old module will be deleted. Rename and mark for deletion, using
// a static counter to make sure we get a unique name.
@ -1335,7 +1345,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
}
// Generate RTLIL from AST for the new module and add to the design:
RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast);
RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast));
if (is_top)
new_module->set_bool_attribute(ID::top);
@ -1347,17 +1357,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
static void rename_in_package_stmts(AstNode *pkg)
{
std::unordered_set<std::string> idents;
for (AstNode *item : pkg->children)
for (auto& item : pkg->children)
idents.insert(item->str);
std::function<void(AstNode*)> rename =
[&rename, &idents, pkg](AstNode *node) {
for (AstNode *child : node->children) {
std::function<void(std::unique_ptr<AstNode>&)> rename =
[&rename, &idents, pkg](std::unique_ptr<AstNode>& node) {
for (auto& child : node->children) {
if (idents.count(child->str))
child->str = pkg->str + "::" + child->str.substr(1);
rename(child);
}
};
for (AstNode *item : pkg->children)
for (auto& item : pkg->children)
if (item->type == AST_FUNCTION || item->type == AST_TASK)
rename(item);
}
@ -1390,17 +1400,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
ast->fixup_hierarchy_flags(true);
log_assert(current_ast->type == AST_DESIGN);
for (AstNode *child : current_ast->children)
for (const auto& child : current_ast->children)
{
if (child->type == AST_MODULE || child->type == AST_INTERFACE)
{
for (auto n : design->verilog_globals)
for (auto& n : design->verilog_globals)
child->children.push_back(n->clone());
// append nodes from previous packages using package-qualified names
for (auto &n : design->verilog_packages) {
for (auto& n : design->verilog_packages) {
for (auto &o : n->children) {
AstNode *cloned_node = o->clone();
auto cloned_node = o->clone();
// log("cloned node %s\n", type2str(cloned_node->type).c_str());
if (cloned_node->type == AST_ENUM) {
for (auto &e : cloned_node->children) {
@ -1410,7 +1420,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
} else {
cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
}
child->children.push_back(cloned_node);
child->children.push_back(std::move(cloned_node));
}
}
@ -1419,8 +1429,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
bool defer_local = defer;
if (!defer_local)
for (const AstNode *node : child->children)
if (node->type == AST_PARAMETER && param_has_no_default(node))
for (const auto& node : child->children)
if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
{
log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str());
defer_local = true;
@ -1434,7 +1444,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
if (design->has(child->str)) {
RTLIL::Module *existing_mod = design->module(child->str);
if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str());
log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str());
} else if (nooverwrite) {
log("Ignoring re-definition of module `%s' at %s.\n",
child->str.c_str(), child->loc_string().c_str());
@ -1447,13 +1457,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
}
}
process_module(design, child, defer_local);
process_module(design, child.get(), defer_local);
current_ast_mod = nullptr;
}
else if (child->type == AST_PACKAGE) {
// process enum/other declarations
child->simplify(true, 1, -1, false);
rename_in_package_stmts(child);
rename_in_package_stmts(child.get());
design->verilog_packages.push_back(child->clone());
current_scope.clear();
}
@ -1470,16 +1480,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
current_scope.clear();
}
}
}
// AstModule destructor
AstModule::~AstModule()
{
if (ast != NULL)
delete ast;
}
// An interface port with modport is specified like this:
// <interface_name>.<modport_name>
// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
@ -1516,7 +1519,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
for (auto &ch : intf->children)
if (ch->type == AST_MODPORT)
if (ch->str == name) // Modport found
return ch;
return ch.get();
return NULL;
}
@ -1524,7 +1527,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
{
for (auto w : intfmodule->wires()){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
auto loc = module_ast->location;
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
std::string origname = log_id(w->name);
std::string newname = intfname + "." + origname;
wire->str = newname;
@ -1543,16 +1547,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
}
}
if (found_in_modport) {
module_ast->children.push_back(wire);
}
else { // If not found in modport, do not create port
delete wire;
module_ast->children.push_back(std::move(wire));
}
}
else { // If no modport, set inout
wire->is_input = true;
wire->is_output = true;
module_ast->children.push_back(wire);
module_ast->children.push_back(std::move(wire));
}
}
}
@ -1570,7 +1571,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
log("Reprocessing module %s because instantiated module %s has become available.\n",
log_id(name), log_id(modname));
loadconfig();
process_and_replace_module(design, this, ast, NULL);
process_and_replace_module(design, this, ast.get(), NULL);
return true;
}
}
@ -1583,32 +1584,33 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
{
loadconfig();
AstNode *new_ast = ast->clone();
auto new_ast = ast->clone();
auto loc = ast->location;
for (auto &intf : local_interfaces) {
std::string intfname = intf.first.str();
RTLIL::Module *intfmodule = intf.second;
for (auto w : intfmodule->wires()){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
std::string newname = log_id(w->name);
newname = intfname + "." + newname;
wire->str = newname;
new_ast->children.push_back(wire);
new_ast->children.push_back(std::move(wire));
}
}
AstNode *ast_before_replacing_interface_ports = new_ast->clone();
auto ast_before_replacing_interface_ports = new_ast->clone();
// Explode all interface ports. Note this will only have an effect on 'top
// level' modules. Other sub-modules will have their interface ports
// exploded via the derive(..) function
for (size_t i =0; i<new_ast->children.size(); i++)
{
AstNode *ch2 = new_ast->children[i];
const auto& ch2 = new_ast->children[i];
if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
std::string name_port = ch2->str; // Name of the interface port
if (ch2->children.size() > 0) {
for(size_t j=0; j<ch2->children.size();j++) {
AstNode *ch = ch2->children[j];
const auto& ch = ch2->children[j];
if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
std::string interface_type = res.first;
@ -1616,11 +1618,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
if (design->module(interface_type) != nullptr) {
// Add a cell to the module corresponding to the interface port such that
// it can further propagated down if needed:
AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
auto celltype_for_intf = std::make_unique<AstNode>(loc, AST_CELLTYPE);
celltype_for_intf->str = interface_type;
AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
auto cell_for_intf = std::make_unique<AstNode>(loc, AST_CELL, std::move(celltype_for_intf));
cell_for_intf->str = name_port + "_inst_from_top_dummy";
new_ast->children.push_back(cell_for_intf);
new_ast->children.push_back(std::move(cell_for_intf));
// Get all members of this non-overridden dummy interface instance:
RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming
@ -1628,9 +1630,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// present in design->modules_
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
std::string interface_modport_compare_str = "\\" + interface_modport;
AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport
// Iterate over all wires in the interface and add them to the module:
explode_interface_port(new_ast, intfmodule, name_port, modport);
explode_interface_port(new_ast.get(), intfmodule, name_port, modport);
}
break;
}
@ -1642,9 +1644,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// Generate RTLIL from AST for the new module and add to the design,
// renaming this module to move it out of the way.
RTLIL::Module* new_module =
process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports);
delete new_ast;
process_and_replace_module(design, this, new_ast.get(), std::move(ast_before_replacing_interface_ports));
// Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
new_module->set_bool_attribute(ID::interfaces_replaced_in_module);
@ -1654,7 +1654,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool /*mayfail*/)
{
AstNode *new_ast = NULL;
std::unique_ptr<AstNode> new_ast = NULL;
std::string modname = derive_common(design, parameters, &new_ast);
// Since interfaces themselves may be instantiated with different parameters,
@ -1690,14 +1690,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
if (modports.count(intfname) > 0) {
std::string interface_modport = modports.at(intfname).str();
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
AstNode *ast_node_of_interface = ast_module_of_interface->ast;
AstNode *ast_node_of_interface = ast_module_of_interface->ast.get();
modport = find_modport(ast_node_of_interface, interface_modport);
}
// Iterate over all wires in the interface and add them to the module:
explode_interface_port(new_ast, intfmodule, intfname, modport);
explode_interface_port(new_ast.get(), intfmodule, intfname, modport);
}
process_module(design, new_ast, false);
process_module(design, new_ast.get(), false);
design->module(modname)->check();
RTLIL::Module* mod = design->module(modname);
@ -1734,7 +1734,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
}
delete new_ast;
return modname;
}
@ -1743,18 +1742,17 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
{
bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox);
AstNode *new_ast = NULL;
std::unique_ptr<AstNode> new_ast = NULL;
std::string modname = derive_common(design, parameters, &new_ast, quiet);
if (!design->has(modname) && new_ast) {
new_ast->str = modname;
process_module(design, new_ast, false, NULL, quiet);
process_module(design, new_ast.get(), false, NULL, quiet);
design->module(modname)->check();
} else if (!quiet) {
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
}
delete new_ast;
return modname;
}
@ -1784,7 +1782,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto
}
// create a new parametric module (when needed) and return the name of the generated module
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, AstNode **new_ast_out, bool quiet)
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, std::unique_ptr<AstNode>* new_ast_out, bool quiet)
{
std::string stripped_name = name.str();
(*new_ast_out) = nullptr;
@ -1794,7 +1792,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
int para_counter = 0;
std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
for (const auto child : ast->children) {
for (const auto& child : ast->children) {
if (child->type != AST_PARAMETER)
continue;
para_counter++;
@ -1828,12 +1826,13 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
pool<IdString> rewritten;
rewritten.reserve(GetSize(parameters));
AstNode *new_ast = ast->clone();
auto new_ast = ast->clone();
auto loc = ast->location;
if (!new_ast->attributes.count(ID::hdlname))
new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1)));
new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1)));
para_counter = 0;
for (auto child : new_ast->children) {
for (auto& child : new_ast->children) {
if (child->type != AST_PARAMETER)
continue;
para_counter++;
@ -1851,16 +1850,15 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
}
continue;
rewrite_parameter:
if (param_has_no_default(child))
if (param_has_no_default(child.get()))
child->children.insert(child->children.begin(), nullptr);
delete child->children.at(0);
if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) {
child->children[0] = new AstNode(AST_REALVALUE);
child->children[0] = std::make_unique<AstNode>(loc, AST_REALVALUE);
child->children[0]->realvalue = std::stod(it->second.decode_string());
} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
child->children[0] = AstNode::mkconst_str(it->second.decode_string());
child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
else
child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
rewritten.insert(it->first);
}
@ -1868,17 +1866,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
for (const auto &param : parameters) {
if (rewritten.count(param.first))
continue;
AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER));
auto defparam = std::make_unique<AstNode>(loc, AST_DEFPARAM, std::make_unique<AstNode>(loc, AST_IDENTIFIER));
defparam->children[0]->str = param.first.str();
if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string()));
defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string()));
else
defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
new_ast->children.push_back(defparam);
defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
new_ast->children.push_back(std::move(defparam));
}
new_ast->fixup_hierarchy_flags(true);
(*new_ast_out) = new_ast;
new_ast_out->reset(new_ast.release());
return modname;
}
@ -1928,7 +1926,7 @@ void AstNode::input_error(const char *format, ...) const
{
va_list ap;
va_start(ap, format);
logv_file_error(filename, location.first_line, format, ap);
logv_file_error(*location.begin.filename, location.begin.line, format, ap);
}
YOSYS_NAMESPACE_END

View file

@ -28,6 +28,7 @@
#include "kernel/rtlil.h"
#include "kernel/fmt.h"
#include "frontends/verilog/verilog_location.h"
#include <stdint.h>
#include <set>
@ -153,6 +154,7 @@ namespace AST
AST_MODPORT,
AST_MODPORTMEMBER,
AST_PACKAGE,
AST_IMPORT,
AST_WIRETYPE,
AST_TYPEDEF,
@ -162,12 +164,7 @@ namespace AST
AST_BIND
};
struct AstSrcLocType {
unsigned int first_line, last_line;
unsigned int first_column, last_column;
AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}
AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
};
using AstSrcLocType = Location;
// convert an node type to a string (e.g. for debug output)
std::string type2str(AstNodeType type);
@ -183,10 +180,10 @@ namespace AST
AstNodeType type;
// the list of child nodes for this node
std::vector<AstNode*> children;
std::vector<std::unique_ptr<AstNode>> children;
// the list of attributes assigned to this node
std::map<RTLIL::IdString, AstNode*> attributes;
std::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;
bool get_bool_attribute(RTLIL::IdString id);
// node content - most of it is unused in most node types
@ -212,7 +209,7 @@ namespace AST
int unpacked_dimensions;
// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
AstNode* id2ast;
// this is used by simplify to detect if basic analysis has been performed already on the node
bool basic_prep;
@ -223,7 +220,6 @@ namespace AST
// this is the original sourcecode location that resulted in this AST node
// it is automatically set by the constructor using AST::current_filename and
// the AST::get_line_num() callback function.
std::string filename;
AstSrcLocType location;
// are we embedded in an lvalue, param?
@ -234,9 +230,9 @@ namespace AST
bool in_param_from_above;
// creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
AstNode *clone() const;
void cloneInto(AstNode *other) const;
AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
std::unique_ptr<AstNode> clone() const;
void cloneInto(AstNode &other) const;
void delete_children();
~AstNode();
@ -265,14 +261,14 @@ namespace AST
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);
void replace_result_wire_name_in_function(const std::string &from, const std::string &to);
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
std::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
void expand_genblock(const std::string &prefix);
void label_genblks(std::set<std::string>& existing, int &counter);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
void mem2reg_remove(pool<AstNode*> &mem2reg_set);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
bool detect_latch(const std::string &var);
const RTLIL::Module* lookup_cell_module();
@ -288,7 +284,7 @@ namespace AST
};
bool has_const_only_constructs();
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
std::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);
bool is_simple_const_expr();
// helper for parsing format strings
@ -305,29 +301,30 @@ namespace AST
std::vector<RTLIL::Binding *> genBindings() const;
// used by genRTLIL() for detecting expression width and sign
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
// create RTLIL code for this AST node
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);
// compare AST nodes
bool operator==(const AstNode &other) const;
bool operator!=(const AstNode &other) const;
bool contains(const AstNode *other) const;
AstNode operator=(AstNode) = delete;
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
// helper function to create an AST node for a temporary register
AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
@ -356,12 +353,12 @@ namespace AST
// helper to clone the node with some of its subexpressions replaced with zero (this is used
// to evaluate widths of dynamic ranges)
AstNode *clone_at_zero();
std::unique_ptr<AstNode> clone_at_zero();
void set_attribute(RTLIL::IdString key, AstNode *node)
void set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)
{
attributes[key] = node;
node->set_in_param_flag(true);
attributes[key] = std::move(node);
}
// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
@ -377,7 +374,7 @@ namespace AST
void fixup_hierarchy_flags(bool force_descend = false);
// helpers for indexing
AstNode *make_index_range(AstNode *node, bool unpacked_range = false);
std::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);
AstNode *get_struct_member() const;
// helper to print errors from simplify/genrtlil code
@ -391,12 +388,11 @@ namespace AST
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
std::unique_ptr<AstNode> ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
~AstModule() override;
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail) override;
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, AstNode **new_ast_out, bool quiet = false);
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);
void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
bool reprocess_if_necessary(RTLIL::Design *design) override;
RTLIL::Module *clone() const override;
@ -406,9 +402,9 @@ namespace AST
// this must be set by the language frontend before parsing the sources
// the AstNode constructor then uses current_filename and get_line_num()
// to initialize the filename and linenum properties of new nodes
extern std::string current_filename;
extern void (*set_line_num)(int);
extern int (*get_line_num)();
// extern std::string current_filename;
// also set by the language frontend to control some AST processing
extern bool sv_mode_but_global_and_used_for_literally_one_condition;
// for stats
unsigned long long astnode_count();
@ -418,7 +414,7 @@ namespace AST
void use_internal_line_num();
// call a DPI function
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
// Helper functions related to handling SystemVerilog interfaces
std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
@ -464,7 +460,7 @@ namespace AST_INTERNAL
process_and_replace_module(RTLIL::Design *design,
RTLIL::Module *old_module,
AST::AstNode *new_ast,
AST::AstNode *original_ast = nullptr);
std::unique_ptr<AST::AstNode> original_ast = nullptr);
}
YOSYS_NAMESPACE_END

View file

@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name)
log_error("unable to resolve '%s'.\n", symbol_name.c_str());
}
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
{
AST::AstNode *newNode = nullptr;
std::unique_ptr<AST::AstNode> newNode = nullptr;
union value { double f64; float f32; int32_t i32; void *ptr; };
std::vector<value> value_store(args.size() + 1);
std::vector<ffi_type *> types(args.size() + 1);
@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
if (rtype == "real") {
newNode = new AstNode(AST_REALVALUE);
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f64;
log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "shortreal") {
newNode = new AstNode(AST_REALVALUE);
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f32;
log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "chandle") {
@ -137,10 +137,10 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
std::vector<RTLIL::State> bits(64);
for (int i = 0; i < 64; i++)
bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
newNode = AstNode::mkconst_bits(bits, false);
newNode = AstNode::mkconst_bits(loc, bits, false);
log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
} else {
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
log(" return integer: %lld\n", (long long)newNode->asInt(true));
}
@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<std::unique_ptr<AST::AstNode>>&)
{
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}

View file

@ -45,7 +45,7 @@ using namespace AST_INTERNAL;
// helper function for creating RTLIL code for unary operations
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
{
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that);
@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
return;
}
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
set_src_attr(cell, that);
@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
set_src_attr(wire, that);
wire->is_signed = that->is_signed;
if (that != NULL)
if (that != nullptr)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
// helper function for creating RTLIL code for binary operations
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that);
@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
log_assert(cond.size() == 1);
std::stringstream sstr;
sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++);
sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
set_src_attr(cell, that);
@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->lookahead) {
log_assert(node->type == AST_IDENTIFIER);
if (!lookaheadids.count(node->str)) {
AstNode *wire = new AstNode(AST_WIRE);
for (auto c : node->id2ast->children)
auto wire = std::make_unique<AstNode>(node->location, AST_WIRE);
for (auto& c : node->id2ast->children)
wire->children.push_back(c->clone());
wire->fixup_hierarchy_flags();
wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++);
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false));
wire->is_logic = true;
while (wire->simplify(true, 1, -1, false)) { }
current_ast_mod->children.push_back(wire);
lookaheadids[node->str] = make_pair(node->id2ast, wire);
lookaheadids[node->str] = make_pair(node->id2ast, wire.get());
wire->genRTLIL();
current_ast_mod->children.push_back(std::move(wire));
}
}
for (auto child : node->children)
collect_lookaheadids(child);
for (auto& child : node->children)
collect_lookaheadids(child.get());
}
bool has_lookaheadids(AstNode *node)
@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0)
return true;
for (auto child : node->children)
if (has_lookaheadids(child))
for (auto& child : node->children)
if (has_lookaheadids(child.get()))
return true;
return false;
@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0)
return true;
for (auto child : node->children)
if (has_nonlookaheadids(child))
for (auto& child : node->children)
if (has_nonlookaheadids(child.get()))
return true;
return false;
@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter
{
if (node->type == AST_ASSIGN_LE)
{
if (has_lookaheadids(node->children[0]))
if (has_lookaheadids(node->children[0].get()))
{
if (has_nonlookaheadids(node->children[0]))
if (has_nonlookaheadids(node->children[0].get()))
log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n");
rewrite_lookaheadids(node->children[0], true);
rewrite_lookaheadids(node->children[0].get(), true);
node->type = AST_ASSIGN_EQ;
}
rewrite_lookaheadids(node->children[1], lhs);
rewrite_lookaheadids(node->children[1].get(), lhs);
return;
}
@ -261,21 +261,22 @@ struct AST_INTERNAL::LookaheadRewriter
lhs = false;
}
for (auto child : node->children)
rewrite_lookaheadids(child, lhs);
for (auto& child : node->children)
rewrite_lookaheadids(child.get(), lhs);
}
LookaheadRewriter(AstNode *top)
{
// top->dumpAst(NULL, "REWRITE-BEFORE> ");
// top->dumpVlog(NULL, "REWRITE-BEFORE> ");
// top->dumpAst(nullptr, "REWRITE-BEFORE> ");
// top->dumpVlog(nullptr, "REWRITE-BEFORE> ");
AstNode *block = nullptr;
auto loc = top->location;
for (auto c : top->children)
for (auto& c : top->children)
if (c->type == AST_BLOCK) {
log_assert(block == nullptr);
block = c;
block = c.get();
}
log_assert(block != nullptr);
@ -284,25 +285,25 @@ struct AST_INTERNAL::LookaheadRewriter
for (auto it : lookaheadids)
{
AstNode *ref_orig = new AstNode(AST_IDENTIFIER);
auto ref_orig = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ref_orig->str = it.second.first->str;
ref_orig->id2ast = it.second.first;
ref_orig->was_checked = true;
AstNode *ref_temp = new AstNode(AST_IDENTIFIER);
auto ref_temp = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ref_temp->str = it.second.second->str;
ref_temp->id2ast = it.second.second;
ref_temp->was_checked = true;
AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp);
auto init_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
auto final_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp));
block->children.insert(block->children.begin(), init_assign);
block->children.push_back(final_assign);
block->children.insert(block->children.begin(), std::move(init_assign));
block->children.push_back(std::move(final_assign));
}
// top->dumpAst(NULL, "REWRITE-AFTER> ");
// top->dumpVlog(NULL, "REWRITE-AFTER> ");
// top->dumpAst(nullptr, "REWRITE-AFTER> ");
// top->dumpVlog(nullptr, "REWRITE-AFTER> ");
}
};
@ -310,7 +311,7 @@ struct AST_INTERNAL::LookaheadRewriter
struct AST_INTERNAL::ProcessGenerator
{
// input and output structures
AstNode *always;
std::unique_ptr<AstNode> always;
RTLIL::SigSpec initSyncSignals;
RTLIL::Process *proc;
RTLIL::SigSpec outputSignals;
@ -341,14 +342,14 @@ struct AST_INTERNAL::ProcessGenerator
// The most recently assigned $print or $check cell \PRIORITY.
int last_effect_priority;
ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
{
// rewrite lookahead references
LookaheadRewriter la_rewriter(always);
LookaheadRewriter la_rewriter(always.get());
// generate process and simple root case
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++));
set_src_attr(proc, always);
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++));
set_src_attr(proc, always.get());
for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT)
always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
@ -358,13 +359,13 @@ struct AST_INTERNAL::ProcessGenerator
// create initial temporary signal for all output registers
RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
collect_lvalues(subst_lvalue_from, always, true, true);
collect_lvalues(subst_lvalue_from, always.get(), true, true);
subst_lvalue_to = new_temp_signal(subst_lvalue_from);
subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to);
bool found_global_syncs = false;
bool found_anyedge_syncs = false;
for (auto child : always->children)
for (auto& child : always->children)
{
if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) {
@ -388,7 +389,7 @@ struct AST_INTERNAL::ProcessGenerator
// create syncs for the process
bool found_clocked_sync = false;
for (auto child : always->children)
for (auto& child : always->children)
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk))
@ -420,9 +421,9 @@ struct AST_INTERNAL::ProcessGenerator
}
// process the AST
for (auto child : always->children)
for (auto& child : always->children)
if (child->type == AST_BLOCK)
processAst(child);
processAst(child.get());
for (auto sync: proc->syncs)
processMemWrites(sync);
@ -472,7 +473,7 @@ struct AST_INTERNAL::ProcessGenerator
for (int i = 0; i < GetSize(chunks); i++)
{
RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL)
if (chunk.wire == nullptr)
continue;
std::string wire_name;
@ -484,7 +485,7 @@ struct AST_INTERNAL::ProcessGenerator
} while (current_module->wires_.count(wire_name) > 0);
RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width);
set_src_attr(wire, always);
set_src_attr(wire, always.get());
chunk.wire = wire;
chunk.offset = 0;
@ -499,10 +500,10 @@ struct AST_INTERNAL::ProcessGenerator
switch (ast->type)
{
case AST_CASE:
for (auto child : ast->children)
for (auto& child : ast->children)
if (child != ast->children[0]) {
log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
collect_lvalues(reg, child, type_eq, type_le, false);
collect_lvalues(reg, child.get(), type_eq, type_le, false);
}
break;
@ -511,19 +512,19 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CONDZ:
case AST_ALWAYS:
case AST_INITIAL:
for (auto child : ast->children)
for (auto& child : ast->children)
if (child->type == AST_BLOCK)
collect_lvalues(reg, child, type_eq, type_le, false);
collect_lvalues(reg, child.get(), type_eq, type_le, false);
break;
case AST_BLOCK:
for (auto child : ast->children) {
for (auto& child : ast->children) {
if (child->type == AST_ASSIGN_EQ && type_eq)
reg.append(child->children[0]->genRTLIL());
if (child->type == AST_ASSIGN_LE && type_le)
reg.append(child->children[0]->genRTLIL());
if (child->type == AST_CASE || child->type == AST_BLOCK)
collect_lvalues(reg, child, type_eq, type_le, false);
collect_lvalues(reg, child.get(), type_eq, type_le, false);
}
break;
@ -583,8 +584,8 @@ struct AST_INTERNAL::ProcessGenerator
switch (ast->type)
{
case AST_BLOCK:
for (auto child : ast->children)
processAst(child);
for (auto& child : ast->children)
processAst(child.get());
break;
case AST_ASSIGN_EQ:
@ -641,9 +642,9 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue;
this_case_eq_rvalue.replace(subst_rvalue_map.stdmap());
RTLIL::CaseRule *default_case = NULL;
RTLIL::CaseRule *last_generated_case = NULL;
for (auto child : ast->children)
RTLIL::CaseRule *default_case = nullptr;
RTLIL::CaseRule *last_generated_case = nullptr;
for (auto& child : ast->children)
{
if (child == ast->children[0])
continue;
@ -657,14 +658,14 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
set_src_attr(current_case, child);
set_src_attr(current_case, child.get());
last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
for (auto node : child->children) {
for (auto& node : child->children) {
if (node->type == AST_DEFAULT)
default_case = current_case;
else if (node->type == AST_BLOCK)
processAst(node);
processAst(node.get());
else
current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap()));
}
@ -678,7 +679,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.restore();
}
if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) {
if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) {
#if 0
// this is a valid transformation, but as optimization it is premature.
// better: add a default case that assigns 'x' to everything, and let later
@ -690,7 +691,7 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case);
#endif
} else {
if (default_case == NULL) {
if (default_case == nullptr) {
default_case = new RTLIL::CaseRule;
addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
}
@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
std::stringstream sstr;
sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++);
sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++);
Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
set_src_attr(en, ast);
@ -760,14 +761,14 @@ struct AST_INTERNAL::ProcessGenerator
default_base = 16;
std::vector<VerilogFmtArg> args;
for (auto node : ast->children) {
for (auto& node : ast->children) {
int width;
bool is_signed;
node->detectSignWidth(width, is_signed, nullptr);
VerilogFmtArg arg = {};
arg.filename = node->filename;
arg.first_line = node->location.first_line;
arg.filename = *node->location.begin.filename;
arg.first_line = node->location.begin.line;
if (node->type == AST_CONSTANT && node->is_string) {
arg.type = VerilogFmtArg::STRING;
arg.str = node->bitsAsConst().decode_string();
@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator
fmt.append_literal("\n");
fmt.emit_rtlil(cell);
} else if (!ast->str.empty()) {
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
}
break;
@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator
IdString cellname;
if (ast->str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++);
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++);
else
cellname = ast->str;
check_unique_id(current_module, cellname, ast, "procedural assertion");
@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator
set_src_attr(cell, ast);
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
cell->setParam(ID::FLAVOR, flavor);
@ -866,8 +867,8 @@ struct AST_INTERNAL::ProcessGenerator
break;
default:
// ast->dumpAst(NULL, "ast> ");
// current_ast_mod->dumpAst(NULL, "mod> ");
// ast->dumpAst(nullptr, "ast> ");
// current_ast_mod->dumpAst(nullptr, "mod> ");
log_abort();
}
}
@ -876,14 +877,14 @@ struct AST_INTERNAL::ProcessGenerator
{
// Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array.
dict<std::pair<std::string, int>, int> port_map;
for (auto child : always->children)
for (auto& child : always->children)
if (child->type == AST_MEMWR)
{
std::string memid = child->str;
int portid = child->children[3]->asInt(false);
int cur_idx = GetSize(sync->mem_write_actions);
RTLIL::MemWriteAction action;
set_src_attr(&action, child);
set_src_attr(&action, child.get());
action.memid = memid;
action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap());
action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap());
@ -971,11 +972,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
bool sub_sign_hint = true;
int sub_width_hint = -1;
int this_width = 0;
AstNode *range = NULL;
AstNode *id_ast = NULL;
AstNode *range = nullptr;
AstNode *id_ast = nullptr;
bool local_found_real = false;
if (found_real == NULL)
if (found_real == nullptr)
found_real = &local_found_real;
switch (type)
@ -1019,22 +1020,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Failed to detect width for parameter %s!\n", str.c_str());
}
if (children.size() != 0)
range = children[0];
range = children[0].get();
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
if (!id_ast->range_valid) {
if (id_ast->type == AST_AUTOWIRE)
this_width = 1;
else {
// current_ast_mod->dumpAst(NULL, "mod> ");
// current_ast_mod->dumpAst(nullptr, "mod> ");
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
// id_ast->dumpAst(nullptr, "decl> ");
// dumpAst(nullptr, "ref> ");
input_error("Failed to detect width of signal access `%s'!\n", str.c_str());
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
if (children.size() != 0)
range = children[0];
range = children[0].get();
}
} else if (id_ast->type == AST_GENVAR) {
this_width = 32;
@ -1043,26 +1044,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
range = children[1].get();
} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) {
AstNode *tmp_range = make_index_range(id_ast);
auto tmp_range = make_index_range(id_ast);
this_width = tmp_range->range_left - tmp_range->range_right + 1;
delete tmp_range;
} else
input_error("Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
if (range->children.size() == 1)
this_width = 1;
else if (!range->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
} else
this_width = range->range_left - range->range_right + 1;
sign_hint = false;
@ -1106,7 +1104,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
break;
case AST_CONCAT:
for (auto child : children) {
for (auto& child : children) {
sub_width_hint = 0;
sub_sign_hint = true;
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
@ -1135,7 +1133,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_BIT_OR:
case AST_BIT_XOR:
case AST_BIT_XNOR:
for (auto child : children)
for (auto& child : children)
child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
@ -1175,7 +1173,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_MUL:
case AST_DIV:
case AST_MOD:
for (auto child : children)
for (auto& child : children)
child->detectSignWidthWorker(width_hint, sign_hint, found_real);
break;
@ -1216,12 +1214,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
width_hint = max(width_hint, sub_width_hint);
sign_hint &= sub_sign_hint;
};
visit_case_expr(children[0]);
visit_case_expr(children[0].get());
for (size_t i = 1; i < children.size(); i++) {
AstNode *child = children[i];
for (AstNode *v : child->children)
AstNode *child = children[i].get();
for (auto& v : child->children) {
if (v->type != AST_DEFAULT && v->type != AST_BLOCK)
visit_case_expr(v);
visit_case_expr(v.get());
}
}
break;
}
@ -1269,9 +1268,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (func->type != AST_FUNCTION)
input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
const AstNode *wire = nullptr;
for (const AstNode *child : func->children)
for (const auto& child : func->children)
if (child->str == func->str) {
wire = child;
wire = child.get();
break;
}
log_assert(wire && wire->type == AST_WIRE);
@ -1280,10 +1279,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!wire->children.empty())
{
log_assert(wire->children.size() == 1);
const AstNode *range = wire->children.at(0);
const AstNode *range = wire->children.at(0).get();
log_assert(range->type == AST_RANGE && range->children.size() == 2);
AstNode *left = range->children.at(0)->clone();
AstNode *right = range->children.at(1)->clone();
auto left = range->children.at(0)->clone();
auto right = range->children.at(1)->clone();
left->set_in_param_flag(true);
right->set_in_param_flag(true);
while (left->simplify(true, 1, -1, false)) { }
@ -1292,8 +1291,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
input_error("Function %s has non-constant width!",
RTLIL::unescape_id(str).c_str());
result_width = abs(int(left->asInt(true) - right->asInt(true)));
delete left;
delete right;
}
width_hint = max(width_hint, result_width);
break;
@ -1306,6 +1303,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
for (auto f : log_files)
current_scope_ast->dumpAst(f, "verilog-ast> ");
input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
}
if (*found_real)
@ -1342,8 +1340,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// be instantiated for this type of AST node.
IdString type_name;
current_filename = filename;
switch (type)
{
// simply ignore this nodes.
@ -1361,6 +1357,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENIF:
case AST_GENCASE:
case AST_PACKAGE:
case AST_IMPORT:
case AST_ENUM:
case AST_MODPORT:
case AST_MODPORTMEMBER:
@ -1508,7 +1505,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig;
}
@ -1517,11 +1514,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// shifter cell is created and the output signal of this cell is returned
case AST_IDENTIFIER:
{
RTLIL::Wire *wire = NULL;
RTLIL::Wire *wire = nullptr;
RTLIL::SigChunk chunk;
bool is_interface = false;
AST::AstNode *member_node = NULL;
AST::AstNode *member_node = nullptr;
int add_undef_bits_msb = 0;
int add_undef_bits_lsb = 0;
@ -1540,7 +1537,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (dynamic_cast<RTLIL::Binding*>(current_module)) {
/* nothing to do here */
} else if (flag_autowire)
log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());
log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str());
else
input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
}
@ -1608,14 +1605,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
if (!children[0]->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
auto fake_ast = std::make_unique<AstNode>(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children();
if (member_node)
@ -1636,10 +1633,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
delete right_at_zero_ast;
delete fake_ast;
RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
return sig;
} else {
chunk.width = children[0]->range_left - children[0]->range_right + 1;
@ -1648,10 +1642,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = source_width - (chunk.offset + chunk.width);
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
if (chunk.width == 1)
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
str.c_str());
else
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
@ -1665,10 +1659,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
}
}
@ -1942,7 +1936,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMRD:
{
std::stringstream sstr;
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
set_src_attr(cell, this);
@ -1980,7 +1974,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMINIT:
{
std::stringstream sstr;
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
SigSpec en_sig = children[2]->genRTLIL();
@ -2025,7 +2019,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString cellname;
if (str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
else
cellname = str;
check_unique_id(current_module, cellname, this, "procedural assertion");
@ -2068,7 +2062,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_left.append(left[i]);
new_right.append(right[i]);
}
log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n"
log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n"
" old assignment: %s = %s\n new assignment: %s = %s.\n",
log_signal(left), log_signal(right),
log_signal(new_left), log_signal(new_right));
@ -2092,7 +2086,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->set_bool_attribute(ID::module_not_derived);
for (auto it = children.begin(); it != children.end(); it++) {
AstNode *child = *it;
auto* child = it->get();
if (child->type == AST_CELLTYPE) {
cell->type = child->str;
if (flag_icells && cell->type.begins_with("\\$"))
@ -2101,9 +2095,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
if (child->type == AST_PARASET) {
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
const AstNode *value = child->children[0];
const auto* value = child->children[0].get();
if (value->type == AST_REALVALUE)
log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n",
log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), value->realvalue);
else if (value->type != AST_CONSTANT)
input_error("Parameter %s.%s with non-constant value!\n",
@ -2114,7 +2108,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (child->type == AST_ARGUMENT) {
RTLIL::SigSpec sig;
if (child->children.size() > 0) {
AstNode *arg = child->children[0];
auto* arg = child->children[0].get();
int local_width_hint = -1;
bool local_sign_hint = false;
// don't inadvertently attempt to detect the width of interfaces
@ -2186,30 +2180,27 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// use ProcessGenerator for always blocks
case AST_ALWAYS: {
AstNode *always = this->clone();
ProcessGenerator generator(always);
ProcessGenerator generator(this->clone());
ignoreThisSignalsInInitial.append(generator.outputSignals);
delete always;
} break;
case AST_INITIAL: {
AstNode *always = this->clone();
ProcessGenerator generator(always, ignoreThisSignalsInInitial);
delete always;
auto always = this->clone();
ProcessGenerator generator(this->clone(), ignoreThisSignalsInInitial);
} break;
case AST_TECALL: {
int sz = children.size();
if (str == "$info") {
if (sz > 0)
log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str());
log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
else
log_file_info(filename, location.first_line, "\n");
log_file_info(*location.begin.filename, location.begin.line, "\n");
} else if (str == "$warning") {
if (sz > 0)
log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str());
log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
else
log_file_warning(filename, location.first_line, "\n");
log_file_warning(*location.begin.filename, location.begin.line, "\n");
} else if (str == "$error") {
if (sz > 0)
input_error("%s.\n", children[0]->str.c_str());

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,10 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_frontend.o: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
@ -20,5 +24,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/verilog_error.o
OBJS += frontends/verilog/const2ast.o

View file

@ -42,14 +42,23 @@
YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace VERILOG_FRONTEND;
void ConstParser::log_maybe_loc_error(std::string msg) {
log_file_error(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
}
void ConstParser::log_maybe_loc_warn(std::string msg) {
log_file_warning(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
}
// divide an arbitrary length decimal number by two and return the rest
static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
int ConstParser::my_decimal_div_by_two(std::vector<uint8_t> &digits)
{
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
if (digits[i] >= 10)
log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n");
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
@ -60,7 +69,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
}
// find the number of significant bits in a binary number (not including the sign bit)
static int my_ilog2(int x)
int ConstParser::my_ilog2(int x)
{
int ret = 0;
while (x != 0 && x != -1) {
@ -71,7 +80,7 @@ static int my_ilog2(int x)
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
void ConstParser::my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
@ -102,8 +111,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
if (*it > (base-1) && *it < 0xf0)
log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
base-1, base);
log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n",
base-1, base));
for (int i = 0; i < bits_per_digit; i++) {
int bitmask = 1 << i;
if (*it == 0xf0)
@ -126,7 +135,7 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
}
if (is_unsized && (len > len_in_bits))
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len));
for (len = len - 1; len >= 0; len--)
if (data[len] == State::S1)
@ -140,21 +149,19 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
}
if (len_in_bits == 0)
log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
if (len > len_in_bits)
log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
len_in_bits, len, current_filename.c_str(), get_line_num());
log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n",
len_in_bits, len));
}
// convert the Verilog code for a constant to an AST node
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type, bool warn_z)
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
auto ret = const2ast(code, case_type);
if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n");
return ret;
}
@ -172,7 +179,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
ch = ch >> 1;
}
}
AstNode *ast = AstNode::mkconst_bits(data, false);
auto ast = AstNode::mkconst_bits(loc, data, false);
ast->str = code;
return ast;
}
@ -191,7 +198,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == State::S1)
data.push_back(State::S0);
return AstNode::mkconst_bits(data, true);
return AstNode::mkconst_bits(loc, data, true);
}
// unsized constant
@ -239,10 +246,11 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
if (is_signed && data.back() == State::S1)
data.push_back(State::S0);
}
return AstNode::mkconst_bits(data, is_signed, is_unsized);
return AstNode::mkconst_bits(loc, data, is_signed, is_unsized);
}
return NULL;
}
YOSYS_NAMESPACE_END

View file

@ -34,6 +34,7 @@
#include "preproc.h"
#include "verilog_frontend.h"
#include "frontends/verilog/verilog_parser.tab.hh"
#include "kernel/log.h"
#include <assert.h>
#include <stack>
@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream &f,
std::string filename,
const define_map_t &pre_defines,
define_map_t &global_defines_cache,
const std::list<std::string> &include_dirs)
const std::list<std::string> &include_dirs,
ParseState &parse_state,
ParseMode &parse_mode)
{
define_map_t defines;
defines.merge(pre_defines);
@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream &f,
}
if (tok == "`resetall") {
default_nettype_wire = true;
parse_state.default_nettype_wire = true;
continue;
}
if (tok == "`undefineall" && sv_mode) {
if (tok == "`undefineall" && parse_mode.sv) {
defines.clear();
global_defines_cache.clear();
continue;

View file

@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN
struct define_body_t;
struct arg_map_t;
namespace VERILOG_FRONTEND {
struct ParseState;
struct ParseMode;
};
struct define_map_t
{
define_map_t();
@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream &f,
std::string filename,
const define_map_t &pre_defines,
define_map_t &global_defines_cache,
const std::list<std::string> &include_dirs);
const std::list<std::string> &include_dirs,
VERILOG_FRONTEND::ParseState &parse_state,
VERILOG_FRONTEND::ParseMode &parse_mode);
YOSYS_NAMESPACE_END

View file

@ -0,0 +1,68 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
*/
#include "kernel/yosys_common.h"
#include "frontends/verilog/verilog_error.h"
#include "frontends/verilog/verilog_location.h"
USING_YOSYS_NAMESPACE
/**
* Legacy behavior is to only track lines. Now we have columns too, but we don't
* report them in errors.
* TODO: report columns, too
*/
[[noreturn]]
static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap)
{
char buffer[1024];
char *p = buffer;
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer);
exit(1);
}
static void vwarn_at(std::string filename, int begin_line, char const *fmt, va_list ap)
{
char buffer[1024];
char *p = buffer;
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_warning(filename, begin_line, "%s", buffer);
}
[[noreturn]]
void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
}
void VERILOG_FRONTEND::warn_at_loc(Location loc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
vwarn_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
va_end(args);
}

View file

@ -0,0 +1,19 @@
#ifndef VERILOG_ERROR_H
#define VERILOG_ERROR_H
#include "kernel/yosys_common.h"
#include "frontends/ast/ast.h"
#include "frontends/verilog/verilog_location.h"
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND
{
[[noreturn]]
void err_at_loc(Location loc, char const *fmt, ...);
void warn_at_loc(Location loc, char const *fmt, ...);
};
YOSYS_NAMESPACE_END
#endif

View file

@ -31,10 +31,14 @@
#endif
#include "verilog_frontend.h"
#include "verilog_lexer.h"
#include "verilog_error.h"
#include "verilog_location.h"
#include "preproc.h"
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include <stdarg.h>
#include <list>
YOSYS_NAMESPACE_BEGIN
using namespace VERILOG_FRONTEND;
@ -46,13 +50,13 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
static void error_on_dpi_function(AST::AstNode *node)
{
if (node->type == AST::AST_DPI_FUNCTION)
log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str());
for (auto child : node->children)
error_on_dpi_function(child);
if (node->type == AST::AST_DPI_FUNCTION)
err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str());
for (auto& child : node->children)
error_on_dpi_function(child.get());
}
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list)
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list)
{
// prime the parser's user type lookup table with the package qualified names
// of typedefed names in the packages seen so far.
@ -61,7 +65,7 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
for (const auto &node: pkg->children) {
if (node->type == AST::AST_TYPEDEF) {
std::string s = pkg->str + "::" + node->str.substr(1);
user_types[s] = node;
user_types[s] = node.get();
}
}
}
@ -250,6 +254,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_vlog1 = false;
bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false;
bool flag_debug_lexer = false;
bool flag_debug_parser = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
bool flag_nomem2reg = false;
@ -266,22 +272,24 @@ struct VerilogFrontend : public Frontend {
bool flag_noblackbox = false;
bool flag_nowb = false;
bool flag_nosynthesis = false;
bool flag_yydebug = false;
define_map_t defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
frontend_verilog_yydebug = false;
sv_mode = false;
formal_mode = false;
noassert_mode = false;
noassume_mode = false;
norestrict_mode = false;
assume_asserts_mode = false;
assert_assumes_mode = false;
lib_mode = false;
specify_mode = false;
default_nettype_wire = true;
ParseMode parse_mode = {};
ParseState parse_state = {};
parse_mode.sv = false;
parse_mode.formal = false;
parse_mode.noassert = false;
parse_mode.noassume = false;
parse_mode.norestrict = false;
parse_mode.assume_asserts = false;
parse_mode.assert_assumes = false;
parse_mode.lib = false;
parse_mode.specify = false;
parse_state.default_nettype_wire = true;
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
@ -289,11 +297,11 @@ struct VerilogFrontend : public Frontend {
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-sv") {
sv_mode = true;
parse_mode.sv = true;
continue;
}
if (arg == "-formal") {
formal_mode = true;
parse_mode.formal = true;
continue;
}
if (arg == "-nosynthesis") {
@ -301,23 +309,23 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-noassert") {
noassert_mode = true;
parse_mode.noassert = true;
continue;
}
if (arg == "-noassume") {
noassume_mode = true;
parse_mode.noassume = true;
continue;
}
if (arg == "-norestrict") {
norestrict_mode = true;
parse_mode.norestrict = true;
continue;
}
if (arg == "-assume-asserts") {
assume_asserts_mode = true;
parse_mode.assume_asserts = true;
continue;
}
if (arg == "-assert-assumes") {
assert_assumes_mode = true;
parse_mode.assert_assumes = true;
continue;
}
if (arg == "-nodisplay") {
@ -329,7 +337,8 @@ struct VerilogFrontend : public Frontend {
flag_dump_ast2 = true;
flag_dump_vlog1 = true;
flag_dump_vlog2 = true;
frontend_verilog_yydebug = true;
flag_debug_lexer = true;
flag_debug_parser = true;
continue;
}
if (arg == "-dump_ast1") {
@ -357,7 +366,9 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-yydebug") {
frontend_verilog_yydebug = true;
flag_yydebug = true;
flag_debug_lexer = true;
flag_debug_parser = true;
continue;
}
if (arg == "-nolatches") {
@ -393,7 +404,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-lib") {
lib_mode = true;
parse_mode.lib = true;
defines_map.add("BLACKBOX", "");
continue;
}
@ -402,7 +413,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-specify") {
specify_mode = true;
parse_mode.specify = true;
continue;
}
if (arg == "-noopt") {
@ -432,7 +443,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-noautowire") {
default_nettype_wire = false;
parse_state.default_nettype_wire = false;
continue;
}
if (arg == "-setattr" && argidx+1 < args.size()) {
@ -469,76 +480,82 @@ struct VerilogFrontend : public Frontend {
break;
}
if (formal_mode || !flag_nosynthesis)
defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1");
if (parse_mode.formal || !flag_nosynthesis)
defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
extra_args(f, filename, args, argidx);
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename;
AST::set_line_num = &frontend_verilog_yyset_lineno;
AST::get_line_num = &frontend_verilog_yyget_lineno;
current_ast = new AST::AstNode(AST::AST_DESIGN);
lexin = f;
AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
std::string code_after_preproc;
parse_state.lexin = f;
if (!flag_nopp) {
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs);
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode);
if (flag_ppdump)
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
lexin = new std::istringstream(code_after_preproc);
parse_state.lexin = new std::istringstream(code_after_preproc);
}
auto filename_shared = std::make_shared<std::string>(filename);
auto top_loc = Location();
top_loc.begin.filename = filename_shared;
parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
VerilogLexer lexer(&parse_state, &parse_mode, filename_shared);
frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
lexer.set_debug(flag_debug_lexer);
parser.set_debug_level(flag_debug_parser ? 1 : 0);
// make package typedefs available to parser
add_package_types(pkg_user_types, design->verilog_packages);
add_package_types(parse_state.pkg_user_types, design->verilog_packages);
UserTypeMap global_types_map;
for (auto def : design->verilog_globals) {
for (auto& def : design->verilog_globals) {
if (def->type == AST::AST_TYPEDEF) {
global_types_map[def->str] = def;
global_types_map[def->str] = def.get();
}
}
log_assert(user_type_stack.empty());
log_assert(parse_state.user_type_stack.empty());
// use previous global typedefs as bottom level of user type stack
user_type_stack.push_back(std::move(global_types_map));
parse_state.user_type_stack.push_back(std::move(global_types_map));
// add a new empty type map to allow overriding existing global definitions
user_type_stack.push_back(UserTypeMap());
parse_state.user_type_stack.push_back(UserTypeMap());
frontend_verilog_yyset_lineno(1);
frontend_verilog_yyrestart(NULL);
frontend_verilog_yyparse();
frontend_verilog_yylex_destroy();
if (flag_yydebug) {
lexer.set_debug(true);
parser.set_debug_level(1);
}
parser.parse();
// frontend_verilog_yyset_lineno(1);
for (auto &child : current_ast->children) {
for (auto &child : parse_state.current_ast->children) {
if (child->type == AST::AST_MODULE)
for (auto &attr : attributes)
if (child->attributes.count(attr) == 0)
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
}
if (flag_nodpi)
error_on_dpi_function(current_ast);
error_on_dpi_function(parse_state.current_ast);
AST::process(design, current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
AST::process(design, parse_state.current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire);
if (!flag_nopp)
delete lexin;
delete parse_state.lexin;
// only the previous and new global type maps remain
log_assert(user_type_stack.size() == 2);
user_type_stack.clear();
log_assert(parse_state.user_type_stack.size() == 2);
parse_state.user_type_stack.clear();
delete current_ast;
current_ast = NULL;
delete parse_state.current_ast;
parse_state.current_ast = NULL;
log("Successfully finished Verilog frontend.\n");
}
@ -760,18 +777,3 @@ struct VerilogFileList : public Pass {
#endif
YOSYS_NAMESPACE_END
// the yyerror function used by bison to report parser errors
void frontend_verilog_yyerror(char const *fmt, ...)
{
va_list ap;
char buffer[1024];
char *p = buffer;
va_start(ap, fmt);
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
va_end(ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
"%s", buffer);
exit(1);
}

View file

@ -31,70 +31,33 @@
#include "kernel/yosys.h"
#include "frontends/ast/ast.h"
#include <stdio.h>
#include <stdint.h>
#include <list>
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND
{
// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
extern struct AST::AstNode *current_ast;
/* Ephemeral context class */
struct ConstParser {
AST::AstSrcLocType loc;
private:
void log_maybe_loc_error(std::string msg);
void log_maybe_loc_warn(std::string msg);
// divide an arbitrary length decimal number by two and return the rest
int my_decimal_div_by_two(std::vector<uint8_t> &digits);
// find the number of significant bits in a binary number (not including the sign bit)
int my_ilog2(int x);
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized);
public:
// convert the Verilog code for a constant to an AST node
std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false);
// this function converts a Verilog constant to an AST_CONSTANT node
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
// names of locally typedef'ed types in a stack
typedef std::map<std::string, AST::AstNode*> UserTypeMap;
extern std::vector<UserTypeMap> user_type_stack;
// names of package typedef'ed types
extern dict<std::string, AST::AstNode*> pkg_user_types;
// state of `default_nettype
extern bool default_nettype_wire;
// running in SystemVerilog mode
extern bool sv_mode;
// running in -formal mode
extern bool formal_mode;
// running in -noassert mode
extern bool noassert_mode;
// running in -noassume mode
extern bool noassume_mode;
// running in -norestrict mode
extern bool norestrict_mode;
// running in -assume-asserts mode
extern bool assume_asserts_mode;
// running in -assert-assumes mode
extern bool assert_assumes_mode;
// running in -lib mode
extern bool lib_mode;
// running in -specify mode
extern bool specify_mode;
// lexer input stream
extern std::istream *lexin;
}
};
};
YOSYS_NAMESPACE_END
// the usual bison/flex stuff
extern int frontend_verilog_yydebug;
void frontend_verilog_yyerror(char const *fmt, ...);
void frontend_verilog_yyrestart(FILE *f);
int frontend_verilog_yyparse(void);
int frontend_verilog_yylex_destroy(void);
int frontend_verilog_yyget_lineno(void);
void frontend_verilog_yyset_lineno (int);
#endif

View file

@ -0,0 +1,48 @@
#ifndef VERILOG_LEXER_H
#define VERILOG_LEXER_H
#include "kernel/yosys.h"
#include "frontends/ast/ast.h"
#include "frontends/verilog/verilog_parser.tab.hh"
#include <string>
#include <memory>
#if ! defined(yyFlexLexerOnce)
#define yyFlexLexer frontend_verilog_yyFlexLexer
#include <FlexLexer.h>
#endif
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
using parser = frontend_verilog_yy::parser;
class VerilogLexer : public frontend_verilog_yyFlexLexer {
ParseState* extra;
ParseMode* mode;
parser::location_type out_loc;
public:
VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr<string> filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {
out_loc.begin.filename = filename;
}
~VerilogLexer() override {}
// autogenerated body due to YY_DECL
parser::symbol_type nextToken();
// get rid of override virtual function warning
using FlexLexer::yylex;
parser::symbol_type terminate() {
return parser::make_FRONTEND_VERILOG_YYEOF(out_loc);
}
private:
std::shared_ptr<std::string> current_filename;
std::vector<std::shared_ptr<std::string>> fn_stack;
std::vector<int> ln_stack;
int LexerInput(char* buf, int max_size) override {
return readsome(*extra->lexin, buf, max_size);
}
};
};
YOSYS_NAMESPACE_END
#endif

View file

@ -32,6 +32,13 @@
*
*/
%option c++
%option yyclass="VerilogLexer"
%option noyywrap
%option nounput
%option yylineno
%option prefix="frontend_verilog_yy"
%{
#ifdef __clang__
@ -41,78 +48,109 @@
#pragma clang diagnostic ignored "-Wmisleading-indentation"
#endif
#include "kernel/log.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/verilog/verilog_lexer.h"
#include "frontends/ast/ast.h"
#include "verilog_parser.tab.hh"
#include "frontends/verilog/verilog_location.h"
#include "kernel/log.h"
#include <vector>
#include <memory>
USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
using parser = frontend_verilog_yy::parser;
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
std::vector<std::string> fn_stack;
std::vector<int> ln_stack;
YYLTYPE real_location;
YYLTYPE old_location;
}
#undef YY_DECL
#define YY_DECL parser::symbol_type VerilogLexer::nextToken()
#undef yyterminate
#define yyterminate() return terminate()
YOSYS_NAMESPACE_END
#define SV_KEYWORD(_tok) \
if (sv_mode) return _tok; \
if (mode->sv) return _tok; \
log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
"recognized unless read_verilog is called with -sv!\n", yytext, \
AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
yylval->string = new std::string(std::string("\\") + yytext); \
return TOK_ID;
"recognized unless read_verilog is called with -sv!\n", YYText(), \
current_filename->c_str(), yylineno); \
string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
return parser::make_TOK_ID(std::move(val), out_loc);
#define NON_KEYWORD() \
yylval->string = new std::string(std::string("\\") + yytext); \
return TOK_ID;
string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
return parser::make_TOK_ID(std::move(val), out_loc);
#define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
#define YY_USER_ACTION \
old_location = real_location; \
real_location.first_line = real_location.last_line; \
real_location.first_column = real_location.last_column; \
for(int i = 0; yytext[i] != '\0'; ++i){ \
if(yytext[i] == '\n') { \
real_location.last_line++; \
real_location.last_column = 1; \
} \
else { \
real_location.last_column++; \
} \
} \
(*yylloc) = real_location;
out_loc.step(); \
for(int i = 0; YYText()[i] != '\0'; ++i){ \
if(YYText()[i] == '\n') { \
out_loc.lines(); \
} \
else { \
out_loc.columns(); \
} \
} \
out_loc.begin.filename = current_filename; \
out_loc.end.filename = current_filename;
#define YY_BREAK \
(*yylloc) = old_location; \
break;
#undef YY_BUF_SIZE
#define YY_BUF_SIZE 65536
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
static bool isUserType(std::string &s)
static bool isUserType(ParseState* extra, std::string &s)
{
// check current scope then outer scopes for a name
for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) {
for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) {
if (it->count(s) > 0) {
return true;
return true;
}
}
return false;
}
static bool is_hex_dig(char c, int *val)
parser::symbol_type char_tok(char c, parser::location_type loc) {
switch (c) {
case '!': return parser::make_TOK_EXCL(loc);
case '#': return parser::make_TOK_HASH(loc);
case '%': return parser::make_TOK_PERC(loc);
case '&': return parser::make_TOK_AMP(loc);
case '(': return parser::make_TOK_LPAREN(loc);
case ')': return parser::make_TOK_RPAREN(loc);
case '*': return parser::make_TOK_ASTER(loc);
case '+': return parser::make_TOK_PLUS(loc);
case ',': return parser::make_TOK_COMMA(loc);
case '-': return parser::make_TOK_MINUS(loc);
case '.': return parser::make_TOK_DOT(loc);
case '/': return parser::make_TOK_SLASH(loc);
case ':': return parser::make_TOK_COL(loc);
case ';': return parser::make_TOK_SEMICOL(loc);
case '<': return parser::make_TOK_LT(loc);
case '=': return parser::make_TOK_EQ(loc);
case '>': return parser::make_TOK_GT(loc);
case '?': return parser::make_TOK_QUE(loc);
case '@': return parser::make_TOK_AT(loc);
case '[': return parser::make_TOK_LBRA(loc);
case ']': return parser::make_TOK_RBRA(loc);
case '^': return parser::make_TOK_CARET(loc);
case '_': return parser::make_TOK_UNDER(loc);
case '{': return parser::make_TOK_LCURL(loc);
case '|': return parser::make_TOK_PIPE(loc);
case '}': return parser::make_TOK_RCURL(loc);
case '~': return parser::make_TOK_TILDE(loc);
case 'n': return parser::make_TOK_n(loc);
case 'p': return parser::make_TOK_p(loc);
case 'x': return parser::make_TOK_x(loc);
case 'z': return parser::make_TOK_z(loc);
case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc);
default:
return parser::make_ch_t(c, loc);
}
}
static bool is_hex_dig(char c, int *val, parser::location_type loc)
{
if ('0' <= c && c <= '9') {
*val = c - '0';
@ -124,7 +162,7 @@ static bool is_hex_dig(char c, int *val)
*val = c - 'A' + 0xA;
return true;
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c);
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c);
*val = 0; // not semantically valid in hex escape...
return true; // ...but still processed as part of hex token
}
@ -132,13 +170,13 @@ static bool is_hex_dig(char c, int *val)
return false;
}
static bool is_oct_dig(char c, int *val)
static bool is_oct_dig(char c, int *val, parser::location_type loc)
{
if ('0' <= c && c <= '7') {
*val = c - '0';
return true;
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c);
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c);
*val = 0; // not semantically valid in octal escape...
return true; // ...but still processed as part of octal token
}
@ -146,7 +184,7 @@ static bool is_oct_dig(char c, int *val)
return false;
}
static std::string *process_str(char *str, int len, bool triple)
static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc)
{
char *in, *out; // Overwrite input buffer: flex manual states "Actions
// are free to modify 'yytext' except for lengthening it".
@ -158,7 +196,7 @@ static std::string *process_str(char *str, int len, bool triple)
if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r'))
in++;
if (!triple)
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n");
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n");
*out++ = '\n';
break;
case '\\':
@ -186,16 +224,16 @@ static std::string *process_str(char *str, int len, bool triple)
break;
case 'x':
int val;
if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
*out = val;
in++;
if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
*out = *out * 0x10 + val;
in++;
}
out++;
} else
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n");
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n");
break;
case '\\':
*out++ = '\\';
@ -213,12 +251,12 @@ static std::string *process_str(char *str, int len, bool triple)
int val;
*out = *in - '0';
if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
*out = *out * 010 + val;
in++;
if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
if (*out >= 040)
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n");
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n");
*out = *out * 010 + val;
in++;
}
@ -232,18 +270,11 @@ static std::string *process_str(char *str, int len, bool triple)
*out++ = *in;
}
return new std::string(str, out - str);
return parser::make_TOK_STRING(std::make_unique<std::string>(str, out - str), loc);
}
%}
%option yylineno
%option noyywrap
%option nounput
%option bison-locations
%option bison-bridge
%option prefix="frontend_verilog_yy"
%x COMMENT
%x SYNOPSYS_TRANSLATE_OFF
%x SYNOPSYS_FLAGS
@ -256,47 +287,46 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+
TIME_SCALE_SUFFIX [munpf]?s
%%
// Initialise comment_caller to something to avoid a "maybe undefined"
// warning from GCC.
int comment_caller = INITIAL;
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
if (!current_filename.empty() && current_filename.front() == '"')
current_filename = current_filename.substr(1);
if (!current_filename.empty() && current_filename.back() == '"')
current_filename = current_filename.substr(0, current_filename.size()-1);
frontend_verilog_yyset_lineno(0);
yylloc->first_line = yylloc->last_line = 0;
real_location.first_line = real_location.last_line = 0;
ln_stack.push_back(yylineno);
std::string filename = YYText()+11;
if (!filename.empty() && filename.front() == '"')
filename = filename.substr(1);
if (!filename.empty() && filename.back() == '"')
filename = filename.substr(0, filename.size()-1);
current_filename = std::make_shared<std::string>(filename);
yylineno = (0);
out_loc.begin.line = out_loc.end.line = 0;
}
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
current_filename = fn_stack.back();
fn_stack.pop_back();
frontend_verilog_yyset_lineno(ln_stack.back());
yylloc->first_line = yylloc->last_line = ln_stack.back();
real_location.first_line = real_location.last_line = ln_stack.back();
yylineno = (ln_stack.back());
out_loc.begin.line = out_loc.end.line = ln_stack.back();
ln_stack.pop_back();
}
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
char *p = yytext + 5;
const char *p = YYText() + 5;
while (*p == ' ' || *p == '\t') p++;
frontend_verilog_yyset_lineno(atoi(p));
yylloc->first_line = yylloc->last_line = atoi(p);
real_location.first_line = real_location.last_line = atoi(p);
yylineno = (atoi(p));
out_loc.begin.line = out_loc.end.line = atoi(p);
while (*p && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++;
char *q = *p ? p + 1 : p;
const char *q = *p ? p + 1 : p;
while (*q && *q != '"') q++;
current_filename = std::string(p).substr(1, q-p-1);
current_filename = std::make_shared<std::string>(std::string(p).substr(1, q-p-1));
}
"`file_notfound "[^\n]* {
log_error("Can't open include file `%s'!\n", yytext + 15);
log_error("Can't open include file `%s'!\n", YYText() + 15);
}
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
@ -305,222 +335,223 @@ TIME_SCALE_SUFFIX [munpf]?s
"`endcelldefine"[^\n]* /* ignore `endcelldefine */
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext;
const char *p = YYText();
while (*p != 0 && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++;
if (!strcmp(p, "none"))
VERILOG_FRONTEND::default_nettype_wire = false;
extra->default_nettype_wire = false;
else if (!strcmp(p, "wire"))
VERILOG_FRONTEND::default_nettype_wire = true;
extra->default_nettype_wire = true;
else
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
err_at_loc(out_loc, "Unsupported default nettype: %s", p);
}
"`protect"[^\n]* /* ignore `protect*/
"`endprotect"[^\n]* /* ignore `endprotect*/
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText());
}
"module" { return TOK_MODULE; }
"endmodule" { return TOK_ENDMODULE; }
"function" { return TOK_FUNCTION; }
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
"interface" { SV_KEYWORD(TOK_INTERFACE); }
"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
"modport" { SV_KEYWORD(TOK_MODPORT); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
"assign" { return TOK_ASSIGN; }
"always" { return TOK_ALWAYS; }
"initial" { return TOK_INITIAL; }
"begin" { return TOK_BEGIN; }
"end" { return TOK_END; }
"if" { return TOK_IF; }
"else" { return TOK_ELSE; }
"for" { return TOK_FOR; }
"posedge" { return TOK_POSEDGE; }
"negedge" { return TOK_NEGEDGE; }
"or" { return TOK_OR; }
"case" { return TOK_CASE; }
"casex" { return TOK_CASEX; }
"casez" { return TOK_CASEZ; }
"endcase" { return TOK_ENDCASE; }
"default" { return TOK_DEFAULT; }
"generate" { return TOK_GENERATE; }
"endgenerate" { return TOK_ENDGENERATE; }
"while" { return TOK_WHILE; }
"repeat" { return TOK_REPEAT; }
"automatic" { return TOK_AUTOMATIC; }
"module" { return parser::make_TOK_MODULE(out_loc); }
"endmodule" { return parser::make_TOK_ENDMODULE(out_loc); }
"function" { return parser::make_TOK_FUNCTION(out_loc); }
"endfunction" { return parser::make_TOK_ENDFUNCTION(out_loc); }
"task" { return parser::make_TOK_TASK(out_loc); }
"endtask" { return parser::make_TOK_ENDTASK(out_loc); }
"specify" { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); }
"endspecify" { return parser::make_TOK_ENDSPECIFY(out_loc); }
"specparam" { return parser::make_TOK_SPECPARAM(out_loc); }
"package" { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); }
"endpackage" { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); }
"import" { SV_KEYWORD(parser::make_TOK_IMPORT(out_loc)); }
"interface" { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); }
"endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); }
"modport" { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); }
"parameter" { return parser::make_TOK_PARAMETER(out_loc); }
"localparam" { return parser::make_TOK_LOCALPARAM(out_loc); }
"defparam" { return parser::make_TOK_DEFPARAM(out_loc); }
"assign" { return parser::make_TOK_ASSIGN(out_loc); }
"always" { return parser::make_TOK_ALWAYS(out_loc); }
"initial" { return parser::make_TOK_INITIAL(out_loc); }
"begin" { return parser::make_TOK_BEGIN(out_loc); }
"end" { return parser::make_TOK_END(out_loc); }
"if" { return parser::make_TOK_IF(out_loc); }
"else" { return parser::make_TOK_ELSE(out_loc); }
"for" { return parser::make_TOK_FOR(out_loc); }
"posedge" { return parser::make_TOK_POSEDGE(out_loc); }
"negedge" { return parser::make_TOK_NEGEDGE(out_loc); }
"or" { return parser::make_TOK_OR(out_loc); }
"case" { return parser::make_TOK_CASE(out_loc); }
"casex" { return parser::make_TOK_CASEX(out_loc); }
"casez" { return parser::make_TOK_CASEZ(out_loc); }
"endcase" { return parser::make_TOK_ENDCASE(out_loc); }
"default" { return parser::make_TOK_DEFAULT(out_loc); }
"generate" { return parser::make_TOK_GENERATE(out_loc); }
"endgenerate" { return parser::make_TOK_ENDGENERATE(out_loc); }
"while" { return parser::make_TOK_WHILE(out_loc); }
"repeat" { return parser::make_TOK_REPEAT(out_loc); }
"automatic" { return parser::make_TOK_AUTOMATIC(out_loc); }
"unique" { SV_KEYWORD(TOK_UNIQUE); }
"unique0" { SV_KEYWORD(TOK_UNIQUE0); }
"priority" { SV_KEYWORD(TOK_PRIORITY); }
"unique" { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); }
"unique0" { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); }
"priority" { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); }
"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); }
"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); }
"always_comb" { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); }
"always_ff" { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); }
"always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); }
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
global state.. its a mess) */
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
if (!strcmp(yytext, "default"))
return TOK_DEFAULT;
yylval->string = new std::string(std::string("\\") + yytext);
return TOK_SVA_LABEL;
if (!strcmp(YYText(), "default"))
return parser::make_TOK_DEFAULT(out_loc);
string_t val = std::make_unique<std::string>(std::string("\\") + YYText());
return parser::make_TOK_SVA_LABEL(std::move(val), out_loc);
}
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_LOGIC); }
"int" { SV_KEYWORD(TOK_INT); }
"byte" { SV_KEYWORD(TOK_BYTE); }
"shortint" { SV_KEYWORD(TOK_SHORTINT); }
"longint" { SV_KEYWORD(TOK_LONGINT); }
"void" { SV_KEYWORD(TOK_VOID); }
"assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); }
"assume" { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); }
"cover" { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); }
"restrict" { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); }
"property" { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); }
"rand" { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); }
"const" { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); }
"checker" { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); }
"endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); }
"bind" { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); }
"final" { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); }
"logic" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
"var" { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); }
"bit" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
"int" { SV_KEYWORD(parser::make_TOK_INT(out_loc)); }
"byte" { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); }
"shortint" { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); }
"longint" { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); }
"void" { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
"eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
"s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"wire" { return TOK_WIRE; }
"tri" { return TOK_WIRE; }
"wor" { return TOK_WOR; }
"trior" { return TOK_WOR; }
"wand" { return TOK_WAND; }
"triand" { return TOK_WAND; }
"reg" { return TOK_REG; }
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
"unsigned" { SV_KEYWORD(TOK_UNSIGNED); }
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
"input" { return parser::make_TOK_INPUT(out_loc); }
"output" { return parser::make_TOK_OUTPUT(out_loc); }
"inout" { return parser::make_TOK_INOUT(out_loc); }
"wire" { return parser::make_TOK_WIRE(out_loc); }
"tri" { return parser::make_TOK_WIRE(out_loc); }
"wor" { return parser::make_TOK_WOR(out_loc); }
"trior" { return parser::make_TOK_WOR(out_loc); }
"wand" { return parser::make_TOK_WAND(out_loc); }
"triand" { return parser::make_TOK_WAND(out_loc); }
"reg" { return parser::make_TOK_REG(out_loc); }
"integer" { return parser::make_TOK_INTEGER(out_loc); }
"signed" { return parser::make_TOK_SIGNED(out_loc); }
"unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); }
"genvar" { return parser::make_TOK_GENVAR(out_loc); }
"real" { return parser::make_TOK_REAL(out_loc); }
"enum" { SV_KEYWORD(TOK_ENUM); }
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
"struct" { SV_KEYWORD(TOK_STRUCT); }
"union" { SV_KEYWORD(TOK_UNION); }
"packed" { SV_KEYWORD(TOK_PACKED); }
"enum" { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); }
"typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); }
"struct" { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); }
"union" { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); }
"packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); }
{UNSIGNED_NUMBER} {
yylval->string = new std::string(yytext);
return TOK_CONSTVAL;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_CONSTVAL(std::move(val), out_loc);
}
\'[01zxZX] {
yylval->string = new std::string(yytext);
return TOK_UNBASED_UNSIZED_CONSTVAL;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc);
}
\'[sS]?[bodhBODH] {
BEGIN(BASED_CONST);
yylval->string = new std::string(yytext);
return TOK_BASE;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_BASE(std::move(val), out_loc);
}
<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* {
BEGIN(0);
yylval->string = new std::string(yytext);
return TOK_BASED_CONSTVAL;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc);
}
{FIXED_POINT_NUMBER_DEC} {
yylval->string = new std::string(yytext);
return TOK_REALVAL;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_REALVAL(std::move(val), out_loc);
}
{FIXED_POINT_NUMBER_NO_DEC} {
yylval->string = new std::string(yytext);
return TOK_REALVAL;
string_t val = std::make_unique<std::string>(YYText());
return parser::make_TOK_REALVAL(std::move(val), out_loc);
}
\"([^\\"]|\\.|\\\n)*\" { yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; }
\"([^\\"]|\\.|\\\n)*\" { return process_str(yytext + 1, yyleng - 2, false, out_loc); }
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; }
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { return process_str(yytext + 3, yyleng - 6, true, out_loc); }
and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
yylval->string = new std::string(yytext);
return TOK_PRIMITIVE;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_PRIMITIVE(std::move(val), out_loc);
}
supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; }
supply0 { return parser::make_TOK_SUPPLY0(out_loc); }
supply1 { return parser::make_TOK_SUPPLY1(out_loc); }
"$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
yylval->string = new std::string(yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT;
yylval->string = new std::string(yytext);
return TOK_ID;
if (!mode->specify) REJECT;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
"$"(info|warning|error|fatal) {
yylval->string = new std::string(yytext);
return TOK_MSG_TASKS;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_MSG_TASKS(std::move(val), out_loc);
}
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
"$signed" { return parser::make_TOK_TO_SIGNED(out_loc); }
"$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); }
[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* {
// package qualifier
auto s = std::string("\\") + yytext;
if (pkg_user_types.count(s) > 0) {
auto s = std::string("\\") + YYText();
if (extra->pkg_user_types.count(s) > 0) {
// package qualified typedefed name
yylval->string = new std::string(s);
return TOK_PKG_USER_TYPE;
auto val = std::make_unique<std::string>(s);
return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc);
}
else {
// backup before :: just return first part
size_t len = strchr(yytext, ':') - yytext;
size_t len = strchr(YYText(), ':') - YYText();
yyless(len);
yylval->string = new std::string(std::string("\\") + yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
}
[a-zA-Z_$][a-zA-Z0-9_$]* {
auto s = std::string("\\") + yytext;
if (isUserType(s)) {
auto s = std::string("\\") + YYText();
if (isUserType(extra, s)) {
// previously typedefed name
yylval->string = new std::string(s);
return TOK_USER_TYPE;
auto val = std::make_unique<std::string>(s);
return parser::make_TOK_USER_TYPE(std::move(val), out_loc);
}
else {
yylval->string = new std::string(std::string("\\") + yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
}
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
yylval->string = new std::string(std::string("\\") + yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
@ -556,7 +587,7 @@ supply1 { return TOK_SUPPLY1; }
);
printed_warning = true;
}
return TOK_SYNOPSYS_FULL_CASE;
return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc);
}
<SYNOPSYS_FLAGS>parallel_case {
static bool printed_warning = false;
@ -570,119 +601,115 @@ supply1 { return TOK_SUPPLY1; }
);
printed_warning = true;
}
return TOK_SYNOPSYS_PARALLEL_CASE;
return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc);
}
<SYNOPSYS_FLAGS>. /* ignore everything else */
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
BEGIN(IMPORT_DPI);
return TOK_DPI_FUNCTION;
return parser::make_TOK_DPI_FUNCTION(out_loc);
}
<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
yylval->string = new std::string(std::string("\\") + yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
<IMPORT_DPI>";" {
BEGIN(0);
return *yytext;
return char_tok(*YYText(), out_loc);
}
<IMPORT_DPI>. {
return *yytext;
return char_tok(*YYText(), out_loc);
}
"\\"[^ \t\r\n]+ {
yylval->string = new std::string(yytext);
return TOK_ID;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_ID(std::move(val), out_loc);
}
"(*" { return ATTR_BEGIN; }
"*)" { return ATTR_END; }
"(*" { return parser::make_ATTR_BEGIN(out_loc); }
"*)" { return parser::make_ATTR_END(out_loc); }
"{*" { return DEFATTR_BEGIN; }
"*}" { return DEFATTR_END; }
"{*" { return parser::make_DEFATTR_BEGIN(out_loc); }
"*}" { return parser::make_DEFATTR_END(out_loc); }
"**" { return OP_POW; }
"||" { return OP_LOR; }
"&&" { return OP_LAND; }
"==" { return OP_EQ; }
"!=" { return OP_NE; }
"<=" { return OP_LE; }
">=" { return OP_GE; }
"**" { return parser::make_OP_POW(out_loc); }
"||" { return parser::make_OP_LOR(out_loc); }
"&&" { return parser::make_OP_LAND(out_loc); }
"==" { return parser::make_OP_EQ(out_loc); }
"!=" { return parser::make_OP_NE(out_loc); }
"<=" { return parser::make_OP_LE(out_loc); }
">=" { return parser::make_OP_GE(out_loc); }
"===" { return OP_EQX; }
"!==" { return OP_NEX; }
"===" { return parser::make_OP_EQX(out_loc); }
"!==" { return parser::make_OP_NEX(out_loc); }
"~&" { return OP_NAND; }
"~|" { return OP_NOR; }
"~^" { return OP_XNOR; }
"^~" { return OP_XNOR; }
"~&" { return parser::make_OP_NAND(out_loc); }
"~|" { return parser::make_OP_NOR(out_loc); }
"~^" { return parser::make_OP_XNOR(out_loc); }
"^~" { return parser::make_OP_XNOR(out_loc); }
"<<" { return OP_SHL; }
">>" { return OP_SHR; }
"<<<" { return OP_SSHL; }
">>>" { return OP_SSHR; }
"<<" { return parser::make_OP_SHL(out_loc); }
">>" { return parser::make_OP_SHR(out_loc); }
"<<<" { return parser::make_OP_SSHL(out_loc); }
">>>" { return parser::make_OP_SSHR(out_loc); }
"'" { return OP_CAST; }
"'" { return parser::make_OP_CAST(out_loc); }
"::" { return TOK_PACKAGESEP; }
"++" { return TOK_INCREMENT; }
"--" { return TOK_DECREMENT; }
"::" { return parser::make_TOK_PACKAGESEP(out_loc); }
"++" { return parser::make_TOK_INCREMENT(out_loc); }
"--" { return parser::make_TOK_DECREMENT(out_loc); }
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
"+:" { return parser::make_TOK_POS_INDEXED(out_loc); }
"-:" { return parser::make_TOK_NEG_INDEXED(out_loc); }
".*" { return TOK_WILDCARD_CONNECT; }
".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); }
"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); }
"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); }
"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); }
"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); }
"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); }
"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); }
"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); }
"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); }
"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); }
">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); }
"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); }
">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); }
"|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); }
"&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); }
"+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); }
"-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); }
"^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); }
"/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); }
"%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); }
"*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); }
"<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); }
">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); }
"<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); }
">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); }
[-+]?[=*]> {
if (!specify_mode) REJECT;
yylval->string = new std::string(yytext);
return TOK_SPECIFY_OPER;
if (!mode->specify) REJECT;
auto val = std::make_unique<std::string>(YYText());
return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc);
}
"&&&" {
if (!specify_mode) return TOK_IGNORED_SPECIFY_AND;
return TOK_SPECIFY_AND;
if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc);
return parser::make_TOK_SPECIFY_AND(out_loc);
}
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
<COMMENT>"*/" { BEGIN(comment_caller); }
<INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */
<INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */
<INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */
<INITIAL>. { return *yytext; }
<*>. { BEGIN(0); return *yytext; }
<INITIAL>. { return char_tok(*YYText(), out_loc); }
<*>. { BEGIN(0); return char_tok(*YYText(), out_loc); }
%%
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *frontend_verilog_avoid_input_warnings() {
return (void*)&yyinput;
}

View file

@ -0,0 +1,97 @@
#ifndef VERILOG_LOCATION_H
#define VERILOG_LOCATION_H
#include <memory>
#include <string>
#include <stack>
#include <string>
#include <sstream>
/**
* Provide frontend-wide location tracking like what bison generates
* but using shared_ptr for filename
*/
struct Position {
std::shared_ptr<std::string> filename;
int line;
int column;
Position(std::shared_ptr<std::string> filename, int line = 1, int column = 1)
: filename(filename), line(line), column(column) {}
Position() = default;
Position(const Position& other) = default;
Position& operator=(const Position& other) = default;
void advance() { ++column; }
void columns(int count = 1) {
column += count;
}
void lines(int count = 1) {
line += count;
column = 1;
}
std::string to_string() const {
std::ostringstream oss;
if (filename && !filename->empty()) {
oss << *filename << ":";
}
oss << line << ":" << column;
return oss.str();
}
};
struct Location {
Position begin;
Position end;
Location() = default;
Location(const Position& b, const Position& e)
: begin(b), end(e) {}
Location(const Location& other) = default;
Location& operator=(const Location& other) = default;
void step() { begin = end; }
void columns(int count = 1) {
end.columns(count);
}
void lines(int count = 1) {
end.lines(count);
}
std::string to_string() const {
std::ostringstream oss;
bool same_file = (!begin.filename && !end.filename) ||
(begin.filename && end.filename &&
*begin.filename == *end.filename);
if (same_file) {
if (begin.filename && !begin.filename->empty())
oss << *begin.filename << ":";
if (begin.line == end.line) {
if (begin.column == end.column) {
oss << begin.line << ":" << begin.column;
} else {
oss << begin.line << ":" << begin.column
<< "-" << end.column;
}
} else {
oss << begin.line << ":" << begin.column
<< "-" << end.line << ":" << end.column;
}
} else {
oss << begin.to_string() << "-" << end.to_string();
}
return oss.str();
}
};
static inline std::ostream& operator<<(std::ostream& os, const Location& loc) {
return os << loc.to_string();
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,18 @@
YOSYS_NAMESPACE_BEGIN
/**
* This file implements BitPatternPool for efficiently storing and querying
* sets of fixed-width 2-valued logic constants compressed as "bit patterns".
* A bit pattern can have don't cares on one or more bit positions (State::Sa).
*
* In terms of logic synthesis:
* A BitPatternPool is a sum of products (SOP).
* BitPatternPool::bits_t is a cube.
*
* BitPatternPool does not permit adding new patterns, only removing.
* Its intended use case is in analysing cases in case/match constructs in HDL.
*/
struct BitPatternPool
{
int width;
@ -67,6 +79,9 @@ struct BitPatternPool
}
}
/**
* Constructs a pool of all possible patterns (all don't-care bits)
*/
BitPatternPool(int width)
{
this->width = width;
@ -78,6 +93,10 @@ struct BitPatternPool
}
}
/**
* Convert a constant SigSpec to a pattern. Normalize Yosys many-valued
* to three-valued logic.
*/
bits_t sig2bits(RTLIL::SigSpec sig)
{
bits_t bits;
@ -88,6 +107,9 @@ struct BitPatternPool
return bits;
}
/**
* Two cubes match if their intersection is non-empty.
*/
bool match(bits_t a, bits_t b)
{
log_assert(int(a.bitdata.size()) == width);
@ -98,6 +120,15 @@ struct BitPatternPool
return true;
}
/**
* Does cube sig overlap any cube in the pool?
* For example:
* pool({aaa}).has_any(01a) == true
* pool({01a}).has_any(01a) == true
* pool({011}).has_any(01a) == true
* pool({01a}).has_any(011) == true
* pool({111}).has_any(01a) == false
*/
bool has_any(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
@ -107,6 +138,15 @@ struct BitPatternPool
return false;
}
/**
* Is cube sig covered by a cube in the pool?
* For example:
* pool({aaa}).has_all(01a) == true
* pool({01a}).has_any(01a) == true
* pool({01a}).has_any(011) == true
* pool({011}).has_all(01a) == false
* pool({111}).has_all(01a) == false
*/
bool has_all(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
@ -121,6 +161,12 @@ struct BitPatternPool
return false;
}
/**
* Remove cube sig from the pool, splitting the remaining cubes. True if success.
* For example:
* Taking 011 out of pool({01a}) -> pool({010}), returns true.
* Taking 011 out of pool({010}) does nothing, returns false.
*/
bool take(RTLIL::SigSpec sig)
{
bool status = false;
@ -143,6 +189,9 @@ struct BitPatternPool
return status;
}
/**
* Remove all patterns. Returns false if already empty.
*/
bool take_all()
{
if (database.empty())

View file

@ -334,6 +334,7 @@ struct CellTypes
return v;
}
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
{
if (type == ID($sshr) && !signed1)
@ -416,6 +417,7 @@ struct CellTypes
log_abort();
}
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
{
if (cell->type == ID($slice)) {
@ -503,10 +505,13 @@ struct CellTypes
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
}
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
{
if (cell->type.in(ID($mux), ID($_MUX_)))
return const_mux(arg1, arg2, arg3);
if (cell->type == ID($_NMUX_))
return eval_not(const_mux(arg1, arg2, arg3));
if (cell->type == ID($bwmux))
return const_bwmux(arg1, arg2, arg3);
if (cell->type == ID($pmux))
@ -520,6 +525,7 @@ struct CellTypes
return eval(cell, arg1, arg2, errp);
}
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
{
if (cell->type == ID($_AOI4_))

View file

@ -349,7 +349,11 @@ struct ConstEval
return false;
bool eval_err = false;
RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
RTLIL::Const eval_ret;
if (sig_s.size() > 0 && eval(sig_s, undef, cell)) {
eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_s.as_const(), &eval_err);
} else
eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
if (eval_err)
return false;

View file

@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN
struct FfInitVals
{
const SigMap *sigmap;
const SigMapView *sigmap;
dict<SigBit, std::pair<State,SigBit>> initbits;
void set(const SigMap *sigmap_, RTLIL::Module *module)
void set(const SigMapView *sigmap_, RTLIL::Module *module)
{
sigmap = sigmap_;
initbits.clear();
@ -126,7 +126,7 @@ struct FfInitVals
initbits.clear();
}
FfInitVals (const SigMap *sigmap, RTLIL::Module *module)
FfInitVals (const SigMapView *sigmap, RTLIL::Module *module)
{
set(sigmap, module);
}

View file

@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN
struct FfMergeHelper
{
const SigMap *sigmap;
const SigMapView *sigmap;
RTLIL::Module *module;
FfInitVals *initvals;

View file

@ -12,6 +12,7 @@
#ifndef HASHLIB_H
#define HASHLIB_H
#include <array>
#include <stdexcept>
#include <algorithm>
#include <optional>
@ -100,7 +101,7 @@ private:
uint32_t hash = ((a << 5) + a) ^ b;
return hash;
}
public:
public:
void hash32(uint32_t i) {
state = djb2_xor(i, state);
state = mkhash_xorshift(fudge ^ state);
@ -127,6 +128,7 @@ private:
*this = hash_ops<T>::hash_into(t, *this);
}
[[deprecated]]
void commutative_eat(hash_t t) {
state ^= t;
}
@ -177,58 +179,58 @@ struct hash_ops {
};
template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
static inline bool cmp(const std::pair<P, Q> &a, const std::pair<P, Q> &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const std::pair<P, Q> &a, Hasher h) {
h = hash_ops<P>::hash_into(a.first, h);
h = hash_ops<Q>::hash_into(a.second, h);
return h;
}
HASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND
HASH_TOP_LOOP_FST (const std::pair<P, Q> &a) HASH_TOP_LOOP_SND
};
template<typename... T> struct hash_ops<std::tuple<T...>> {
static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
static inline bool cmp(const std::tuple<T...> &a, const std::tuple<T...> &b) {
return a == b;
}
template<size_t I = 0>
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(const std::tuple<T...> &, Hasher h) {
return h;
}
template<size_t I = 0>
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(const std::tuple<T...> &a, Hasher h) {
typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
h = hash_into<I+1>(a, h);
h = element_ops_t::hash_into(std::get<I>(a), h);
return h;
}
HASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND
HASH_TOP_LOOP_FST (const std::tuple<T...> &a) HASH_TOP_LOOP_SND
};
template<typename T> struct hash_ops<std::vector<T>> {
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
static inline bool cmp(const std::vector<T> &a, const std::vector<T> &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash_into(std::vector<T> a, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const std::vector<T> &a, Hasher h) {
h.eat((uint32_t)a.size());
for (auto k : a)
h.eat(k);
return h;
}
HASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND
HASH_TOP_LOOP_FST (const std::vector<T> &a) HASH_TOP_LOOP_SND
};
template<typename T, size_t N> struct hash_ops<std::array<T, N>> {
static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {
static inline bool cmp(const std::array<T, N> &a, const std::array<T, N> &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash_into(std::array<T, N> a, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const std::array<T, N> &a, Hasher h) {
for (const auto& k : a)
h = hash_ops<T>::hash_into(k, h);
return h;
}
HASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND
HASH_TOP_LOOP_FST (const std::array<T, N> &a) HASH_TOP_LOOP_SND
};
struct hash_cstr_ops {
@ -300,10 +302,10 @@ template<> struct hash_ops<std::monostate> {
};
template<typename... T> struct hash_ops<std::variant<T...>> {
static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
static inline bool cmp(const std::variant<T...> &a, const std::variant<T...> &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash_into(std::variant<T...> a, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const std::variant<T...> &a, Hasher h) {
std::visit([& h](const auto &v) { h.eat(v); }, a);
h.eat(a.index());
return h;
@ -311,10 +313,10 @@ template<typename... T> struct hash_ops<std::variant<T...>> {
};
template<typename T> struct hash_ops<std::optional<T>> {
static inline bool cmp(std::optional<T> a, std::optional<T> b) {
static inline bool cmp(const std::optional<T> &a, const std::optional<T> &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash_into(std::optional<T> a, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const std::optional<T> &a, Hasher h) {
if(a.has_value())
h.eat(*a);
else
@ -356,6 +358,29 @@ template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
template<typename K, typename OPS = hash_ops<K>> class pool;
template<typename K, typename OPS = hash_ops<K>> class mfp;
// Computes the hash value of an unordered set of elements.
// See https://www.preprints.org/manuscript/201710.0192/v1/download.
// This is the Sum(4) algorithm from that paper, which has good collision resistance,
// much better than Sum(1) or Xor(1) (and somewhat better than Xor(4)).
class commutative_hash {
public:
commutative_hash() {
buckets.fill(0);
}
void eat(Hasher h) {
Hasher::hash_t v = h.yield();
size_t index = v & (buckets.size() - 1);
buckets[index] += v;
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
for (auto b : buckets)
h.eat(b);
return h;
}
private:
std::array<Hasher::hash_t, 4> buckets;
};
template<typename K, typename T, typename OPS>
class dict {
struct entry_t
@ -801,14 +826,14 @@ public:
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
commutative_hash comm;
for (auto &it : entries) {
Hasher entry_hash;
entry_hash.eat(it.udata.first);
entry_hash.eat(it.udata.second);
h.commutative_eat(entry_hash.yield());
comm.eat(entry_hash);
}
h.eat(entries.size());
return h;
return comm.hash_into(h);
}
void reserve(size_t n) { entries.reserve(n); }
@ -1184,11 +1209,11 @@ public:
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
commutative_hash comm;
for (auto &it : entries) {
h.commutative_eat(ops.hash(it.udata).yield());
comm.eat(ops.hash(it.udata));
}
h.eat(entries.size());
return h;
return comm.hash_into(h);
}
void reserve(size_t n) { entries.reserve(n); }
@ -1353,7 +1378,8 @@ public:
return p;
}
// Merge sets if the given indices belong to different sets
// Merge sets if the given indices belong to different sets.
// Makes ifind(j) the root of the merged set.
void imerge(int i, int j)
{
i = ifind(i);

View file

@ -412,6 +412,70 @@ static std::string string_view_stringf(std::string_view spec, ...)
return result;
}
static int spec_parameter_size(std::string_view spec)
{
// Every valid spec starts with '%' which means the code below
// won't look before the spec start.
switch (spec[spec.size() - 1]) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
switch (spec[spec.size() - 2]) {
case 'h':
if (spec[spec.size() - 3] == 'h')
return sizeof(char);
return sizeof(short);
case 'l':
if (spec[spec.size() - 3] == 'l')
return sizeof(long long);
return sizeof(long);
case 'L':
case 'q':
return sizeof(long long);
case 'j':
return sizeof(intmax_t);
case 'z':
case 'Z':
return sizeof(size_t);
case 't':
return sizeof(ptrdiff_t);
}
return sizeof(int);
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
case 'a':
case 'A':
if (spec[spec.size() - 2] == 'L')
return sizeof(long double);
if (spec[spec.size() - 2] == 'l' && spec[spec.size() - 3] == 'l')
return sizeof(long double);
return sizeof(double);
case 'c':
if (spec[spec.size() - 2] == 'l') {
return sizeof(wchar_t);
}
return sizeof(unsigned char);
case 'C':
return sizeof(wchar_t);
case 's':
case 'p':
case 'S':
case 'n':
return sizeof(void *);
case 'm':
return sizeof(int);
default:
return -1;
}
}
template <typename Arg>
static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints,
DynamicIntCount num_dynamic_ints, Arg arg)
@ -439,7 +503,13 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna
result += std::to_string(static_cast<int>(arg));
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
if (spec_parameter_size(spec) <= 4) {
// On some platforms (Wasm) we must ensure that the arg is properly aligned
// after the dynamic `int` parameters.
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (int)arg);
} else {
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
}
}
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
@ -454,7 +524,13 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec,
result += static_cast<char>(arg);
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
if (spec_parameter_size(spec) <= 4) {
// On some platforms (Wasm) we must ensure that the arg is properly aligned
// after the dynamic `int` parameters.
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (unsigned int)arg);
} else {
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
}
}
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,

View file

@ -44,6 +44,7 @@ std::vector<std::string> log_scratchpads;
std::map<std::string, std::set<std::string>> log_hdump;
std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;
std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
int log_warnings_count = 0;
int log_warnings_count_noexpect = 0;
@ -178,7 +179,7 @@ void logv(const char *format, va_list ap)
{
log_warn_regex_recusion_guard = true;
if (log_warn_regexes.empty() && log_expect_log.empty())
if (log_warn_regexes.empty() && log_expect_log.empty() && log_expect_prefix_log.empty())
{
linebuffer.clear();
}
@ -191,9 +192,9 @@ void logv(const char *format, va_list ap)
if (std::regex_search(linebuffer, re))
log_warning("Found log message matching -W regex:\n%s", str.c_str());
for (auto &item : log_expect_log)
if (std::regex_search(linebuffer, item.second.pattern))
item.second.current_count++;
for (auto &[_, item] : log_expect_log)
if (std::regex_search(linebuffer, item.pattern))
item.current_count++;
linebuffer.clear();
}
@ -266,9 +267,15 @@ static void logv_warning_with_prefix(const char *prefix,
log_error("%s", message.c_str());
bool warning_match = false;
for (auto &item : log_expect_warning)
if (std::regex_search(message, item.second.pattern)) {
item.second.current_count++;
for (auto &[_, item] : log_expect_warning)
if (std::regex_search(message, item.pattern)) {
item.current_count++;
warning_match = true;
}
for (auto &[_, item] : log_expect_prefix_warning)
if (std::regex_search(string(prefix) + message, item.pattern)) {
item.current_count++;
warning_match = true;
}
@ -355,9 +362,13 @@ static void logv_error_with_prefix(const char *prefix,
log_make_debug = bak_log_make_debug;
for (auto &item : log_expect_error)
if (std::regex_search(log_last_error, item.second.pattern))
item.second.current_count++;
for (auto &[_, item] : log_expect_error)
if (std::regex_search(log_last_error, item.pattern))
item.current_count++;
for (auto &[_, item] : log_expect_prefix_error)
if (std::regex_search(string(prefix) + string(log_last_error), item.pattern))
item.current_count++;
log_check_expected();
@ -705,38 +716,39 @@ void log_check_expected()
// copy out all of the expected logs so that they cannot be re-checked
// or match against themselves
dict<std::string, LogExpectedItem> expect_log, expect_warning, expect_error;
dict<std::string, LogExpectedItem> expect_prefix_log, expect_prefix_warning, expect_prefix_error;
std::swap(expect_warning, log_expect_warning);
std::swap(expect_log, log_expect_log);
std::swap(expect_error, log_expect_error);
std::swap(expect_prefix_warning, log_expect_prefix_warning);
std::swap(expect_prefix_log, log_expect_prefix_log);
std::swap(expect_prefix_error, log_expect_prefix_error);
for (auto &item : expect_warning) {
if (item.second.current_count == 0) {
auto check = [&](const std::string kind, std::string pattern, LogExpectedItem item) {
if (item.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str());
}
if (item.second.current_count != item.second.expected_count) {
if (item.current_count != item.expected_count) {
log_warn_regexes.clear();
log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n",
item.first.c_str(), item.second.current_count, item.second.expected_count);
log_error("Expected %s pattern '%s' found %d time(s), instead of %d time(s) !\n",
kind.c_str(), pattern.c_str(), item.current_count, item.expected_count);
}
}
};
for (auto &item : expect_log) {
if (item.second.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
}
if (item.second.current_count != item.second.expected_count) {
log_warn_regexes.clear();
log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n",
item.first.c_str(), item.second.current_count, item.second.expected_count);
}
}
for (auto &[pattern, item] : expect_warning)
check("warning", pattern, item);
for (auto &[pattern, item] : expect_prefix_warning)
check("prefixed warning", pattern, item);
for (auto &[pattern, item] : expect_log)
check("log", pattern, item);
for (auto &[pattern, item] : expect_prefix_log)
check("prefixed log", pattern, item);
for (auto &item : expect_error)
if (item.second.current_count == item.second.expected_count) {
auto check_err = [&](const std::string kind, std::string pattern, LogExpectedItem item) {
if (item.current_count == item.expected_count) {
log_warn_regexes.clear();
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
log("Expected %s pattern '%s' found !!!\n", kind.c_str(), pattern.c_str());
yosys_shutdown();
#ifdef EMSCRIPTEN
throw 0;
@ -747,8 +759,13 @@ void log_check_expected()
#endif
} else {
log_warn_regexes.clear();
log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str());
}
};
for (auto &[pattern, item] : expect_error)
check_err("error", pattern, item);
for (auto &[pattern, item] : expect_prefix_error)
check_err("prefixed error", pattern, item);
}
// ---------------------------------------------------

View file

@ -201,6 +201,7 @@ struct LogExpectedItem
};
extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
extern dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;
void log_check_expected();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);

View file

@ -952,10 +952,6 @@ RTLIL::Design::~Design()
delete pr.second;
for (auto n : bindings_)
delete n;
for (auto n : verilog_packages)
delete n;
for (auto n : verilog_globals)
delete n;
#ifdef WITH_PYTHON
RTLIL::Design::get_all_designs()->erase(hashidx_);
#endif
@ -4287,9 +4283,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
return;
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux) || type == ID($bwmux) || type == ID($bweqx)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
if (type != ID($buf) && type != ID($mux))
if (type.in(ID($pmux), ID($bmux)))
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
check();
return;
@ -4344,7 +4340,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
parameters[ID::B_WIDTH] = GetSize(connections_[ID::B]);
}
if (connections_.count(ID::Y))
if (connections_.count(ID::Y) && type != ID($concat))
parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]);
if (connections_.count(ID::Q))
@ -5710,16 +5706,10 @@ static void sigspec_parse_split(std::vector<std::string> &tokens, const std::str
tokens.push_back(text.substr(start));
}
static int sigspec_parse_get_dummy_line_num()
{
return 0;
}
bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
{
cover("kernel.rtlil.sigspec.parse");
AST::current_filename = "input";
std::vector<std::string> tokens;
sigspec_parse_split(tokens, str, ',');
@ -5735,12 +5725,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') {
cover("kernel.rtlil.sigspec.parse.const");
AST::get_line_num = sigspec_parse_get_dummy_line_num;
AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname);
if (ast == NULL)
VERILOG_FRONTEND::ConstParser p{Location()};
auto ast = p.const2ast(netname);
if (ast == nullptr)
return false;
sig.append(RTLIL::Const(ast->bits));
delete ast;
continue;
}

View file

@ -1334,7 +1334,7 @@ struct RTLIL::Design
dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Binding*> bindings_;
std::vector<AST::AstNode*> verilog_packages, verilog_globals;
std::vector<std::unique_ptr<AST::AstNode>> verilog_packages, verilog_globals;
std::unique_ptr<define_map_t> verilog_defines;
std::vector<RTLIL::Selection> selection_stack;

View file

@ -64,7 +64,7 @@ struct ezSatPtr : public std::unique_ptr<ezSAT> {
struct SatGen
{
ezSAT *ez;
SigMap *sigmap;
const SigMap *sigmap;
std::string prefix;
SigPool initial_state;
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
@ -75,12 +75,12 @@ struct SatGen
bool model_undef;
bool def_formal = false;
SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) :
SatGen(ezSAT *ez, const SigMap *sigmap, std::string prefix = std::string()) :
ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)
{
}
void setContext(SigMap *sigmap, std::string prefix = std::string())
void setContext(const SigMap *sigmap, std::string prefix = std::string())
{
this->sigmap = sigmap;
this->prefix = prefix;

View file

@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell
template<typename T>
class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};
struct SigMapView
{
mfp<SigBit> database;
// Modify bit to its representative
void apply(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
}
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
apply(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
apply(bit);
return bit;
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
SigSpec sig(wire);
apply(sig);
return sig;
}
};
/**
* SigMap wraps a union-find "database"
* to map SigBits of a module to canonical representative SigBits.
@ -244,10 +280,8 @@ class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name
* If a SigBit has a const state (impl: bit.wire is nullptr),
* it's promoted to a representative.
*/
struct SigMap
struct SigMap final : public SigMapView
{
mfp<SigBit> database;
SigMap(RTLIL::Module *module = NULL)
{
if (module != NULL)
@ -320,37 +354,6 @@ struct SigMap
inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }
// Modify bit to its representative
void apply(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
}
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
apply(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
apply(bit);
return bit;
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
SigSpec sig(wire);
apply(sig);
return sig;
}
// All non-const bits
RTLIL::SigSpec allbits() const
{
@ -362,6 +365,107 @@ struct SigMap
}
};
/**
* SiValgMap wraps a union-find "database" to map SigBits of a module to
* canonical representative SigBits plus some optional Val value associated with the bits.
* Val has a commutative, associative, idempotent operator|=, a default constructor
* which constructs an identity element, and a copy constructor.
* SigBits that are connected share a set in the underlying database;
* the associated value is the "sum" of all the values associated with the contributing bits.
* If any of the SigBits in a set are a constant, the canonical SigBit is a constant.
*/
template <class Val>
struct SigValMap final : public SigMapView
{
dict<SigBit, Val> values;
void swap(SigValMap<Val> &other)
{
database.swap(other.database);
values.swap(other.values);
}
void clear()
{
database.clear();
values.clear();
}
// Rebuild SigMap for all connections in module
void set(RTLIL::Module *module)
{
int bitcount = 0;
for (auto &it : module->connections())
bitcount += it.first.size();
database.clear();
values.clear();
database.reserve(bitcount);
for (auto &it : module->connections())
add(it.first, it.second);
}
// Add connections from "from" to "to", bit-by-bit.
void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)
{
log_assert(GetSize(from) == GetSize(to));
for (int i = 0; i < GetSize(from); i++)
{
int bfi = database.lookup(from[i]);
int bti = database.lookup(to[i]);
if (bfi == bti) {
continue;
}
const RTLIL::SigBit &bf = database[bfi];
const RTLIL::SigBit &bt = database[bti];
if (bf.wire == nullptr) {
// bf is constant so make it the canonical representative.
database.imerge(bti, bfi);
merge_value(bt, bf);
} else {
// Make bt the canonical representative.
database.imerge(bfi, bti);
merge_value(bf, bt);
}
}
}
void addVal(const RTLIL::SigBit &bit, const Val &val)
{
values[database.find(bit)] |= val;
}
void addVal(const RTLIL::SigSpec &sig, const Val &val)
{
for (const auto &bit : sig)
addVal(bit, val);
}
Val apply_and_get_value(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
auto it = values.find(bit);
return it == values.end() ? Val() : it->second;
}
private:
void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to)
{
auto it = values.find(from);
if (it == values.end()) {
return;
}
// values[to] could resize the underlying `entries` so
// finish using `it` first.
Val v = it->second;
values.erase(it);
values[to] |= v;
}
};
YOSYS_NAMESPACE_END
#endif /* SIGTOOLS_H */

View file

@ -20,6 +20,7 @@
#ifndef YOSYS_COMMON_H
#define YOSYS_COMMON_H
#include <array>
#include <map>
#include <set>
#include <tuple>

View file

@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/.
rm -rf zlib-1.2.11
pushd "$vcxsrc"/yosys
ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt
if [ -f "/usr/include/FlexLexer.h" ] ; then
mkdir -p libs/flex
cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h
ls libs/flex/*.h >> ../../srcfiles.txt
fi
popd
{
n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
@ -31,6 +38,9 @@ popd
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
if [ -f "/usr/include/FlexLexer.h" ] ; then
sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
fi
mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj
mkdir -p "$vcxsrc"/yosys

View file

@ -373,6 +373,12 @@ struct AbstractPass : public Pass {
log(" abstractions performed by either mode. This option is not supported in\n");
log(" the -init mode.\n");
log("\n");
log(" -initstates <n>\n");
log(" Perform conditional abstraction for the first <n> time steps. See the\n");
log(" description of the -state and -value modes for details on how the\n");
log(" condition affects the abstractions performed by either mode. This option\n");
log(" is not supported in the -init mode.\n");
log("\n");
log(" -slice <lhs>:<rhs>\n");
log(" -slice <index>\n");
log(" -rtlilslice <lhs>:<rhs>\n");
@ -402,8 +408,10 @@ struct AbstractPass : public Pass {
Always = -1,
ActiveLow = false, // ensuring we can use bool(enable)
ActiveHigh = true,
Initstates = 2,
};
Enable enable = Enable::Always;
int initstates = 0;
std::string enable_name;
std::vector<Slice> slices;
for (argidx = 1; argidx < args.size(); argidx++)
@ -435,6 +443,13 @@ struct AbstractPass : public Pass {
enable = Enable::ActiveLow;
continue;
}
if (arg == "-initstates" && argidx + 1 < args.size()) {
if (enable != Enable::Always)
log_cmd_error("Multiple enable condition are not supported\n");
initstates = atoi(args[++argidx].c_str());
enable = Enable::Initstates;
continue;
}
if (arg == "-slice" && argidx + 1 < args.size()) {
slices.emplace_back(SliceIndices::HdlSlice, args[++argidx]);
continue;
@ -451,22 +466,50 @@ struct AbstractPass : public Pass {
if (mode == Mode::Initial)
log_cmd_error("Conditional initial value abstraction is not supported\n");
if (enable_name.empty())
log_cmd_error("Unspecified enable wire\n");
switch (enable) {
case Enable::Always:
log_assert(false);
case Enable::ActiveLow:
case Enable::ActiveHigh: {
if (enable_name.empty())
log_cmd_error("Unspecified enable wire\n");
} break;
case Enable::Initstates: {
if (initstates <= 0)
log_cmd_error("Number of initial time steps must be positive\n");
} break;
}
}
unsigned int changed = 0;
if ((mode == State) || (mode == Value)) {
for (auto mod : design->selected_modules()) {
EnableLogic enable_logic = { State::S1, true };
if (enable != Enable::Always) {
Wire *enable_wire = mod->wire("\\" + enable_name);
if (!enable_wire)
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
if (GetSize(enable_wire) != 1)
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
EnableLogic enable_logic;
switch (enable) {
case Enable::Always: {
enable_logic = { State::S1, true };
} break;
case Enable::ActiveLow:
case Enable::ActiveHigh: {
Wire *enable_wire = mod->wire("\\" + enable_name);
if (!enable_wire)
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
if (GetSize(enable_wire) != 1)
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
} break;
case Enable::Initstates: {
SigBit in_init_states = mod->Initstate(NEW_ID);
for (int i = 1; i < initstates; i++) {
Wire *in_init_states_q = mod->addWire(NEW_ID);
mod->addFf(NEW_ID, in_init_states, in_init_states_q);
in_init_states_q->attributes[ID::init] = State::S1;
in_init_states = in_init_states_q;
}
enable_logic = { in_init_states, true };
} break;
}
if (mode == State)
changed += abstract_state(mod, enable_logic, slices);

View file

@ -195,16 +195,23 @@ struct CheckPass : public Pass {
// in port widths are those for us to check.
if (!cell->type.in(
ID($add), ID($sub),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($pmux), ID($bmux)))
return false;
int in_widths = 0, out_widths = 0;
for (auto &conn : cell->connections()) {
if (cell->input(conn.first))
in_widths += conn.second.size();
if (cell->output(conn.first))
out_widths += conn.second.size();
if (cell->type.in(ID($pmux), ID($bmux))) {
// We're skipping inputs A and B, since each of their bits contributes only one edge
in_widths = GetSize(cell->getPort(ID::S));
out_widths = GetSize(cell->getPort(ID::Y));
} else {
for (auto &conn : cell->connections()) {
if (cell->input(conn.first))
in_widths += conn.second.size();
if (cell->output(conn.first))
out_widths += conn.second.size();
}
}
const int threshold = 1024;

View file

@ -368,14 +368,8 @@ struct DesignPass : public Pass {
if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
{
for (auto node : design->verilog_packages)
delete node;
design->verilog_packages.clear();
for (auto node : design->verilog_globals)
delete node;
design->verilog_globals.clear();
design->verilog_defines->clear();
}

View file

@ -65,6 +65,8 @@ struct LoggerPass : public Pass {
log(" -expect <type> <regex> <expected_count>\n");
log(" expect log, warning or error to appear. matched errors will terminate\n");
log(" with exit code 0.\n");
log(" Types prefix-log, prefix-warning and prefix-error match the entire\n");
log(" logged string, including filename if present.\n");
log("\n");
log(" -expect-no-warnings\n");
log(" gives error in case there is at least one warning that is not expected.\n");
@ -156,26 +158,33 @@ struct LoggerPass : public Pass {
}
if (args[argidx] == "-expect" && argidx+3 < args.size()) {
std::string type = args[++argidx];
if (type!="error" && type!="warning" && type!="log")
if (type!="error" && type!="warning" && type!="log"
&& type!="prefix-error" && type!="prefix-warning" && type!="prefix-log")
log_cmd_error("Expect command require type to be 'log', 'warning' or 'error' !\n");
if (type=="error" && log_expect_error.size()>0)
if ((type=="error" || type=="prefix-error") && log_expect_error.size()>0)
log_cmd_error("Only single error message can be expected !\n");
std::string pattern = args[++argidx];
if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2);
if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2);
int count = atoi(args[++argidx].c_str());
if (count<=0)
log_cmd_error("Number of expected messages must be higher then 0 !\n");
if (type=="error" && count!=1)
if ((type=="error" || type=="prefix-error") && count!=1)
log_cmd_error("Expected error message occurrences must be 1 !\n");
log("Added regex '%s' to expected %s messages list.\n",
pattern.c_str(), type.c_str());
try {
if (type == "error")
log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type == "prefix-error")
log_expect_prefix_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type == "warning")
log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type == "prefix-warning")
log_expect_prefix_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type == "log")
log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else if (type == "prefix-log")
log_expect_prefix_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
else log_abort();
}
catch (const std::regex_error& e) {

View file

@ -67,7 +67,7 @@ static std::string derive_name_from_src(const std::string &src, int counter)
return stringf("\\%s$%d", src_base.c_str(), counter);
}
static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix)
static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix, bool move_to_cell)
{
// Find output
const SigSpec *output = nullptr;
@ -93,13 +93,21 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, strin
name += chunk.wire->name.str();
if (chunk.wire->width != chunk.width) {
name += "[";
if (chunk.width != 1)
name += std::to_string(chunk.offset + chunk.width) + ":";
name += std::to_string(chunk.offset) + "]";
int lhs = chunk.wire->to_hdl_index(chunk.offset + chunk.width - 1);
int rhs = chunk.wire->to_hdl_index(chunk.offset);
if (lhs != rhs)
name += stringf("[%d:%d]", lhs, rhs);
else
name += stringf("[%d]", lhs);
}
}
RTLIL::Wire *wire;
if (move_to_cell && (!(wire = cell->module->wire(name)) || !(wire->port_input || wire->port_output)))
return name;
if (suffix.empty()) {
suffix = cell->type.str();
}
@ -232,13 +240,17 @@ struct RenamePass : public Pass {
log("cells with private names.\n");
log("\n");
log("\n");
log(" rename -wire [selection] [-suffix <suffix>]\n");
log(" rename -wire [selection] [-move-to-cell] [-suffix <suffix>]\n");
log("\n");
log("Assign auto-generated names based on the wires they drive to all selected\n");
log("cells with private names. Ignores cells driving privatly named wires.\n");
log("By default, the cell is named after the wire with the cell type as suffix.\n");
log("The -suffix option can be used to set the suffix to the given string instead.\n");
log("\n");
log("The -move-to-cell option can be used to name the cell after the wire without\n");
log("any suffix. If this would lead to conflicts, the suffix is added to the wire\n");
log("instead. For cells driving ports, the -move-to-cell option is ignored.\n");
log("\n");
log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
@ -286,6 +298,7 @@ struct RenamePass : public Pass {
std::string cell_suffix = "";
bool flag_src = false;
bool flag_wire = false;
bool flag_move_to_cell = false;
bool flag_enumerate = false;
bool flag_witness = false;
bool flag_hide = false;
@ -345,6 +358,10 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
if (arg == "-move-to-cell" && flag_wire && !flag_move_to_cell) {
flag_move_to_cell = true;
continue;
}
if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) {
int pos = args[++argidx].find('%');
pattern_prefix = args[argidx].substr(0, pos);
@ -396,9 +413,26 @@ struct RenamePass : public Pass {
dict<RTLIL::Cell *, IdString> new_cell_names;
for (auto cell : module->selected_cells())
if (cell->name[0] == '$')
new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix);
for (auto &it : new_cell_names)
module->rename(it.first, it.second);
new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix, flag_move_to_cell);
for (auto &[cell, new_name] : new_cell_names) {
if (flag_move_to_cell) {
RTLIL::Wire *found_wire = module->wire(new_name);
if (found_wire) {
std::string wire_suffix = cell_suffix;
if (wire_suffix.empty()) {
for (auto const &[port, _] : cell->connections()) {
if (cell->output(port)) {
wire_suffix += stringf("%s.%s", cell->type.c_str(), port.c_str() + 1);
break;
}
}
}
IdString new_wire_name = found_wire->name.str() + wire_suffix;
module->rename(found_wire, new_wire_name);
}
}
module->rename(cell, new_name);
}
}
}
else
@ -564,6 +598,8 @@ struct RenamePass : public Pass {
for (auto &it : new_cell_names)
module->rename(it.first, it.second);
module->fixup_ports();
}
}
else

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,7 @@ struct ContextData {
std::string unused_outputs;
};
std::optional<std::string> format(std::string fmt, const dict<IdString, Const> &parameters,
std::optional<std::string> format_with_params(std::string fmt, const dict<IdString, Const> &parameters,
const ContextData &context)
{
std::stringstream result;
@ -230,7 +230,7 @@ struct WrapcellPass : Pass {
context.unused_outputs += "_" + RTLIL::unescape_id(chunk.format(cell));
}
std::optional<std::string> unescaped_name = format(name_fmt, cell->parameters, context);
std::optional<std::string> unescaped_name = format_with_params(name_fmt, cell->parameters, context);
if (!unescaped_name)
log_error("Formatting error when processing cell '%s' in module '%s'\n",
log_id(cell), log_id(module));
@ -270,7 +270,7 @@ struct WrapcellPass : Pass {
if (rule.value_fmt.empty()) {
subm->set_bool_attribute(rule.name);
} else {
std::optional<std::string> value = format(rule.value_fmt, cell->parameters, context);
std::optional<std::string> value = format_with_params(rule.value_fmt, cell->parameters, context);
if (!value)
log_error("Formatting error when processing cell '%s' in module '%s'\n",

View file

@ -37,14 +37,15 @@ struct EquivInductWorker
int max_seq;
int success_counter;
bool set_assumes;
dict<int, int> ez_step_is_consistent;
pool<Cell*> cell_warn_cache;
SigPool undriven_signals;
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq) : module(module), sigmap(module),
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq, bool set_assumes) : module(module), sigmap(module),
cells(module->selected_cells()), workset(unproven_equiv_cells),
satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0)
satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0), set_assumes(set_assumes)
{
satgen.model_undef = model_undef;
}
@ -77,6 +78,16 @@ struct EquivInductWorker
}
}
if (set_assumes) {
if (step == 1) {
RTLIL::SigSpec assumes_a, assumes_en;
satgen.getAssumes(assumes_a, assumes_en, step);
for (int i = 0; i < GetSize(assumes_a); i++)
log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
}
ez->assume(satgen.importAssumes(step));
}
if (satgen.model_undef) {
for (auto bit : undriven_signals.export_all())
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step)));
@ -184,6 +195,9 @@ struct EquivInductPass : public Pass {
log(" -seq <N>\n");
log(" the max. number of time steps to be considered (default = 4)\n");
log("\n");
log(" -set-assumes\n");
log(" set all assumptions provided via $assume cells\n");
log("\n");
log("This command is very effective in proving complex sequential circuits, when\n");
log("the internal state of the circuit quickly propagates to $equiv cells.\n");
log("\n");
@ -200,7 +214,7 @@ struct EquivInductPass : public Pass {
void execute(std::vector<std::string> args, Design *design) override
{
int success_counter = 0;
bool model_undef = false;
bool model_undef = false, set_assumes = false;
int max_seq = 4;
log_header(design, "Executing EQUIV_INDUCT pass.\n");
@ -215,6 +229,10 @@ struct EquivInductPass : public Pass {
max_seq = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-set-assumes") {
set_assumes = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -222,6 +240,7 @@ struct EquivInductPass : public Pass {
for (auto module : design->selected_modules())
{
pool<Cell*> unproven_equiv_cells;
vector<Cell*> assume_cells;
for (auto cell : module->selected_cells())
if (cell->type == ID($equiv)) {
@ -234,7 +253,7 @@ struct EquivInductPass : public Pass {
continue;
}
EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq);
EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq, set_assumes);
worker.run();
success_counter += worker.success_counter;
}

View file

@ -27,215 +27,345 @@ struct EquivSimpleWorker
{
Module *module;
const vector<Cell*> &equiv_cells;
Cell *equiv_cell;
const vector<Cell*> &assume_cells;
struct Cone {
pool<Cell*> cells;
pool<SigBit> bits;
void clear() {
cells.clear();
bits.clear();
}
};
SigMap &sigmap;
dict<SigBit, Cell*> &bit2driver;
struct DesignModel {
const SigMap &sigmap;
dict<SigBit, Cell*> &bit2driver;
};
DesignModel model;
ezSatPtr ez;
SatGen satgen;
int max_seq;
bool short_cones;
bool verbose;
struct Config {
bool verbose = false;
bool short_cones = false;
bool model_undef = false;
bool nogroup = false;
bool set_assumes = false;
int max_seq = 1;
};
Config cfg;
pool<pair<Cell*, int>> imported_cells_cache;
EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef) :
module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr),
sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose)
EquivSimpleWorker(const vector<Cell*> &equiv_cells, const vector<Cell*> &assume_cells, DesignModel model, Config cfg) :
module(equiv_cells.front()->module), equiv_cells(equiv_cells), assume_cells(assume_cells),
model(model), satgen(ez.get(), &model.sigmap), cfg(cfg)
{
satgen.model_undef = model_undef;
satgen.model_undef = cfg.model_undef;
}
bool find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, Cell *cell)
{
if (cells_cone.count(cell))
struct ConeFinder {
DesignModel model;
// Bits we should also analyze in a later iteration (flop inputs)
pool<SigBit> &next_seed;
// Cells and bits we've seen so far while traversing
Cone& cone;
// We're not allowed to traverse past cells and bits in `stop`
const Cone& stop;
// Input bits are bits that no longer can be traversed
// Tracking these is optional
pool<SigBit>* input_bits;
// Recursively traverses backwards from a cell to find all cells in its input cone
// Adds cell to cone.cells, stops at cells in 'stop' set
// Returns true if stopped on a stop cell
bool find_input_cone(Cell *cell)
{
if (cone.cells.count(cell))
return false;
cone.cells.insert(cell);
if (stop.cells.count(cell))
return true;
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_input(cell->type, conn.first))
for (auto bit : model.sigmap(conn.second)) {
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
if (!conn.first.in(ID::CLK, ID::C))
next_seed.insert(bit);
} else
find_input_cone(bit);
}
return false;
}
void find_input_cone(SigBit bit)
{
if (cone.bits.count(bit))
return;
cells_cone.insert(cell);
cone.bits.insert(bit);
if (cells_stop.count(cell))
return true;
if (stop.bits.count(bit)) {
if (input_bits != nullptr) input_bits->insert(bit);
return;
}
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_input(cell->type, conn.first))
for (auto bit : sigmap(conn.second)) {
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
if (!conn.first.in(ID::CLK, ID::C))
next_seed.insert(bit);
} else
find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit);
}
return false;
}
if (!model.bit2driver.count(bit))
return;
void find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, SigBit bit)
// If the input cone of the driver cell reaches a stop bit,
// then `bit` is an "input bit"
if (find_input_cone(model.bit2driver.at(bit)))
if (input_bits != nullptr) input_bits->insert(bit);
}
void find_input_cone(pool<SigBit> bits)
{
for (auto bit : bits)
find_input_cone(bit);
}
};
// Builds (full or short) input cones from the seeds
// Creates full cones (no stops) and optionally short cones (stop at other side's cone)
// Updates seed_a/seed_b with next iteration's FF inputs
// Returns input bits and cone structures for SAT problem construction
std::tuple<pool<SigBit>, Cone, Cone> init_iter(pool<SigBit>& seed_a, pool<SigBit>& seed_b) const
{
if (bits_cone.count(bit))
return;
// Empty, never inserted to, to traverse full cones
const Cone no_stop;
Cone full_cone_a, full_cone_b;
bits_cone.insert(bit);
// Values of seed_* for the next iteration
pool<SigBit> next_seed_a, next_seed_b;
if (bits_stop.count(bit)) {
if (input_bits != nullptr) input_bits->insert(bit);
return;
{
ConeFinder finder_a {model, next_seed_a, full_cone_a, no_stop, nullptr};
finder_a.find_input_cone(seed_a);
ConeFinder finder_b {model, next_seed_b, full_cone_b, no_stop, nullptr};
finder_b.find_input_cone(seed_b);
}
if (!bit2driver.count(bit))
return;
Cone short_cone_a, short_cone_b;
pool<SigBit> input_bits;
if (find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit2driver.at(bit)))
if (input_bits != nullptr) input_bits->insert(bit);
if (cfg.short_cones)
{
// Rebuild cones with the knowledge of the full cones.
// Avoids stuffing overlaps in input cones into the solver
// e.g. for A by using the full B cone as stops
next_seed_a.clear();
ConeFinder short_finder_a = {model, next_seed_a, short_cone_a, short_cone_b, &input_bits};
short_finder_a.find_input_cone(seed_a);
next_seed_a.swap(seed_a);
next_seed_b.clear();
ConeFinder short_finder_b = {model, next_seed_b, short_cone_b, short_cone_a, &input_bits};
short_finder_b.find_input_cone(seed_b);
next_seed_b.swap(seed_b);
}
else
{
short_cone_a = full_cone_a;
next_seed_a.swap(seed_a);
short_cone_b = full_cone_b;
next_seed_b.swap(seed_b);
}
return std::make_tuple(input_bits, short_cone_a, short_cone_b);
}
bool run_cell()
void report_new_cells(const pool<Cell*>& cells, const Cone& cone_a, const Cone& cone_b) const
{
SigBit bit_a = sigmap(equiv_cell->getPort(ID::A)).as_bit();
SigBit bit_b = sigmap(equiv_cell->getPort(ID::B)).as_bit();
int ez_context = ez->frozen_literal();
log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
GetSize(cells), GetSize(cone_a.cells), GetSize(cone_b.cells),
(GetSize(cone_a.cells) + GetSize(cone_b.cells)) - GetSize(cells));
#if 0
for (auto cell : short_cells_cone_a)
log(" A-side cell: %s\n", log_id(cell));
for (auto cell : short_cells_cone_b)
log(" B-side cell: %s\n", log_id(cell));
#endif
}
void report_new_assume_cells(const pool<Cell*>& extra_problem_cells, int old_size, const pool<Cell*>& problem_cells) const
{
if (cfg.verbose) {
log(" Adding %d new cells to check assumptions (and reusing %d).\n",
GetSize(problem_cells) - old_size,
old_size - (GetSize(problem_cells) - GetSize(extra_problem_cells)));
#if 0
for (auto cell : extra_problem_cells)
log(" cell: %s\n", log_id(cell));
#endif
}
}
// Ensure the input cones of $assume cells get modelled by the problem
pool<Cell*> add_assumes_to_problem(const Cone& cone_a, const Cone& cone_b) const
{
pool<Cell*> extra_problem_cells;
for (auto assume : assume_cells) {
pool<SigBit> assume_seed, dummy_next_seed, overlap_bits;
assume_seed.insert(model.sigmap(assume->getPort(ID::A)).as_bit());
assume_seed.insert(model.sigmap(assume->getPort(ID::EN)).as_bit());
for (auto& cone : {cone_a, cone_b}) {
Cone assume_cone;
ConeFinder{model, dummy_next_seed, assume_cone, cone, &overlap_bits}
.find_input_cone(assume_seed);
if (GetSize(overlap_bits)) {
extra_problem_cells.insert(assume);
extra_problem_cells.insert(assume_cone.cells.begin(), assume_cone.cells.end());
overlap_bits.clear();
}
assume_cone.clear();
dummy_next_seed.clear();
}
}
return extra_problem_cells;
}
static void report_missing_model(Cell* cell)
{
if (RTLIL::builtin_ff_cell_types().count(cell->type))
log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
else
log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
}
void prepare_ezsat(int ez_context, SigBit bit_a, SigBit bit_b)
{
if (satgen.model_undef)
{
int ez_a = satgen.importSigBit(bit_a, max_seq+1);
int ez_b = satgen.importDefSigBit(bit_b, max_seq+1);
int ez_undef_a = satgen.importUndefSigBit(bit_a, max_seq+1);
int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1);
int ez_b = satgen.importDefSigBit(bit_b, cfg.max_seq+1);
int ez_undef_a = satgen.importUndefSigBit(bit_a, cfg.max_seq+1);
ez->assume(ez->XOR(ez_a, ez_b), ez_context);
ez->assume(ez->NOT(ez_undef_a), ez_context);
}
else
{
int ez_a = satgen.importSigBit(bit_a, max_seq+1);
int ez_b = satgen.importSigBit(bit_b, max_seq+1);
int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1);
int ez_b = satgen.importSigBit(bit_b, cfg.max_seq+1);
ez->assume(ez->XOR(ez_a, ez_b), ez_context);
}
}
void construct_ezsat(const pool<SigBit>& input_bits, int step)
{
if (cfg.set_assumes) {
if (cfg.verbose && step == cfg.max_seq) {
RTLIL::SigSpec assumes_a, assumes_en;
satgen.getAssumes(assumes_a, assumes_en, step+1);
for (int i = 0; i < GetSize(assumes_a); i++)
log(" Import constraint from assume cell: %s when %s (%d).\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]), step);
}
ez->assume(satgen.importAssumes(step+1));
}
if (satgen.model_undef) {
for (auto bit : input_bits)
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
}
if (cfg.verbose)
log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
}
bool prove_equiv_cell(Cell* cell)
{
SigBit bit_a = model.sigmap(cell->getPort(ID::A)).as_bit();
SigBit bit_b = model.sigmap(cell->getPort(ID::B)).as_bit();
int ez_context = ez->frozen_literal();
prepare_ezsat(ez_context, bit_a, bit_b);
// Two bits, bit_a, and bit_b, have been marked equivalent in the design
// We will be traversing the input cones for each of them
// In the first iteration, we will using those as starting points
pool<SigBit> seed_a = { bit_a };
pool<SigBit> seed_b = { bit_b };
if (verbose) {
log(" Trying to prove $equiv cell %s:\n", log_id(equiv_cell));
log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(equiv_cell->getPort(ID::Y)));
if (cfg.verbose) {
log(" Trying to prove $equiv cell %s:\n", log_id(cell));
log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(cell->getPort(ID::Y)));
} else {
log(" Trying to prove $equiv for %s:", log_signal(equiv_cell->getPort(ID::Y)));
log(" Trying to prove $equiv for %s:", log_signal(cell->getPort(ID::Y)));
}
int step = max_seq;
int step = cfg.max_seq;
while (1)
{
pool<Cell*> no_stop_cells;
pool<SigBit> no_stop_bits;
pool<Cell*> full_cells_cone_a, full_cells_cone_b;
pool<SigBit> full_bits_cone_a, full_bits_cone_b;
pool<SigBit> next_seed_a, next_seed_b;
for (auto bit_a : seed_a)
find_input_cone(next_seed_a, full_cells_cone_a, full_bits_cone_a, no_stop_cells, no_stop_bits, nullptr, bit_a);
for (auto bit_b : seed_b)
find_input_cone(next_seed_b, full_cells_cone_b, full_bits_cone_b, no_stop_cells, no_stop_bits, nullptr, bit_b);
pool<Cell*> short_cells_cone_a, short_cells_cone_b;
pool<SigBit> short_bits_cone_a, short_bits_cone_b;
pool<SigBit> input_bits;
if (short_cones)
{
next_seed_a.clear();
for (auto bit_a : seed_a)
find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
next_seed_a.swap(seed_a);
next_seed_b.clear();
for (auto bit_b : seed_b)
find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
next_seed_b.swap(seed_b);
}
else
{
short_cells_cone_a = full_cells_cone_a;
short_bits_cone_a = full_bits_cone_a;
next_seed_a.swap(seed_a);
short_cells_cone_b = full_cells_cone_b;
short_bits_cone_b = full_bits_cone_b;
next_seed_b.swap(seed_b);
}
// Traverse input cones of seed_a and seed_b, potentially finding new seeds
auto [input_bits, cone_a, cone_b] = init_iter(seed_a, seed_b);
// Cells to model in SAT solver
pool<Cell*> problem_cells;
problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end());
problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end());
problem_cells.insert(cone_a.cells.begin(), cone_a.cells.end());
problem_cells.insert(cone_b.cells.begin(), cone_b.cells.end());
if (verbose)
{
log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b),
(GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells));
#if 0
for (auto cell : short_cells_cone_a)
log(" A-side cell: %s\n", log_id(cell));
if (cfg.verbose)
report_new_cells(problem_cells, cone_a, cone_b);
for (auto cell : short_cells_cone_b)
log(" B-side cell: %s\n", log_id(cell));
#endif
if (cfg.set_assumes) {
auto extras = add_assumes_to_problem(cone_a, cone_b);
if (GetSize(extras)) {
auto old_size = GetSize(problem_cells);
problem_cells.insert(extras.begin(), extras.end());
report_new_assume_cells(extras, old_size, problem_cells);
}
}
for (auto cell : problem_cells) {
auto key = pair<Cell*, int>(cell, step+1);
if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1)) {
if (RTLIL::builtin_ff_cell_types().count(cell->type))
log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
else
log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
report_missing_model(cell);
}
imported_cells_cache.insert(key);
}
if (satgen.model_undef) {
for (auto bit : input_bits)
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
}
if (verbose)
log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
construct_ezsat(input_bits, step);
if (!ez->solve(ez_context)) {
log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
equiv_cell->setPort(ID::B, equiv_cell->getPort(ID::A));
log(cfg.verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
// Replace $equiv cell with a short
cell->setPort(ID::B, cell->getPort(ID::A));
ez->assume(ez->NOT(ez_context));
return true;
}
if (verbose)
log(" Failed to prove equivalence with sequence length %d.\n", max_seq - step);
if (cfg.verbose)
log(" Failed to prove equivalence with sequence length %d.\n", cfg.max_seq - step);
if (--step < 0) {
if (verbose)
if (cfg.verbose)
log(" Reached sequence limit.\n");
break;
}
if (seed_a.empty() && seed_b.empty()) {
if (verbose)
if (cfg.verbose)
log(" No nets to continue in previous time step.\n");
break;
}
if (seed_a.empty()) {
if (verbose)
if (cfg.verbose)
log(" No nets on A-side to continue in previous time step.\n");
break;
}
if (seed_b.empty()) {
if (verbose)
if (cfg.verbose)
log(" No nets on B-side to continue in previous time step.\n");
break;
}
if (verbose) {
if (cfg.verbose) {
#if 0
log(" Continuing analysis in previous time step with the following nets:\n");
for (auto bit : seed_a)
@ -248,7 +378,7 @@ struct EquivSimpleWorker
}
}
if (!verbose)
if (!cfg.verbose)
log(" failed.\n");
ez->assume(ez->NOT(ez_context));
@ -260,14 +390,13 @@ struct EquivSimpleWorker
if (GetSize(equiv_cells) > 1) {
SigSpec sig;
for (auto c : equiv_cells)
sig.append(sigmap(c->getPort(ID::Y)));
sig.append(model.sigmap(c->getPort(ID::Y)));
log(" Grouping SAT models for %s:\n", log_signal(sig));
}
int counter = 0;
for (auto c : equiv_cells) {
equiv_cell = c;
if (run_cell())
if (prove_equiv_cell(c))
counter++;
}
return counter;
@ -301,35 +430,41 @@ struct EquivSimplePass : public Pass {
log(" -seq <N>\n");
log(" the max. number of time steps to be considered (default = 1)\n");
log("\n");
log(" -set-assumes\n");
log(" set all assumptions provided via $assume cells\n");
log("\n");
}
void execute(std::vector<std::string> args, Design *design) override
{
bool verbose = false, short_cones = false, model_undef = false, nogroup = false;
EquivSimpleWorker::Config cfg = {};
int success_counter = 0;
int max_seq = 1;
log_header(design, "Executing EQUIV_SIMPLE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-v") {
verbose = true;
cfg.verbose = true;
continue;
}
if (args[argidx] == "-short") {
short_cones = true;
cfg.short_cones = true;
continue;
}
if (args[argidx] == "-undef") {
model_undef = true;
cfg.model_undef = true;
continue;
}
if (args[argidx] == "-nogroup") {
nogroup = true;
cfg.nogroup = true;
continue;
}
if (args[argidx] == "-seq" && argidx+1 < args.size()) {
max_seq = atoi(args[++argidx].c_str());
cfg.max_seq = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-set-assumes") {
cfg.set_assumes = true;
continue;
}
break;
@ -347,17 +482,21 @@ struct EquivSimplePass : public Pass {
SigMap sigmap(module);
dict<SigBit, Cell*> bit2driver;
dict<SigBit, dict<SigBit, Cell*>> unproven_equiv_cells;
vector<Cell*> assumes;
int unproven_cells_counter = 0;
for (auto cell : module->selected_cells())
for (auto cell : module->selected_cells()) {
if (cell->type == ID($equiv) && cell->getPort(ID::A) != cell->getPort(ID::B)) {
auto bit = sigmap(cell->getPort(ID::Y).as_bit());
auto bit_group = bit;
if (!nogroup && bit_group.wire)
if (!cfg.nogroup && bit_group.wire)
bit_group.offset = 0;
unproven_equiv_cells[bit_group][bit] = cell;
unproven_cells_counter++;
} else if (cell->type == ID($assume)) {
assumes.push_back(cell);
}
}
if (unproven_equiv_cells.empty())
continue;
@ -375,15 +514,16 @@ struct EquivSimplePass : public Pass {
}
unproven_equiv_cells.sort();
for (auto it : unproven_equiv_cells)
for (auto [_, d] : unproven_equiv_cells)
{
it.second.sort();
d.sort();
vector<Cell*> cells;
for (auto it2 : it.second)
cells.push_back(it2.second);
for (auto [_, cell] : d)
cells.push_back(cell);
EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef);
EquivSimpleWorker::DesignModel model {sigmap, bit2driver};
EquivSimpleWorker worker(cells, assumes, model, cfg);
success_counter += worker.run();
}
}

View file

@ -100,7 +100,7 @@ enum class WrTransKind {
struct WrTransDef {
WrTransTargetKind target_kind;
int target_group;
int target_group = 0;
WrTransKind kind;
};

View file

@ -199,7 +199,7 @@ struct OptDffWorker
const auto complimentary_var = find_comp(left, right);
if (complimentary_var) {
if (complimentary_var && new_patterns.count(right)) {
new_patterns.erase(right);
right.erase(complimentary_var.value());
new_patterns.insert(right);

View file

@ -44,20 +44,16 @@ struct OptMergeWorker
CellTypes ct;
int total_count;
static vector<pair<SigBit, SigSpec>> sorted_pmux_in(const dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h)
{
SigSpec sig_s = conn.at(ID::S);
SigSpec sig_b = conn.at(ID::B);
int s_width = GetSize(sig_s);
int width = GetSize(sig_b) / s_width;
vector<pair<SigBit, SigSpec>> sb_pairs;
hashlib::commutative_hash comm;
for (int i = 0; i < s_width; i++)
sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
comm.eat(hash_ops<std::pair<SigBit, SigSpec>>::hash({sig_s[i], sig_b.extract(i*width, width)}));
std::sort(sb_pairs.begin(), sb_pairs.end());
return sb_pairs;
return comm.hash_into(h);
}
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
@ -89,12 +85,10 @@ struct OptMergeWorker
// (builtin || stdcell) && (unary || binary) && symmetrical
if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
std::array<RTLIL::SigSpec, 2> inputs = {
assign_map(cell->getPort(ID::A)),
assign_map(cell->getPort(ID::B))
};
std::sort(inputs.begin(), inputs.end());
h = hash_ops<std::array<RTLIL::SigSpec, 2>>::hash_into(inputs, h);
hashlib::commutative_hash comm;
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::A))));
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::B))));
h = comm.hash_into(h);
} else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
SigSpec a = assign_map(cell->getPort(ID::A));
a.sort();
@ -104,44 +98,31 @@ struct OptMergeWorker
a.sort_and_unify();
h = a.hash_into(h);
} else if (cell->type == ID($pmux)) {
dict<RTLIL::IdString, RTLIL::SigSpec> conn = cell->connections();
assign_map.apply(conn.at(ID::A));
assign_map.apply(conn.at(ID::B));
assign_map.apply(conn.at(ID::S));
for (const auto& [s_bit, b_chunk] : sorted_pmux_in(conn)) {
h = s_bit.hash_into(h);
h = b_chunk.hash_into(h);
}
SigSpec sig_s = assign_map(cell->getPort(ID::S));
SigSpec sig_b = assign_map(cell->getPort(ID::B));
h = hash_pmux_in(sig_s, sig_b, h);
h = assign_map(cell->getPort(ID::A)).hash_into(h);
} else {
std::vector<std::pair<IdString, SigSpec>> conns;
for (const auto& conn : cell->connections()) {
conns.push_back(conn);
hashlib::commutative_hash comm;
for (const auto& [port, sig] : cell->connections()) {
if (cell->output(port))
continue;
comm.eat(hash_ops<std::pair<IdString, SigSpec>>::hash({port, assign_map(sig)}));
}
std::sort(conns.begin(), conns.end());
for (const auto& [port, sig] : conns) {
if (!cell->output(port)) {
h = port.hash_into(h);
h = assign_map(sig).hash_into(h);
}
}
h = comm.hash_into(h);
if (RTLIL::builtin_ff_cell_types().count(cell->type))
h = initvals(cell->getPort(ID::Q)).hash_into(h);
}
return h;
}
static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h)
{
using Paramvec = std::vector<std::pair<IdString, Const>>;
Paramvec params;
hashlib::commutative_hash comm;
for (const auto& param : cell->parameters) {
params.push_back(param);
comm.eat(hash_ops<std::pair<IdString, Const>>::hash(param));
}
std::sort(params.begin(), params.end());
return hash_ops<Paramvec>::hash_into(params, h);
return comm.hash_into(h);
}
Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const
@ -227,7 +208,7 @@ struct OptMergeWorker
}
OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) :
design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
design(design), module(module), mode_share_all(mode_share_all)
{
total_count = 0;
ct.setup_internals();

View file

@ -23,12 +23,40 @@
#include "kernel/celltypes.h"
#include <stdlib.h>
#include <stdio.h>
#include <unordered_map>
#include <unordered_set>
#include <set>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
using RTLIL::id2cstr;
/**
* TERMINOLOGY
*
* A multiplexer tree (mux tree) is a tree composed exclusively of muxes.
* By mux, I mean $mux or $pmux. By port, I usually mean input port.
* The children of a node are all the muxes driving its input ports (A, B).
* It must be rooted in a "root mux", a mux which has multiple mux users
* or any number of non-mux users. Only the root and leaf nodes can be
* root muxes, not the internal nodes. Leaf nodes that are root muxes
* are roots of "input trees".
*
* OPERATING PRINCIPLE
*
* This pass traverses mux trees, learning port activations and making
* assumptions about them as it goes. When valid, ports are replaced
* with constants, or removed if they can never be activated.
* When valid, muxes are replaced with shorts from port to output,
* or removed if their outputs are found to be no longer observable.
*
* Input trees can be recursed into if limits_t::recursions_left allows.
* Otherwise, the input tree is queued for a re-run with a fresh knowledge_t.
* At any point, if glob_evals_left goes to 0, the pass terminates.
*
* Unlike share, this pass doesn't use SAT to learn things about logic
* driving the mux control signals, and traverses mux regions from users
* to drivers.
*/
struct OptMuxtreeWorker
{
@ -36,9 +64,10 @@ struct OptMuxtreeWorker
RTLIL::Module *module;
SigMap assign_map;
int removed_count;
int glob_abort_cnt = 100000;
int glob_evals_left = 100000;
struct bitinfo_t {
// Is bit directly used by non-mux cells or ports?
bool seen_non_mux;
pool<int> mux_users;
pool<int> mux_drivers;
@ -48,12 +77,13 @@ struct OptMuxtreeWorker
vector<bitinfo_t> bit2info;
struct portinfo_t {
int ctrl_sig;
pool<int> input_sigs;
pool<int> input_muxes;
bool const_activated;
bool const_deactivated;
bool enabled;
int ctrl_sig = -1; // No associated control signal by default
pool<int> input_sigs = {};
pool<int> input_muxes = {};
bool const_activated = false;
bool const_deactivated = false;
// Is the port reachable from inputs of a mux tree?
bool observable = false;
};
struct muxinfo_t {
@ -66,13 +96,16 @@ struct OptMuxtreeWorker
vector<bool> root_enable_muxes;
pool<int> root_mux_rerun;
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
{
log("Running muxtree optimizer on module %s..\n", module->name.c_str());
log(" Creating internal representation of mux trees.\n");
portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx) {
portinfo_t portinfo = {};
for (int bit_idx : sig2bits(sig)) {
bit2info[bit_idx].mux_users.insert(mux_idx);
portinfo.input_sigs.insert(bit_idx);
}
return portinfo;
}
void track_mux(Cell* cell) {
// Populate bit2info[]:
// .seen_non_mux
// .mux_users
@ -82,73 +115,59 @@ struct OptMuxtreeWorker
// .input_sigs
// .const_activated
// .const_deactivated
for (auto cell : module->cells())
{
if (cell->type.in(ID($mux), ID($pmux)))
{
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
RTLIL::SigSpec sig_s = cell->getPort(ID::S);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
RTLIL::SigSpec sig_s = cell->getPort(ID::S);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
muxinfo_t muxinfo;
muxinfo.cell = cell;
muxinfo_t muxinfo;
muxinfo.cell = cell;
int this_mux_idx = GetSize(mux2info);
for (int i = 0; i < GetSize(sig_s); i++) {
RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo;
portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
for (int idx : sig2bits(sig)) {
bit2info[idx].mux_users.insert(GetSize(mux2info));
portinfo.input_sigs.insert(idx);
}
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
}
portinfo_t portinfo;
for (int idx : sig2bits(sig_a)) {
bit2info[idx].mux_users.insert(GetSize(mux2info));
portinfo.input_sigs.insert(idx);
}
portinfo.ctrl_sig = -1;
portinfo.const_activated = false;
portinfo.const_deactivated = false;
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
for (int idx : sig2bits(sig_y))
bit2info[idx].mux_drivers.insert(GetSize(mux2info));
for (int idx : sig2bits(sig_s))
bit2info[idx].seen_non_mux = true;
mux2info.push_back(muxinfo);
}
else
{
for (auto &it : cell->connections()) {
for (int idx : sig2bits(it.second))
bit2info[idx].seen_non_mux = true;
}
}
// Analyze port B
// In case of $pmux, port B is multiple slices, concatenated, one per bit of port S
for (int i = 0; i < GetSize(sig_s); i++) {
RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo = used_port_bit(sig, this_mux_idx);
portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
muxinfo.ports.push_back(portinfo);
}
// Analyze port A
muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx));
for (int idx : sig2bits(sig_y))
bit2info[idx].mux_drivers.insert(this_mux_idx);
for (int idx : sig2bits(sig_s))
bit2info[idx].seen_non_mux = true;
mux2info.push_back(muxinfo);
}
void see_non_mux_cell(Cell* cell) {
for (auto &it : cell->connections()) {
for (int idx : sig2bits(it.second))
bit2info[idx].seen_non_mux = true;
}
}
void see_non_mux_wires() {
for (auto wire : module->wires()) {
if (wire->port_output || wire->get_bool_attribute(ID::keep))
for (int idx : sig2bits(RTLIL::SigSpec(wire)))
bit2info[idx].seen_non_mux = true;
}
}
if (mux2info.empty()) {
log(" No muxes found in this module.\n");
return;
}
// Populate mux2info[].ports[]:
// .input_muxes
// Populate mux2info[].ports[]:
// .input_muxes
void fixup_input_muxes() {
// bit2info knows the mux users and mux drivers of bits
// use this to tell mux2info ports about what muxes are driven by it
for (int i = 0; i < GetSize(bit2info); i++)
for (int j : bit2info[i].mux_users)
for (auto &p : mux2info[j].ports) {
@ -156,12 +175,15 @@ struct OptMuxtreeWorker
for (int k : bit2info[i].mux_drivers)
p.input_muxes.insert(k);
}
}
log(" Evaluating internal representation of mux trees.\n");
void populate_roots() {
// mux_to_users[i] means "set of muxes using output of mux i"
dict<int, pool<int>> mux_to_users;
root_muxes.resize(GetSize(mux2info));
// Pure root muxes (outputs seen by non-muxes)
root_enable_muxes.resize(GetSize(mux2info));
// All root muxes (outputs seen by non-muxes or multiple muxes)
root_muxes.resize(GetSize(mux2info));
for (auto &bi : bit2info) {
for (int i : bi.mux_drivers)
@ -175,16 +197,44 @@ struct OptMuxtreeWorker
}
}
for (auto &it : mux_to_users)
if (GetSize(it.second) > 1)
root_muxes.at(it.first) = true;
for (auto &[driving_mux, user_muxes] : mux_to_users)
if (GetSize(user_muxes) > 1)
root_muxes.at(driving_mux) = true;
}
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
{
log("Running muxtree optimizer on module %s..\n", module->name.c_str());
log(" Creating internal representation of mux trees.\n");
for (auto cell : module->cells())
{
if (cell->type.in(ID($mux), ID($pmux)))
track_mux(cell);
else
see_non_mux_cell(cell);
}
see_non_mux_wires();
if (mux2info.empty()) {
log(" No muxes found in this module.\n");
return;
}
fixup_input_muxes();
log(" Evaluating internal representation of mux trees.\n");
populate_roots();
for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
if (root_muxes.at(mux_idx)) {
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
if (glob_evals_left == 0) {
log(" Giving up (too many iterations)\n");
return;
}
@ -196,21 +246,21 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
if (glob_evals_left == 0) {
log(" Giving up (too many iterations)\n");
return;
}
}
log(" Analyzing evaluation results.\n");
log_assert(glob_abort_cnt > 0);
log_assert(glob_evals_left > 0);
for (auto &mi : mux2info)
{
vector<int> live_ports;
for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) {
portinfo_t &pi = mi.ports[port_idx];
if (pi.enabled) {
if (pi.observable) {
live_ports.push_back(port_idx);
} else {
log(" dead port %d/%d on %s %s.\n", port_idx+1, GetSize(mi.ports),
@ -288,73 +338,125 @@ struct OptMuxtreeWorker
struct knowledge_t
{
// database of known inactive signals
// the payload is a reference counter used to manage the
// list. when it is non-zero the signal in known to be inactive
vector<int> known_inactive;
// Known inactive signals
// The payload is a reference counter used to manage the list
// When it is non-zero, the signal in known to be inactive
// When it reaches zero, the map element is removed
std::unordered_map<int, int> known_inactive;
// database of known active signals
vector<int> known_active;
std::unordered_map<int, int> known_active;
// this is just used to keep track of visited muxes in order to prohibit
// endless recursion in mux loops
vector<bool> visited_muxes;
std::unordered_set<int> visited_muxes;
};
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
static void activate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) {
// First, mark all other ports inactive
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
if (i == port_idx)
continue;
if (muxinfo.ports[i].ctrl_sig >= 0)
++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig];
}
// Mark port active unless it's the last one
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig];
}
static void deactivate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) {
auto unlearn = [](std::unordered_map<int, int>& knowns, int i) {
auto it = knowns.find(i);
if (it != knowns.end())
if (--it->second == 0)
knowns.erase(it);
};
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
unlearn(knowledge.known_active, muxinfo.ports[port_idx].ctrl_sig);
// Undo inactivity assumptions for other ports
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
if (i == port_idx)
continue;
if (muxinfo.ports[i].ctrl_sig >= 0)
unlearn(knowledge.known_inactive, muxinfo.ports[i].ctrl_sig);
}
}
struct limits_t {
// Are we allowed to replace inputs with constants?
// True if knowledge doesn't contain assumptions
bool do_replace_known = true;
// Are we allowed to mark ports as observable?
// True if we're recursing from a pure root mux
bool do_mark_ports_observable = true;
// How many more subtree recursions into input trees can we take?
// Then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three.
int recursions_left = 3;
limits_t subtree() const {
limits_t ret = *this;
log_assert(ret.recursions_left > 0);
ret.recursions_left--;
return ret;
}
};
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, limits_t limits)
{
if (glob_abort_cnt == 0)
if (glob_evals_left == 0)
return;
muxinfo_t &muxinfo = mux2info[mux_idx];
if (do_enable_ports)
muxinfo.ports[port_idx].enabled = true;
if (limits.do_mark_ports_observable)
muxinfo.ports[port_idx].observable = true;
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
if (i == port_idx)
continue;
if (muxinfo.ports[i].ctrl_sig >= 0)
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
}
// For the purposes of recursion, we assume the port is active,
// meaning all other ports are inactive
activate_port(knowledge, port_idx, muxinfo);
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
vector<int> parent_muxes;
vector<int> input_mux_queue;
for (int m : muxinfo.ports[port_idx].input_muxes) {
if (knowledge.visited_muxes[m])
if (knowledge.visited_muxes.count(m))
continue;
knowledge.visited_muxes[m] = true;
parent_muxes.push_back(m);
knowledge.visited_muxes.insert(m);
input_mux_queue.push_back(m);
}
for (int m : parent_muxes) {
for (int m : input_mux_queue) {
if (root_enable_muxes.at(m))
continue;
else if (root_muxes.at(m)) {
if (abort_count == 0) {
// This leaf node of the current tree
// is the root of an input tree of the current tree
if (limits.recursions_left == 0) {
// Ran out of subtree depth, re-eval this input tree in the next re-run
root_mux_rerun.insert(m);
root_enable_muxes.at(m) = true;
log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
} else
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else
eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
if (glob_abort_cnt == 0)
} else {
auto new_limits = limits.subtree();
// Since our knowledge includes assumption,
// we can't generally allow replacing in an input tree based on it
new_limits.do_replace_known = false;
eval_mux(knowledge, m, new_limits);
}
} else {
// This non-root input mux has only this mux as a user,
// so here we are allowed to pass along do_replace_known
eval_mux(knowledge, m, limits);
}
if (glob_evals_left == 0)
return;
}
for (int m : parent_muxes)
knowledge.visited_muxes[m] = false;
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
// Allow revisiting input muxes, since evaluating other ports should
// revisit these input muxes with different activation assumptions
for (int m : input_mux_queue)
knowledge.visited_muxes.erase(m);
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
if (i == port_idx)
continue;
if (muxinfo.ports[i].ctrl_sig >= 0)
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--;
}
// Undo our assumptions that the port is active
deactivate_port(knowledge, port_idx, muxinfo);
}
void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname)
@ -362,37 +464,51 @@ struct OptMuxtreeWorker
SigSpec sig = muxinfo.cell->getPort(portname);
bool did_something = false;
int width = 0;
int width_if_b = 0;
idict<int> ctrl_bits;
if (portname == ID::B)
width = GetSize(muxinfo.cell->getPort(ID::A));
width_if_b = GetSize(muxinfo.cell->getPort(ID::A));
for (int bit : sig2bits(muxinfo.cell->getPort(ID::S), false))
ctrl_bits(bit);
int port_idx = 0, port_off = 0;
int slice_idx = 0, slice_off = 0;
vector<int> bits = sig2bits(sig, false);
for (int i = 0; i < GetSize(bits); i++) {
if (bits[i] >= 0) {
if (knowledge.known_inactive.at(bits[i])) {
if (knowledge.known_inactive.count(bits[i]) > 0) {
sig[i] = State::S0;
did_something = true;
} else
if (knowledge.known_active.at(bits[i])) {
if (knowledge.known_active.count(bits[i]) > 0) {
sig[i] = State::S1;
did_something = true;
}
if (ctrl_bits.count(bits[i])) {
if (width) {
sig[i] = ctrl_bits.at(bits[i]) == port_idx ? State::S1 : State::S0;
} else {
if (!width_if_b) {
// Single-bit $mux example
// mux: S ? B : A = Y
// A=S
// 0 ? B : 0 = 0
// 1 ? B : 1 = B
// rewrite to A=0
// 0 ? B : 0 = 0
// 1 ? B : 0 = B
// which is equivalent
sig[i] = State::S0;
} else {
// "Sliced" $pmux example
// B[i]=S[j]
// i == j => B[i] activated only when B[i] is high, safe to rewrite to 1
// i != j => B[i] activated only when B[i] is low, safe to rewrite to 0
sig[i] = ctrl_bits.at(bits[i]) == slice_idx ? State::S1 : State::S0;
}
did_something = true;
}
}
if (width) {
if (++port_off == width)
port_idx++, port_off=0;
if (width_if_b) {
// Roll over into next slice
if (++slice_off == width_if_b)
slice_idx++, slice_off=0;
}
}
@ -403,16 +519,17 @@ struct OptMuxtreeWorker
}
}
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
void eval_mux(knowledge_t &knowledge, int mux_idx, limits_t limits)
{
if (glob_abort_cnt == 0)
if (glob_evals_left == 0)
return;
glob_abort_cnt--;
glob_evals_left--;
muxinfo_t &muxinfo = mux2info[mux_idx];
log_debug("\t\teval %s (replace %d enable %d)\n", log_id(muxinfo.cell), limits.do_replace_known, limits.do_mark_ports_observable);
// set input ports to constants if we find known active or inactive signals
if (do_replace_known) {
if (limits.do_replace_known) {
replace_known(knowledge, muxinfo, ID::A);
replace_known(knowledge, muxinfo, ID::B);
}
@ -422,21 +539,21 @@ struct OptMuxtreeWorker
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
if (portinfo.const_activated) {
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
eval_mux_port(knowledge, mux_idx, port_idx, limits);
return;
}
}
// compare ports with known_active signals. if we find a match, only this
// port can be active. do not include the last port (its the default port
// that has no control signals).
// Compare ports with known active control signals. if we find a match,
// only this port can be active. Do not include the last port,
// it's the default port without an associated control signal
for (int port_idx = 0; port_idx < GetSize(muxinfo.ports)-1; port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
if (portinfo.const_deactivated)
continue;
if (knowledge.known_active.at(portinfo.ctrl_sig)) {
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) {
eval_mux_port(knowledge, mux_idx, port_idx, limits);
return;
}
}
@ -449,24 +566,23 @@ struct OptMuxtreeWorker
if (portinfo.const_deactivated)
continue;
if (port_idx < GetSize(muxinfo.ports)-1)
if (knowledge.known_inactive.at(portinfo.ctrl_sig))
if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0)
continue;
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
eval_mux_port(knowledge, mux_idx, port_idx, limits);
if (glob_abort_cnt == 0)
if (glob_evals_left == 0)
return;
}
}
void eval_root_mux(int mux_idx)
{
log_assert(glob_abort_cnt > 0);
log_assert(glob_evals_left > 0);
knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info));
knowledge.visited_muxes.resize(GetSize(mux2info));
knowledge.visited_muxes[mux_idx] = true;
eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
knowledge.visited_muxes.insert(mux_idx);
limits_t limits = {};
limits.do_mark_ports_observable = root_enable_muxes.at(mux_idx);
eval_mux(knowledge, mux_idx, limits);
}
};

File diff suppressed because it is too large Load diff

View file

@ -71,6 +71,29 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
cell->setPort(ID::Y, wire);
}
if (cell_type.in(ID($_MUX_), ID($_NMUX_)))
{
wire = module->addWire(ID::A);
wire->width = 1;
wire->port_input = true;
cell->setPort(ID::A, wire);
wire = module->addWire(ID::B);
wire->width = 1;
wire->port_input = true;
cell->setPort(ID::B, wire);
wire = module->addWire(ID::S);
wire->width = 1;
wire->port_input = true;
cell->setPort(ID::S, wire);
wire = module->addWire(ID::Y);
wire->width = 1;
wire->port_output = true;
cell->setPort(ID::Y, wire);
}
if (cell_type == ID($bmux))
{
int width = 1 + xorshift32(8 * bloat_factor);
@ -167,7 +190,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
cell->setPort(ID::CO, wire);
}
if (cell_type == ID($macc))
if (cell_type == ID($macc_v2))
{
Macc macc;
int width = 1 + xorshift32(8 * bloat_factor);
@ -201,6 +224,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
this_term.do_subtract = xorshift32(2) == 1;
macc.terms.push_back(this_term);
}
// Macc::to_cell sets the input ports
macc.to_cell(cell);
@ -208,12 +232,6 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
wire->width = width;
wire->port_output = true;
cell->setPort(ID::Y, wire);
// override the B input (macc helpers always sets an empty vector)
wire = module->addWire(ID::B);
wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
wire->port_input = true;
cell->setPort(ID::B, wire);
}
if (cell_type == ID($lut))
@ -273,14 +291,19 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
if (cell_type_flags.find('A') != std::string::npos) {
wire = module->addWire(ID::A);
wire->width = 1 + xorshift32(8 * bloat_factor);
if (cell_type_flags.find('b') != std::string::npos)
wire->width = 1;
else
wire->width = 1 + xorshift32(8 * bloat_factor);
wire->port_input = true;
cell->setPort(ID::A, wire);
}
if (cell_type_flags.find('B') != std::string::npos) {
wire = module->addWire(ID::B);
if (cell_type_flags.find('h') != std::string::npos)
if (cell_type_flags.find('b') != std::string::npos)
wire->width = 1;
else if (cell_type_flags.find('h') != std::string::npos)
wire->width = 1 + xorshift32(6 * bloat_factor);
else
wire->width = 1 + xorshift32(8 * bloat_factor);
@ -288,6 +311,26 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
cell->setPort(ID::B, wire);
}
if (cell_type_flags.find('C') != std::string::npos) {
wire = module->addWire(ID::C);
if (cell_type_flags.find('b') != std::string::npos)
wire->width = 1;
else
wire->width = 1 + xorshift32(8 * bloat_factor);
wire->port_input = true;
cell->setPort(ID::C, wire);
}
if (cell_type_flags.find('D') != std::string::npos) {
wire = module->addWire(ID::D);
if (cell_type_flags.find('b') != std::string::npos)
wire->width = 1;
else
wire->width = 1 + xorshift32(8 * bloat_factor);
wire->port_input = true;
cell->setPort(ID::D, wire);
}
if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
if (cell_type_flags.find('A') != std::string::npos)
cell->parameters[ID::A_SIGNED] = true;
@ -304,7 +347,10 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
if (cell_type_flags.find('Y') != std::string::npos) {
wire = module->addWire(ID::Y);
wire->width = 1 + xorshift32(8 * bloat_factor);
if (cell_type_flags.find('b') != std::string::npos)
wire->width = 1;
else
wire->width = 1 + xorshift32(8 * bloat_factor);
wire->port_output = true;
cell->setPort(ID::Y, wire);
}
@ -345,6 +391,58 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
cell->setPort(ID::CO, wire);
}
if (cell_type == ID($slice))
{
int a_size = GetSize(cell->getPort(ID::A));
int y_size = 1;
if (a_size > 1)
y_size += (xorshift32(8 * bloat_factor) % (a_size - 1));
wire = module->addWire(ID::Y);
wire->width = y_size;
wire->port_output = true;
cell->setPort(ID::Y, wire);
if (a_size > y_size)
cell->setParam(ID::OFFSET, (xorshift32(8 * bloat_factor) % (a_size - y_size)));
else
cell->setParam(ID::OFFSET, 0);
}
if (cell_type == ID($concat))
{
wire = module->addWire(ID::Y);
wire->width = GetSize(cell->getPort(ID::A)) + GetSize(cell->getPort(ID::B));
wire->port_output = true;
cell->setPort(ID::Y, wire);
}
if (cell_type == ID($buf))
{
wire = module->addWire(ID::Y);
wire->width = GetSize(cell->getPort(ID::A));
wire->port_output = true;
cell->setPort(ID::Y, wire);
}
if (cell_type.in(ID($bwmux), ID($bweqx)))
{
int a_size = GetSize(cell->getPort(ID::A));
wire = module->addWire(ID::B);
wire->width = a_size;
wire->port_input = true;
cell->setPort(ID::B, wire);
if (cell_type == ID($bwmux))
{
wire = module->addWire(ID::S);
wire->width = a_size;
wire->port_input = true;
cell->setPort(ID::S, wire);
}
wire = module->addWire(ID::Y);
wire->width = a_size;
wire->port_output = true;
cell->setPort(ID::Y, wire);
}
if (constmode)
{
auto conn_list = cell->connections();
@ -884,6 +982,9 @@ struct TestCellPass : public Pass {
cell_types[ID($not)] = "ASY";
cell_types[ID($pos)] = "ASY";
cell_types[ID($neg)] = "ASY";
// $buf is unsupported with techmap -assert
if (techmap_cmd.compare("techmap -assert") != 0)
cell_types[ID($buf)] = "A";
cell_types[ID($and)] = "ABSY";
cell_types[ID($or)] = "ABSY";
@ -907,8 +1008,14 @@ struct TestCellPass : public Pass {
cell_types[ID($le)] = "ABSY";
cell_types[ID($eq)] = "ABSY";
cell_types[ID($ne)] = "ABSY";
// cell_types[ID($eqx)] = "ABSY";
// cell_types[ID($nex)] = "ABSY";
// $eqx, $nex, and $bweqx don't work in sat, and are unsupported with
// 'techmap -assert'
if (nosat && techmap_cmd.compare("techmap -assert") != 0)
{
cell_types[ID($eqx)] = "ABSY";
cell_types[ID($nex)] = "ABSY";
cell_types[ID($bweqx)] = "A";
}
cell_types[ID($ge)] = "ABSY";
cell_types[ID($gt)] = "ABSY";
@ -919,7 +1026,10 @@ struct TestCellPass : public Pass {
cell_types[ID($mod)] = "ABSY";
cell_types[ID($divfloor)] = "ABSY";
cell_types[ID($modfloor)] = "ABSY";
// cell_types[ID($pow)] = "ABsY";
// $pow doesnt work in sat, not supported with 'techmap -assert', and only
// only partially supported with '-simlib'
if (nosat && techmap_cmd.compare("aigmap") == 0)
cell_types[ID($pow)] = "ABsY";
cell_types[ID($logic_not)] = "ASY";
cell_types[ID($logic_and)] = "ABSY";
@ -928,20 +1038,43 @@ struct TestCellPass : public Pass {
cell_types[ID($mux)] = "*";
cell_types[ID($bmux)] = "*";
cell_types[ID($demux)] = "*";
if (edges) {
// $pmux doesn't work in sat, and is not supported with 'techmap -assert' or
// '-simlib'
if (nosat && techmap_cmd.compare("aigmap") == 0)
cell_types[ID($pmux)] = "*";
}
cell_types[ID($bwmux)] = "A";
// cell_types[ID($slice)] = "A";
// cell_types[ID($concat)] = "A";
cell_types[ID($slice)] = "A";
cell_types[ID($concat)] = "AB";
cell_types[ID($lut)] = "*";
cell_types[ID($sop)] = "*";
cell_types[ID($alu)] = "ABSY";
cell_types[ID($lcu)] = "*";
cell_types[ID($macc)] = "*";
cell_types[ID($macc_v2)] = "*";
cell_types[ID($fa)] = "*";
cell_types[ID($_BUF_)] = "AYb";
cell_types[ID($_NOT_)] = "AYb";
cell_types[ID($_AND_)] = "ABYb";
cell_types[ID($_NAND_)] = "ABYb";
cell_types[ID($_OR_)] = "ABYb";
cell_types[ID($_NOR_)] = "ABYb";
cell_types[ID($_XOR_)] = "ABYb";
cell_types[ID($_XNOR_)] = "ABYb";
cell_types[ID($_ANDNOT_)] = "ABYb";
cell_types[ID($_ORNOT_)] = "ABYb";
cell_types[ID($_MUX_)] = "*";
cell_types[ID($_NMUX_)] = "*";
// wide $_MUX_ cells are not yet implemented
// cell_types[ID($_MUX4_)] = "*";
// cell_types[ID($_MUX8_)] = "*";
// cell_types[ID($_MUX16_)] = "*";
cell_types[ID($_AOI3_)] = "ABCYb";
cell_types[ID($_OAI3_)] = "ABCYb";
cell_types[ID($_AOI4_)] = "ABCDYb";
cell_types[ID($_OAI4_)] = "ABCDYb";
for (; argidx < GetSize(args); argidx++)
{
if (args[argidx].rfind("-", 0) == 0)

View file

@ -51,16 +51,27 @@ class libyosys_so_ext(Extension):
]
def custom_build(self, bext: build_ext):
make_flags_split = shlex.split(os.getenv("makeFlags", ""))
# abc linking takes a lot of memory, best get it out of the way first
bext.spawn(
[
"make",
f"-j{os.cpu_count() or 1}",
"yosys-abc",
*make_flags_split,
*self.args,
]
)
# build libyosys and share with abc out of the way
bext.spawn(
[
"make",
f"-j{os.cpu_count() or 1}",
self.name,
"yosys-abc",
"share",
*make_flags_split,
*self.args,
]
+ shlex.split(os.getenv("makeFlags", ""))
+ self.args
)
build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name)))
pyosys_path = os.path.join(build_path, "pyosys")
@ -85,6 +96,7 @@ class libyosys_so_ext(Extension):
shutil.copytree("share", share_target)
class custom_build_ext(build_ext):
def build_extension(self, ext) -> None:
if not hasattr(ext, "custom_build"):
@ -100,8 +112,8 @@ setup(
long_description=open(os.path.join(__dir__, "README.md")).read(),
long_description_content_type="text/markdown",
install_requires=["wheel", "setuptools"],
license="MIT",
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Intended Audience :: Developers",
"Operating System :: POSIX :: Linux",

View file

@ -19,6 +19,8 @@ endmodule
(* blackbox *)
module DP16KD (...);
parameter CLKAMUX = "CLKA";
parameter CLKBMUX = "CLKB";
parameter DATA_WIDTH_A = 18;
parameter DATA_WIDTH_B = 18;
parameter REGMODE_A = "NOREG";
@ -215,6 +217,8 @@ endmodule
(* blackbox *)
module PDPW16KD (...);
parameter CLKRMUX = "CLKR";
parameter CLKWMUX = "CLKW";
parameter DATA_WIDTH_W = 36;
parameter DATA_WIDTH_R = 36;
parameter GSR = "ENABLED";

View file

@ -11,10 +11,11 @@ import re
class Cell:
def __init__(self, name, keep=False, port_attrs={}):
def __init__(self, name, keep=False, port_attrs={}, extra_params={}):
self.name = name
self.keep = keep
self.port_attrs = port_attrs
self.extra_params = extra_params
self.found = False
class State(Enum):
@ -120,8 +121,18 @@ devices = [
#Cell("XOR3"),
#Cell("XOR4"),
#Cell("XOR5"),
Cell("DP16KD"),
Cell("PDPW16KD"),
Cell("DP16KD", extra_params={
# Optional clock inverters, present in prjtrellis data but
# not in Diamond bb models.
"CLKAMUX": "CLKA",
"CLKBMUX": "CLKB",
}),
Cell("PDPW16KD", extra_params={
# Optional clock inverters, present in prjtrellis data but
# not in Diamond bb models.
"CLKWMUX": "CLKW",
"CLKRMUX": "CLKR",
}),
#Cell("DPR16X4C"),
#Cell("SPR16X4C"),
#Cell("LVDSOB"),
@ -795,6 +806,10 @@ def xtract_cells_decl(device, cells, dirs, outf):
rng = None
module_ports.append((kind, rng, port))
elif l.startswith('parameter ') and state == State.IN_MODULE:
if cell.extra_params:
for name, default in sorted(cell.extra_params.items()):
outf.write(' parameter {} = "{}";\n'.format(name, default))
cell.extra_params = None
l = l.strip()
if l.endswith((';', ',')):
l = l[:-1]

View file

@ -78,7 +78,7 @@ struct SynthQuickLogicPass : public ScriptPass {
}
string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path;
bool abc9, inferAdder, nobram, bramTypes, dsp, ioff;
bool abc9, inferAdder, nobram, bramTypes, dsp, ioff, flatten;
void clear_flags() override
{
@ -95,6 +95,7 @@ struct SynthQuickLogicPass : public ScriptPass {
lib_path = "+/quicklogic/";
dsp = true;
ioff = true;
flatten = true;
}
void set_scratchpad_defaults(RTLIL::Design *design) {
@ -163,6 +164,10 @@ struct SynthQuickLogicPass : public ScriptPass {
ioff = false;
continue;
}
if (args[argidx] == "-noflatten") {
flatten = false;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -207,7 +212,8 @@ struct SynthQuickLogicPass : public ScriptPass {
if (check_label("prepare")) {
run("proc");
run("flatten");
if (flatten)
run("flatten", "(unless -noflatten)");
if (help_mode || family == "pp3") {
run("tribuf -logic", " (for pp3)");
}

View file

@ -0,0 +1,648 @@
# Generated by Yosys 0.53+24 (git sha1 ab636979e, sccache clang++ 19.1.7 -fPIC -O3 -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address,undefined)
autoidx 171528
attribute \hdlname "csr_regfile_0000000000000000_1"
module \csr_regfile_0000000000000000_1
wire $delete_wire$169641
wire $delete_wire$169642
wire $delete_wire$169643
wire $delete_wire$169644
wire $delete_wire$169645
wire $delete_wire$169646
wire $delete_wire$169647
wire $delete_wire$169648
wire $delete_wire$169649
wire $delete_wire$169650
wire $delete_wire$169651
wire $delete_wire$169652
wire $delete_wire$169653
wire $delete_wire$169654
wire $delete_wire$169655
wire $delete_wire$169656
wire $delete_wire$169657
wire $delete_wire$169658
wire $delete_wire$169659
wire $delete_wire$169660
wire $delete_wire$169661
wire $delete_wire$169662
wire $delete_wire$169663
wire $delete_wire$169664
wire $delete_wire$169665
wire $delete_wire$169666
wire $delete_wire$169667
wire $delete_wire$169668
wire $delete_wire$169669
wire $delete_wire$169670
wire $delete_wire$169671
wire $delete_wire$169672
wire $delete_wire$169673
wire $delete_wire$169674
wire $delete_wire$169675
wire $delete_wire$169676
wire $delete_wire$169677
wire $delete_wire$169678
wire $delete_wire$169679
wire $delete_wire$169680
wire $delete_wire$169681
wire $delete_wire$169682
wire $delete_wire$169683
wire $delete_wire$169684
wire $delete_wire$169685
wire $delete_wire$169686
wire $delete_wire$169687
wire $delete_wire$169688
wire $delete_wire$169689
wire $delete_wire$169690
wire $delete_wire$169691
wire $delete_wire$169692
wire $delete_wire$169693
wire $delete_wire$169694
wire $delete_wire$169695
wire $delete_wire$169696
wire $delete_wire$169697
wire $delete_wire$169698
wire $delete_wire$169699
wire $delete_wire$169700
wire $delete_wire$169701
wire $delete_wire$169702
wire $delete_wire$169703
wire $delete_wire$169704
wire $delete_wire$169705
wire $delete_wire$169706
wire $delete_wire$169707
wire $delete_wire$169708
wire $delete_wire$169709
wire $delete_wire$169710
wire $delete_wire$169711
wire $delete_wire$169712
wire width 32 $delete_wire$169713
wire $delete_wire$169714
wire $delete_wire$169715
wire $delete_wire$169716
wire $delete_wire$169717
wire $delete_wire$169718
wire $delete_wire$169719
wire $delete_wire$169720
wire $delete_wire$169721
wire $delete_wire$169722
wire $delete_wire$169723
wire $delete_wire$169724
wire $delete_wire$169725
wire $delete_wire$169726
wire $delete_wire$169727
wire $delete_wire$169728
wire $delete_wire$169729
wire $delete_wire$169730
wire $delete_wire$169731
wire $delete_wire$169732
wire $delete_wire$169733
wire $delete_wire$169734
wire $delete_wire$169735
wire $delete_wire$169736
wire $delete_wire$169737
wire $delete_wire$169738
wire $delete_wire$169739
wire $delete_wire$169740
wire $delete_wire$169741
wire $delete_wire$169742
wire $delete_wire$169743
wire $delete_wire$169744
wire $delete_wire$169745
wire $delete_wire$169746
wire $delete_wire$169747
wire $delete_wire$169748
wire $delete_wire$169749
wire $delete_wire$169750
wire $delete_wire$169751
wire $delete_wire$169752
wire $delete_wire$169753
wire $delete_wire$169754
wire $delete_wire$169755
wire $delete_wire$169756
wire $delete_wire$169757
wire $delete_wire$169758
wire $delete_wire$169759
wire $delete_wire$169760
wire $delete_wire$169761
wire $delete_wire$169762
wire $delete_wire$169763
wire $delete_wire$169764
wire $delete_wire$169765
wire $delete_wire$169766
wire $delete_wire$169767
wire $delete_wire$169768
wire $delete_wire$169769
wire $delete_wire$169770
wire $delete_wire$169771
wire $delete_wire$169772
wire $delete_wire$169773
wire $delete_wire$169774
wire $delete_wire$169775
wire $delete_wire$169776
wire $delete_wire$169777
wire $delete_wire$169778
wire $delete_wire$169779
wire $delete_wire$169780
wire $delete_wire$169781
wire $delete_wire$169782
wire $delete_wire$169783
wire $delete_wire$169784
wire $delete_wire$169785
wire $delete_wire$169786
wire $delete_wire$169787
wire $delete_wire$169788
wire $delete_wire$169789
wire $delete_wire$169790
wire $delete_wire$169791
wire $delete_wire$169792
wire $delete_wire$169793
wire $delete_wire$169794
wire $delete_wire$169795
wire $delete_wire$169796
wire $delete_wire$169797
wire $delete_wire$169798
wire $delete_wire$169799
wire $delete_wire$169800
wire $delete_wire$169801
wire $delete_wire$169802
wire $delete_wire$169803
wire $delete_wire$169804
wire $delete_wire$169805
wire $delete_wire$169806
wire $delete_wire$169807
wire $delete_wire$169808
wire $delete_wire$169809
wire $delete_wire$169810
wire $delete_wire$169811
wire $delete_wire$169812
wire $delete_wire$169813
wire $delete_wire$169814
wire $delete_wire$169815
wire $delete_wire$169816
wire $delete_wire$169817
wire $delete_wire$169818
wire $delete_wire$169819
wire $delete_wire$169820
wire $delete_wire$169821
wire width 5 $delete_wire$169822
wire width 17 $delete_wire$169823
wire $delete_wire$169824
wire $delete_wire$169825
wire $delete_wire$169826
wire $delete_wire$169827
wire $delete_wire$169828
wire $delete_wire$169829
wire $delete_wire$169830
wire $delete_wire$169831
wire $delete_wire$169832
wire $delete_wire$169833
wire $delete_wire$169834
wire $delete_wire$169835
wire $delete_wire$169836
wire $delete_wire$169837
wire $delete_wire$169838
wire $delete_wire$169839
wire $delete_wire$169840
wire $delete_wire$169960
wire $delete_wire$169961
wire $delete_wire$169962
wire $delete_wire$169963
wire $delete_wire$169964
wire $delete_wire$169965
wire $delete_wire$169966
wire $delete_wire$169967
wire $delete_wire$169968
wire $delete_wire$169969
wire $delete_wire$169970
wire $delete_wire$169971
wire $delete_wire$169972
wire $delete_wire$169973
wire $delete_wire$169974
wire $delete_wire$169975
wire $delete_wire$169976
wire $delete_wire$169977
wire $delete_wire$169978
wire $delete_wire$169979
wire $delete_wire$169980
wire $delete_wire$169981
wire $delete_wire$169982
wire $delete_wire$169983
wire $delete_wire$169984
wire $delete_wire$169985
wire $delete_wire$169986
wire $delete_wire$169987
wire $delete_wire$169988
wire $delete_wire$169989
wire $delete_wire$169990
wire $delete_wire$169991
wire $delete_wire$169992
wire $delete_wire$169993
wire $delete_wire$169994
wire $delete_wire$169995
wire $delete_wire$169996
wire $delete_wire$169997
wire $delete_wire$169998
wire $delete_wire$169999
wire $delete_wire$170000
wire $delete_wire$170001
wire $delete_wire$170002
wire $delete_wire$170003
wire $delete_wire$170004
wire $delete_wire$170005
wire $delete_wire$170006
wire $delete_wire$170007
wire $delete_wire$170008
wire $delete_wire$170009
wire $delete_wire$170010
wire $delete_wire$170011
wire $delete_wire$170012
wire $delete_wire$170013
wire $delete_wire$170014
wire $delete_wire$170015
wire $delete_wire$170016
wire $delete_wire$170017
wire $delete_wire$170018
wire $delete_wire$170019
wire $delete_wire$170020
wire $delete_wire$170021
wire $delete_wire$170022
wire $delete_wire$170023
wire $delete_wire$170024
wire $delete_wire$170025
wire $delete_wire$170026
wire $delete_wire$170027
wire $delete_wire$170028
wire $delete_wire$170029
wire $delete_wire$170030
wire $delete_wire$170031
wire $delete_wire$170032
wire $delete_wire$170033
wire $delete_wire$170034
wire $delete_wire$170035
wire $delete_wire$170036
wire $delete_wire$170037
wire $delete_wire$170038
wire $delete_wire$170039
wire $delete_wire$170040
wire $delete_wire$170041
wire $delete_wire$170042
wire $delete_wire$170043
wire $delete_wire$170044
wire $delete_wire$170045
wire $delete_wire$170046
wire $delete_wire$170047
wire $delete_wire$170048
wire $delete_wire$170049
wire $delete_wire$170050
wire $delete_wire$170051
wire $delete_wire$170052
wire $delete_wire$170053
wire $delete_wire$170054
wire $delete_wire$170055
wire $delete_wire$170056
wire $delete_wire$170057
wire $delete_wire$170058
wire $delete_wire$170059
wire $delete_wire$170635
wire $delete_wire$170636
wire $delete_wire$170637
wire $delete_wire$170638
wire $delete_wire$170639
wire $delete_wire$170640
wire $delete_wire$170641
wire $delete_wire$170642
wire $delete_wire$170643
wire $delete_wire$170644
wire $delete_wire$170645
wire $delete_wire$170646
wire $delete_wire$170647
wire $delete_wire$170648
wire $delete_wire$170649
wire $delete_wire$170650
wire $delete_wire$170651
wire $delete_wire$170652
wire $delete_wire$170653
wire $delete_wire$170654
wire $delete_wire$170655
wire $delete_wire$170656
wire $delete_wire$170657
wire $delete_wire$170658
wire $delete_wire$170659
wire $delete_wire$170660
wire $delete_wire$170661
wire $delete_wire$170662
wire $delete_wire$170663
wire $delete_wire$170664
wire $delete_wire$170665
wire $delete_wire$170666
wire $delete_wire$170667
wire $delete_wire$170668
wire $delete_wire$170669
wire $delete_wire$170670
wire $delete_wire$170749
wire $delete_wire$170750
wire $delete_wire$170751
wire $delete_wire$170752
wire $delete_wire$170753
wire $delete_wire$170754
wire $delete_wire$170755
wire width 2 $delete_wire$170756
wire width 2 $delete_wire$170757
wire $delete_wire$170758
wire $delete_wire$170759
wire $delete_wire$170760
wire $delete_wire$170761
wire $delete_wire$170762
wire $delete_wire$170763
wire $delete_wire$170764
wire $delete_wire$170765
wire $delete_wire$170766
wire $delete_wire$170767
wire $delete_wire$170768
wire $delete_wire$170769
wire $delete_wire$170770
wire $delete_wire$170771
wire $delete_wire$170772
wire $delete_wire$170773
wire $delete_wire$170774
wire $delete_wire$170775
wire $delete_wire$170859
wire $delete_wire$170860
wire $delete_wire$170861
wire $delete_wire$170862
wire $delete_wire$170863
wire $delete_wire$170864
wire $delete_wire$170865
wire $delete_wire$170866
wire $delete_wire$170867
wire $delete_wire$170868
wire $delete_wire$170869
wire $delete_wire$170870
wire $delete_wire$170871
wire $delete_wire$170872
wire $delete_wire$170873
wire $delete_wire$170874
wire $delete_wire$170875
wire $delete_wire$170876
wire $delete_wire$170877
wire $delete_wire$170878
wire $delete_wire$170879
wire $delete_wire$170880
wire $delete_wire$170881
wire $delete_wire$170882
wire $delete_wire$170996
wire $delete_wire$170997
wire $delete_wire$170998
wire $delete_wire$170999
wire $delete_wire$171000
wire $delete_wire$171001
wire $delete_wire$171002
wire $delete_wire$171003
wire $delete_wire$171004
wire $delete_wire$171005
wire $delete_wire$171006
wire $delete_wire$171007
wire $delete_wire$171008
wire $delete_wire$171009
wire $delete_wire$171010
wire $delete_wire$171011
wire $delete_wire$171035
wire $delete_wire$171036
wire $delete_wire$171037
wire $delete_wire$171038
wire $delete_wire$171039
wire $delete_wire$171040
wire $delete_wire$171041
wire $delete_wire$171042
wire $delete_wire$171043
wire $delete_wire$171044
wire $delete_wire$171045
wire $delete_wire$171046
wire $delete_wire$171047
wire $delete_wire$171048
wire $delete_wire$171049
wire $delete_wire$171172
wire $delete_wire$171173
wire $delete_wire$171174
wire $delete_wire$171175
wire $delete_wire$171176
wire $delete_wire$171177
wire $delete_wire$171178
wire $delete_wire$171179
wire $delete_wire$171180
wire $delete_wire$171181
wire $delete_wire$171182
wire $delete_wire$171183
wire $delete_wire$171184
wire $delete_wire$171185
wire $delete_wire$171186
wire $delete_wire$171187
wire $delete_wire$171188
wire $delete_wire$171189
wire $delete_wire$171190
wire width 2 $delete_wire$171200
wire width 2 $delete_wire$171201
wire $delete_wire$171202
wire $delete_wire$171203
wire $delete_wire$171204
wire $delete_wire$171205
wire $delete_wire$171206
wire $delete_wire$171207
wire $delete_wire$171226
wire $delete_wire$171227
wire $delete_wire$171228
wire $delete_wire$171229
wire $delete_wire$171230
wire $delete_wire$171231
wire $delete_wire$171232
wire $delete_wire$171254
wire $delete_wire$171255
wire $delete_wire$171256
wire $delete_wire$171257
wire $delete_wire$171258
wire $delete_wire$171259
wire $delete_wire$171267
wire $delete_wire$171268
wire $delete_wire$171269
wire $delete_wire$171270
wire $delete_wire$171271
wire $delete_wire$171272
wire $delete_wire$171314
wire $delete_wire$171315
wire $delete_wire$171316
wire $delete_wire$171317
wire $delete_wire$171318
wire $delete_wire$171338
wire $delete_wire$171339
wire $delete_wire$171340
wire $delete_wire$171341
wire $delete_wire$171350
wire $delete_wire$171351
wire $delete_wire$171352
wire $delete_wire$171353
wire $delete_wire$171354
wire $delete_wire$171355
wire $delete_wire$171356
wire $delete_wire$171357
wire $delete_wire$171358
wire $delete_wire$171359
wire $delete_wire$171360
wire width 2 $delete_wire$171361
wire $delete_wire$171362
wire $delete_wire$171371
wire $delete_wire$171372
wire $delete_wire$171373
wire $delete_wire$171374
wire $delete_wire$171387
wire $delete_wire$171388
wire $delete_wire$171389
wire $delete_wire$171390
wire $delete_wire$171408
wire $delete_wire$171409
wire $delete_wire$171441
wire $delete_wire$171442
wire $delete_wire$171449
wire $delete_wire$171450
wire $delete_wire$171454
wire $delete_wire$171455
wire $delete_wire$171471
wire $delete_wire$171472
wire $delete_wire$171477
wire $delete_wire$171501
wire $delete_wire$171502
wire $delete_wire$171507
wire $delete_wire$171512
wire $delete_wire$171513
wire $delete_wire$171514
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
wire \N2231
wire \N3558
attribute \unused_bits "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
wire width 32 \dcsr_d
wire \dcsr_q_prv__0_
cell $adff $procdff$137332
parameter \ARST_POLARITY 0
parameter \ARST_VALUE 1'1
parameter \CLK_POLARITY 1'1
parameter \WIDTH 1
connect \ARST $delete_wire$170004
connect \CLK $delete_wire$171206
connect \D \dcsr_d [0]
connect \Q \dcsr_q_prv__0_
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216087$6334
parameter \WIDTH 32
connect \A { $delete_wire$170875 $delete_wire$171472 $delete_wire$171181 $delete_wire$169735 $delete_wire$169994 $delete_wire$169963 $delete_wire$170670 $delete_wire$169702 $delete_wire$169975 $delete_wire$170002 $delete_wire$169641 $delete_wire$171011 $delete_wire$171006 $delete_wire$171173 $delete_wire$171387 $delete_wire$170769 $delete_wire$170881 $delete_wire$169743 $delete_wire$169731 $delete_wire$169710 $delete_wire$169756 $delete_wire$170018 $delete_wire$169779 $delete_wire$170037 $delete_wire$169794 $delete_wire$171339 $delete_wire$171256 $delete_wire$171205 $delete_wire$169670 $delete_wire$171352 $delete_wire$171315 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
connect \S $delete_wire$169809
connect \Y { $delete_wire$169830 $delete_wire$171390 $delete_wire$169837 $delete_wire$169679 $delete_wire$169677 $delete_wire$169767 $delete_wire$169828 $delete_wire$170038 $delete_wire$169704 $delete_wire$169653 $delete_wire$169707 $delete_wire$169684 $delete_wire$169986 $delete_wire$169712 $delete_wire$170033 $delete_wire$169759 $delete_wire$171513 $delete_wire$170012 $delete_wire$170876 $delete_wire$170007 $delete_wire$169965 $delete_wire$169825 $delete_wire$169655 $delete_wire$169839 $delete_wire$170034 $delete_wire$170042 $delete_wire$171338 $delete_wire$169833 $delete_wire$169762 $delete_wire$169835 $delete_wire$169764 \N2231 }
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333
parameter \WIDTH 32
connect \A { $delete_wire$170014 $delete_wire$171257 $delete_wire$170770 $delete_wire$169725 $delete_wire$170873 $delete_wire$171514 $delete_wire$170870 $delete_wire$169692 $delete_wire$171184 $delete_wire$170045 $delete_wire$169649 $delete_wire$170859 $delete_wire$171455 $delete_wire$170053 $delete_wire$170044 $delete_wire$170768 $delete_wire$170659 $delete_wire$169742 $delete_wire$169730 $delete_wire$169718 $delete_wire$169741 $delete_wire$170019 $delete_wire$169778 $delete_wire$170024 $delete_wire$169807 $delete_wire$171046 $delete_wire$171374 $delete_wire$170861 $delete_wire$169669 $delete_wire$171182 $delete_wire$171388 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
connect \S $delete_wire$169810
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332
parameter \WIDTH 32
connect \A { $delete_wire$169820 $delete_wire$171507 $delete_wire$171441 $delete_wire$169724 $delete_wire$169992 $delete_wire$169691 $delete_wire$171356 $delete_wire$169700 $delete_wire$169977 $delete_wire$170046 $delete_wire$169648 $delete_wire$170774 $delete_wire$171038 $delete_wire$171005 $delete_wire$170057 $delete_wire$171226 $delete_wire$170874 $delete_wire$169755 $delete_wire$169729 $delete_wire$171450 $delete_wire$169754 $delete_wire$170020 $delete_wire$169777 $delete_wire$170025 $delete_wire$169806 $delete_wire$170643 $delete_wire$171177 $delete_wire$171449 $delete_wire$169668 $delete_wire$171512 $delete_wire$171501 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
connect \S $delete_wire$169997
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331
parameter \WIDTH 32
connect \A { $delete_wire$169819 $delete_wire$170772 $delete_wire$170773 $delete_wire$169723 $delete_wire$169990 $delete_wire$169690 $delete_wire$170669 $delete_wire$169699 $delete_wire$169978 $delete_wire$170047 $delete_wire$169647 $delete_wire$171049 $delete_wire$171007 $delete_wire$170872 $delete_wire$170056 $delete_wire$171004 $delete_wire$171202 $delete_wire$169793 $delete_wire$169728 $delete_wire$170664 $delete_wire$169753 $delete_wire$170021 $delete_wire$169776 $delete_wire$170026 $delete_wire$169805 $delete_wire$170644 $delete_wire$171008 $delete_wire$170657 $delete_wire$169658 $delete_wire$171003 $delete_wire$170749 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
connect \S $delete_wire$169826
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330
parameter \WIDTH 32
connect \A { 4'0100 $delete_wire$169823 2'00 $delete_wire$169822 1'0 $delete_wire$169781 $delete_wire$170757 }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
connect \S $delete_wire$170006
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329
parameter \WIDTH 32
connect \A { $delete_wire$169818 $delete_wire$170762 $delete_wire$170868 $delete_wire$169722 $delete_wire$169991 $delete_wire$169689 $delete_wire$170642 $delete_wire$169698 $delete_wire$169979 $delete_wire$170048 $delete_wire$169646 $delete_wire$171409 $delete_wire$171259 $delete_wire$170043 $delete_wire$170055 $delete_wire$171471 $delete_wire$170646 $delete_wire$169792 $delete_wire$169727 $delete_wire$169740 $delete_wire$169752 $delete_wire$170022 $delete_wire$169775 $delete_wire$170027 $delete_wire$169804 $delete_wire$170666 $delete_wire$170663 $delete_wire$171179 $delete_wire$169666 $delete_wire$171186 $delete_wire$170655 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
connect \S $delete_wire$169972
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328
parameter \WIDTH 32
connect \A { $delete_wire$169817 $delete_wire$171190 $delete_wire$171408 $delete_wire$169721 $delete_wire$171002 $delete_wire$169688 $delete_wire$171270 $delete_wire$169697 $delete_wire$169980 $delete_wire$169982 $delete_wire$169645 $delete_wire$171180 $delete_wire$169771 $delete_wire$170860 $delete_wire$170054 $delete_wire$171009 $delete_wire$170639 $delete_wire$169791 $delete_wire$170879 $delete_wire$169739 $delete_wire$169751 $delete_wire$170049 $delete_wire$169774 $delete_wire$170028 $delete_wire$169803 $delete_wire$170645 $delete_wire$169989 $delete_wire$171272 $delete_wire$169665 $delete_wire$171174 $delete_wire$170653 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
connect \S $delete_wire$170036
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327
parameter \WIDTH 32
connect \A { $delete_wire$169816 $delete_wire$171228 $delete_wire$171454 $delete_wire$169720 $delete_wire$170997 $delete_wire$169687 $delete_wire$170649 $delete_wire$169696 $delete_wire$169981 $delete_wire$170050 $delete_wire$169644 $delete_wire$170760 $delete_wire$169786 $delete_wire$170862 $delete_wire$170032 $delete_wire$171389 $delete_wire$171043 $delete_wire$169790 $delete_wire$169749 $delete_wire$169738 $delete_wire$169750 $delete_wire$169983 $delete_wire$169773 $delete_wire$170029 $delete_wire$169802 $delete_wire$170660 $delete_wire$169962 $delete_wire$170658 $delete_wire$169664 $delete_wire$170751 $delete_wire$170640 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
connect \S $delete_wire$169705
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326
parameter \WIDTH 32
connect \A { $delete_wire$169815 $delete_wire$171372 $delete_wire$171175 $delete_wire$169719 $delete_wire$171044 $delete_wire$169686 $delete_wire$171231 $delete_wire$169695 $delete_wire$170008 $delete_wire$170052 $delete_wire$169643 $delete_wire$170996 $delete_wire$169785 $delete_wire$170865 $delete_wire$170636 $delete_wire$171185 $delete_wire$171188 $delete_wire$169789 $delete_wire$171045 $delete_wire$169737 $delete_wire$169765 $delete_wire$171268 $delete_wire$169772 $delete_wire$170016 $delete_wire$169801 $delete_wire$170665 $delete_wire$170058 $delete_wire$169961 $delete_wire$169663 $delete_wire$171502 $delete_wire$170652 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
connect \S $delete_wire$170650
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325
parameter \WIDTH 32
connect \A { $delete_wire$169814 $delete_wire$170753 $delete_wire$171176 $delete_wire$169709 $delete_wire$170999 $delete_wire$169685 $delete_wire$170647 $delete_wire$169694 $delete_wire$169999 $delete_wire$170051 $delete_wire$169642 $delete_wire$170863 $delete_wire$169784 $delete_wire$170755 $delete_wire$170754 $delete_wire$171204 $delete_wire$171373 $delete_wire$169788 $delete_wire$170059 $delete_wire$169736 $delete_wire$169748 $delete_wire$171351 $delete_wire$169787 $delete_wire$171340 $delete_wire$169800 $delete_wire$170638 $delete_wire$169970 $delete_wire$169974 $delete_wire$169662 $delete_wire$170764 $delete_wire$170651 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
connect \S $delete_wire$169996
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324
parameter \WIDTH 32
connect \A { $delete_wire$169813 $delete_wire$171229 $delete_wire$170765 $delete_wire$169717 $delete_wire$171035 $delete_wire$169675 $delete_wire$170637 $delete_wire$169693 $delete_wire$170000 $delete_wire$171000 $delete_wire$169650 $delete_wire$171442 $delete_wire$169783 $delete_wire$170882 $delete_wire$171318 $delete_wire$171010 $delete_wire$171357 $delete_wire$169821 $delete_wire$170880 $delete_wire$169726 $delete_wire$169747 $delete_wire$169984 $delete_wire$169770 $delete_wire$170031 $delete_wire$169799 $delete_wire$171048 $delete_wire$169969 $delete_wire$170656 $delete_wire$169661 $delete_wire$171354 $delete_wire$170661 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
connect \S $delete_wire$169671
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323
parameter \WIDTH 32
connect \A { $delete_wire$169998 $delete_wire$171350 $delete_wire$170759 $delete_wire$169716 $delete_wire$169993 $delete_wire$169683 $delete_wire$170654 $delete_wire$169667 $delete_wire$170001 $delete_wire$171371 $delete_wire$169674 $delete_wire$170667 $delete_wire$169782 $delete_wire$171187 $delete_wire$170878 $delete_wire$170766 $delete_wire$171254 $delete_wire$169796 $delete_wire$170877 $delete_wire$169734 $delete_wire$169746 $delete_wire$171207 $delete_wire$169769 $delete_wire$170009 $delete_wire$169798 $delete_wire$171172 $delete_wire$169968 $delete_wire$171271 $delete_wire$169660 $delete_wire$171232 $delete_wire$170662 \dcsr_q_prv__0_ }
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
connect \S $delete_wire$169831
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322
parameter \WIDTH 32
connect \A { $delete_wire$169811 $delete_wire$171355 $delete_wire$170763 $delete_wire$169715 $delete_wire$171039 $delete_wire$169682 $delete_wire$169988 $delete_wire$169657 $delete_wire$170015 $delete_wire$171317 $delete_wire$169673 $delete_wire$170866 $delete_wire$169768 $delete_wire$170998 $delete_wire$170752 $delete_wire$170023 $delete_wire$170767 $delete_wire$169795 $delete_wire$170030 $delete_wire$169733 $delete_wire$169745 $delete_wire$171360 $delete_wire$169834 $delete_wire$170010 $delete_wire$169976 $delete_wire$171203 $delete_wire$169967 $delete_wire$171477 $delete_wire$169659 $delete_wire$171230 $delete_wire$170641 \dcsr_q_prv__0_ }
connect \B $delete_wire$169713
connect \S $delete_wire$171001
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217099$7332
parameter \WIDTH 32
connect \A { $delete_wire$170013 $delete_wire$171353 $delete_wire$171037 $delete_wire$169714 $delete_wire$171269 $delete_wire$169681 $delete_wire$170668 $delete_wire$169656 $delete_wire$170003 $delete_wire$171189 $delete_wire$169672 $delete_wire$169960 $delete_wire$169780 $delete_wire$170775 $delete_wire$170871 $delete_wire$170864 $delete_wire$171183 $delete_wire$169808 $delete_wire$170017 $delete_wire$169732 $delete_wire$169744 $delete_wire$171359 $delete_wire$171041 $delete_wire$171040 $delete_wire$170761 $delete_wire$170635 $delete_wire$169966 $delete_wire$169971 $delete_wire$169701 $delete_wire$170648 $delete_wire$171255 \dcsr_q_prv__0_ }
connect \B { $delete_wire$169829 $delete_wire$171316 $delete_wire$169836 $delete_wire$169678 $delete_wire$169676 $delete_wire$169766 $delete_wire$169827 $delete_wire$170039 $delete_wire$169703 $delete_wire$169652 $delete_wire$169706 $delete_wire$169708 $delete_wire$169987 $delete_wire$169711 $delete_wire$169985 $delete_wire$169758 $delete_wire$169973 $delete_wire$170011 $delete_wire$170869 $delete_wire$169812 $delete_wire$169964 $delete_wire$169824 $delete_wire$169654 $delete_wire$169838 $delete_wire$170035 $delete_wire$169840 $delete_wire$171341 $delete_wire$169832 $delete_wire$169761 $delete_wire$169797 $delete_wire$169763 \N2231 }
connect \S $delete_wire$169760
connect \Y { \dcsr_d [31:9] $delete_wire$171047 $delete_wire$170040 $delete_wire$170750 \dcsr_d [5:2] $delete_wire$171227 \N3558 }
end
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217233$7498
parameter \WIDTH 5
connect \A { $delete_wire$169995 $delete_wire$169651 $delete_wire$171042 $delete_wire$171201 }
connect \B { $delete_wire$170867 $delete_wire$170041 $delete_wire$171178 $delete_wire$171358 \N3558 }
connect \S $delete_wire$170771
connect \Y { \dcsr_d [8:6] \dcsr_d [1:0] }
end
end

View file

@ -0,0 +1,58 @@
# 5279 issue
# Check only for complimentary patterns elimination
read_rtlil opt_dff-simplify.il
select -assert-count 0 t:$adffe
select -assert-count 1 t:$adff
select -assert-count 0 t:$ne
opt_dff
select -assert-count 1 t:$adffe
select -assert-count 0 t:$adff
select -assert-count 8 t:$ne r:A_WIDTH=3 %i
select -assert-count 5 t:$ne r:A_WIDTH=2 %i
select -assert-none t:$ne r:A_WIDTH=13 %i
select -assert-none t:$ne r:A_WIDTH=14 %i
select -assert-none t:$ne r:A_WIDTH=15 %i
select -assert-none t:$ne r:A_WIDTH=10 %i
select -assert-none t:$ne r:A_WIDTH=12 %i
select -assert-none t:$ne r:A_WIDTH=11 %i
# Check for both complimentary and redundancy elimination
read_verilog << EOT
module test(input clk, input h, input i, input m, output reg p);
wire D;
wire a;
wire j;
wire c;
wire mux_test;
wire n;
always @(posedge clk)
p <= D;
assign j = n ? 1'hx : a;
assign a = i ? mux_test : p;
assign D = m ? h : j;
assign c = n ? 1'hx : p;
assign mux_test = m ? 1'hx : c;
endmodule
EOT
cd test
proc
select -assert-count 0 t:$dffe
select -assert-count 1 t:$dff
select -assert-count 0 t:$ne
opt_dff
select -assert-count 1 t:$dffe
select -assert-count 0 t:$dff
select -assert-count 1 t:$ne r:A_WIDTH=2 %i
select -assert-none t:$ne r:A_WIDTH=3 %i

View file

@ -0,0 +1,32 @@
#include <gtest/gtest.h>
#include "kernel/bitpattern.h"
#include "kernel/rtlil.h"
YOSYS_NAMESPACE_BEGIN
TEST(BitpatternTest, has)
{
SigSpec _aaa = {RTLIL::Sa, RTLIL::Sa, RTLIL::Sa};
SigSpec _01a = {RTLIL::S0, RTLIL::S1, RTLIL::Sa};
SigSpec _011 = {RTLIL::S0, RTLIL::S1, RTLIL::S1};
SigSpec _111 = {RTLIL::S1, RTLIL::S1, RTLIL::S1};
EXPECT_TRUE(BitPatternPool(_aaa).has_any(_01a));
EXPECT_TRUE(BitPatternPool(_01a).has_any(_01a));
// 011 overlaps with 01a
EXPECT_TRUE(BitPatternPool(_011).has_any(_01a));
// overlap is symmetric
EXPECT_TRUE(BitPatternPool(_01a).has_any(_011));
EXPECT_FALSE(BitPatternPool(_111).has_any(_01a));
EXPECT_TRUE(BitPatternPool(_aaa).has_all(_01a));
EXPECT_TRUE(BitPatternPool(_01a).has_all(_01a));
// 011 is covered by 01a
EXPECT_TRUE(BitPatternPool(_01a).has_all(_011));
// 01a is not covered by 011
EXPECT_FALSE(BitPatternPool(_011).has_all(_01a));
EXPECT_FALSE(BitPatternPool(_111).has_all(_01a));
}
YOSYS_NAMESPACE_END

View file

@ -0,0 +1,67 @@
#include <gtest/gtest.h>
#include "kernel/yosys_common.h"
#include <unordered_set>
YOSYS_NAMESPACE_BEGIN
static Hasher hash(int x)
{
Hasher h;
h.eat(x);
return h;
}
TEST(CommutativeTest, basic)
{
hashlib::commutative_hash comm1;
comm1.eat(hash(1));
comm1.eat(hash(2));
hashlib::commutative_hash comm2;
comm2.eat(hash(2));
comm2.eat(hash(1));
EXPECT_EQ(comm1.hash_into(Hasher()).yield(), comm2.hash_into(Hasher()).yield());
}
TEST(PoolHashTest, collisions)
{
uint64_t collisions = 0;
std::unordered_set<Hasher::hash_t> hashes;
for (int i = 0; i < 1000; ++i) {
for (int j = i + 1; j < 1000; ++j) {
pool<int> p1;
p1.insert(i);
p1.insert(j);
auto h = p1.hash_into(Hasher()).yield();
if (!hashes.insert(h).second) {
++collisions;
}
}
}
std::cout << "pool<int> collisions: " << collisions << std::endl;
EXPECT_LT(collisions, 10'000);
}
TEST(PoolHashTest, subset_collisions)
{
uint64_t collisions = 0;
std::unordered_set<Hasher::hash_t> hashes;
for (int i = 0; i < 1000 * 1000; ++i) {
pool<int> p1;
for (int b = 0; i >> b; ++b) {
if ((i >> b) & 1) {
p1.insert(b);
}
}
auto h = p1.hash_into(Hasher()).yield();
if (!hashes.insert(h).second) {
++collisions;
}
}
std::cout << "pool<int> subset collisions: " << collisions << std::endl;
EXPECT_LT(collisions, 100);
}
YOSYS_NAMESPACE_END

View file

@ -69,4 +69,14 @@ TEST(KernelStringfTest, dynamicWidthAndPrecision)
EXPECT_EQ(stringf("%*.*f", 8, 4, 1.0), " 1.0000");
}
TEST(KernelStringfTest, dynamicPrecisionInt)
{
EXPECT_EQ(stringf("%.*d", 4, 7), "0007");
}
TEST(KernelStringfTest, dynamicWidthAndPrecisionInt)
{
EXPECT_EQ(stringf("%*.*d", 8, 4, 7), " 0007");
}
YOSYS_NAMESPACE_END

View file

@ -0,0 +1,30 @@
read_verilog <<EOT
module half_clock (CLK, Q, magic);
input CLK;
output reg Q = 0;
input magic;
always @(posedge CLK)
Q <= ~Q;
endmodule
EOT
proc
design -save half_clock
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
abstract -state -initstates 1 */Q
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
design -load half_clock
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 3 Q 0 -set-at 4 Q 0
abstract -state -initstates 2 */Q
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0 -set-at 3 Q 0
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 3 Q 0 -set-at 4 Q 0

View file

@ -0,0 +1,141 @@
read_verilog -sv <<EOT
module gold (input D, output Q);
assign Q = '0;
endmodule
module gate (input D, output Q);
assume property (D == '0);
assign Q = D;
endmodule
EOT
chformal -lower
async2sync
design -stash input
# using $assert cells in sat verifies
design -load input
equiv_make -make_assert gold gate equiv
prep -top equiv
sat -set-assumes -prove-asserts -verify
# this fails
# sat -prove-asserts -verify
# so should $equiv
## in equiv_simple
design -load input
equiv_make gold gate equiv
equiv_simple -set-assumes equiv
equiv_status -assert equiv
## and equiv_induct
delete equiv
equiv_make gold gate equiv
equiv_induct -set-assumes equiv
equiv_status -assert equiv
# and it works through cells
design -reset
read_verilog -sv <<EOT
module gold (input [1:0] D, output [1:0] Q);
assign Q = !D;
endmodule
module gate (input [1:0] D, output [1:0] Q);
assume property (D == 2'b11);
wire [1:0] G = ~D;
assign Q = G;
endmodule
EOT
chformal -lower
async2sync
design -stash input2
design -load input2
equiv_make -make_assert gold gate equiv
prep -top equiv
sat -set-assumes -prove-asserts -verify
design -load input2
equiv_make gold gate equiv
equiv_simple -set-assumes equiv
equiv_status -assert equiv
delete equiv
equiv_make gold gate equiv
equiv_induct -set-assumes equiv
equiv_status -assert equiv
# and registers
design -reset
read_verilog -sv <<EOT
module gold (input clk, input [1:0] D, output [1:0] Q);
assign Q = '0;
endmodule
module gate (input clk, input [1:0] D, output [1:0] Q);
reg [1:0] Dreg;
assume property (Dreg == 2'b11);
always @(clk) begin
Dreg <= D;
end
assign Q = ~Dreg;
endmodule
EOT
proc
chformal -lower
async2sync
design -stash input3
design -load input3
equiv_make -make_assert gold gate equiv
prep -top equiv
sat -set-assumes -prove-asserts -verify
design -load input3
equiv_make gold gate equiv
equiv_simple -set-assumes equiv
equiv_status -assert equiv
delete equiv
equiv_make gold gate equiv
equiv_induct -set-assumes equiv
equiv_status -assert equiv
# so long as the assumption doesn't end up after the equiv
design -reset
read_verilog -sv <<EOT
module gold (input [1:0] D, output [1:0] Q);
assign Q = !D;
endmodule
module gate (input [1:0] D, output [1:0] Q);
assume property (G == 2'b00);
wire [1:0] G = ~D;
assign Q = G;
endmodule
EOT
chformal -lower
async2sync
design -stash input4
logger -expect log "model found: FAIL!" 1
logger -expect log "Found a total of 2 unproven .equiv cells." 2
design -load input4
equiv_make -make_assert gold gate equiv
prep -top equiv
sat -set-assumes -prove-asserts
design -load input4
equiv_make gold gate equiv
equiv_simple -set-assumes equiv
equiv_status equiv
delete equiv
equiv_make gold gate equiv
equiv_induct -set-assumes equiv
equiv_status equiv

View file

@ -39,3 +39,18 @@ select -assert-count 1 w:d__1
select -assert-count 1 w:_e
select -assert-count 1 w:wire_
select -assert-count 1 w:$add$<<EOF:*$1_Y
# Ports are updated during rename
design -reset
read_verilog << EOT
module top(output \$e );
submod \a$ (\$e );
endmodule
module submod(output \a[0] );
assign \a[0] = 0;
endmodule
EOT
rename -unescape
check

View file

@ -0,0 +1,35 @@
read_verilog <<EOF
module top(input clk, rst, input [7:0] din, output [7:0] dout, input bin, output bout);
reg [7:0] dq;
reg bq;
always @(posedge clk, posedge rst) begin
if (rst) dq <= '0;
else dq <= din;
end
always @(posedge clk) bq <= bin;
assign dout = dq;
assign bout = bq;
endmodule
EOF
proc
hierarchy -top top
select -assert-count 1 t:$dff
select -assert-count 1 t:$adff
select -assert-count 0 t:$dff n:bq %i
select -assert-count 0 t:$adff n:dq %i
select -assert-count 1 w:bq
select -assert-count 1 w:dq
rename -wire -move-to-cell
select -assert-count 1 t:$dff
select -assert-count 1 t:$adff
select -assert-count 1 t:$dff n:bq %i
select -assert-count 1 t:$adff n:dq %i
select -assert-count 0 w:bq
select -assert-count 0 w:dq

View file

@ -11,6 +11,8 @@ end
EOT
logger -expect log "Chip area for module '\\top': 9.072000" 1
logger -expect-no-warnings
logger -expect log " 1 9.072 cells" 1
logger -expect log " 1 9.072 sg13g2_and2_1" 1
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz
@ -70,5 +72,8 @@ end
EOT
logger -expect log "Chip area for top module '\\top': 112.492800" 1
logger -expect log "of which used for sequential elements: 94.348800" 1
logger -expect log "2 18.144 cells" 1
logger -expect log "4 112.493 cells" 1
logger -expect log "2 94.349 sg13g2_dfrbp_1" 1
logger -expect-no-warnings
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,62 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell \sg13g2_and2_1 \sub1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \sg13g2_and2_1 \sub2
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \B
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
end
EOT
logger -expect log "4 112.493 2 18.144 cells" 2
logger -expect log "2 18.144 2 18.144 sg13g2_and2_1" 2
logger -expect log "2 94.349 - - sg13g2_dfrbp_1" 2
logger -expect log "2 94.349 2 - submodules" 2
logger -expect-no-warnings
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top -hierarchy

View file

@ -0,0 +1,92 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell $and \sub1
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
wire \Y1
wire \Y2
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \Y2
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \B
connect \B 1'0
connect \Y \Y1
end
cell $reduce_xor \sub3
parameter \A_SIGNED 0
parameter \A_WIDTH 10
parameter \Y_WIDTH 1
connect \A 10'0000000000
connect \Y \Y2
end
end
EOT
logger -expect log "Chip area for top module '\\top': 66.000000" 1
logger -expect log "3 30.5 3 30.5 cells" 1
logger -expect log "2 51 - - \$reduce_xor" 2
logger -expect log "8 66 2 5 cells" 2
logger -expect-no-warnings
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy

View file

@ -0,0 +1,91 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell $and \sub1
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
wire \Y1
wire \Y2
wire width 2 \A2
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \Y2
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
cell $bmux \bmux1
parameter \WIDTH 2
parameter \S_WIDTH 2
connect \A 8'00000000
connect \S 2'00
connect \Y \A2
end
cell $reduce_xor \sub3
parameter \A_SIGNED 0
parameter \A_WIDTH 10
parameter \Y_WIDTH 1
connect \A 10'0000000000
connect \Y \Y2
end
end
EOT
logger -expect log "Chip area for top module '\\top': 80.000000" 1
logger -expect log "1 12 1 12 \$bmux" 1
logger -expect log "3 37.5 3 37.5 cells" 1
logger -expect log "8 80 2 5 cells" 2
logger -expect-no-warnings
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy

View file

@ -0,0 +1,7 @@
logger -expect prefix-error "<<EOT:2: ERROR: Digit larger than 1 used in in base-2 constant." 1
read_verilog <<EOT
module test (y);
output signed [2:0] y = 1'bf;
endmodule
EOT
dump

View file

@ -0,0 +1,3 @@
module test (y);
output signed [2:0] y = 1'bf;
endmodule

View file

@ -0,0 +1,2 @@
logger -expect prefix-error "./constparser_f_file.sv:2: ERROR: Digit larger than 1 used in in base-2 constant." 1
read_verilog -sv ./constparser_f_file.sv

View file

@ -0,0 +1,6 @@
logger -expect prefix-error "<<EOT:2: ERROR: syntax error, unexpected invalid token, expecting TOK_BASED_CONSTVAL" 1
read_verilog <<EOT
module test (y);
output signed [2:0] y = 1'bg;
endmodule
EOT

View file

@ -0,0 +1,15 @@
read_verilog -sv <<EOT
module smoke_initstate (
input resetn,
input clk,
input a
);
always @(posedge clk) begin
assert property ($stable(a));
assert property ($changed(a));
assert property ($rose(a));
assert property ($fell(a));
assume(resetn == !$initstate);
end
endmodule
EOT

View file

@ -0,0 +1,14 @@
package package_import_separate;
localparam integer
DATAWIDTH = 8,
ADDRWIDTH = 4;
localparam logic [2:0]
IDLE = 3'b000,
START = 3'b001,
DATA = 3'b010,
STOP = 3'b100,
DONE = 3'b101;
endpackage

View file

@ -0,0 +1,5 @@
read_verilog -sv package_import_separate.sv
read_verilog -sv package_import_separate_module.sv
hierarchy -check
proc
opt -full

View file

@ -0,0 +1,19 @@
import package_import_separate::*;
module package_import_separate_module;
logic [DATAWIDTH-1:0] data;
logic [ADDRWIDTH-1:0] addr;
logic [2:0] state;
always_comb begin
case (state)
IDLE: data = 8'h00;
START: data = 8'h01;
DATA: data = 8'h02;
STOP: data = 8'h04;
DONE: data = 8'h05;
default: data = 8'hFF;
endcase
end
endmodule