mirror of https://github.com/YosysHQ/yosys.git
Merge from upstream
This commit is contained in:
commit
e54fa487b8
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ __pycache__
|
|||
/boost
|
||||
/ffi
|
||||
/doxygen
|
||||
/bison
|
||||
/venv
|
||||
/*.whl
|
||||
/*.egg-info
|
||||
|
|
|
|||
6
Makefile
6
Makefile
|
|
@ -175,7 +175,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.56+105
|
||||
YOSYS_VER := 0.56+165
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'.' -f3)
|
||||
|
|
@ -376,7 +376,7 @@ BOOST_PYTHON_LIB ?= $(shell \
|
|||
|
||||
# Inside CentOS 7
|
||||
ifeq (${PLATFORM},centos7)
|
||||
BOOST_PYTHON_LIB = -L/opt/boost/lib -lboost_python38 -lboost_system -lboost_filesystem
|
||||
BOOST_PYTHON_LIB = -L/opt/boost/lib -lboost_python38
|
||||
CXXFLAGS += -I/opt/boost/include
|
||||
endif
|
||||
|
||||
|
|
@ -384,7 +384,7 @@ ifeq ($(BOOST_PYTHON_LIB),)
|
|||
$(error BOOST_PYTHON_LIB could not be detected. Please define manually)
|
||||
endif
|
||||
|
||||
LIBS += $(BOOST_PYTHON_LIB)
|
||||
LIBS += $(BOOST_PYTHON_LIB) -lboost_filesystem
|
||||
PY_WRAPPER_FILE = kernel/python_wrappers
|
||||
OBJS += $(PY_WRAPPER_FILE).o
|
||||
PY_GEN_SCRIPT= py_wrap_generator
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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 ¶m : 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <string>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* Provide frontend-wide location tracking like what bison generates
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
%require "3.8"
|
||||
%require "3.6"
|
||||
%language "c++"
|
||||
%define api.value.type variant
|
||||
%define api.prefix {frontend_verilog_yy}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct FfMergeHelper
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
const SigMapView *sigmap;
|
||||
RTLIL::Module *module;
|
||||
FfInitVals *initvals;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef HASHLIB_H
|
||||
#define HASHLIB_H
|
||||
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
|
@ -101,7 +102,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);
|
||||
|
|
@ -128,6 +129,7 @@ private:
|
|||
*this = hash_ops<T>::hash_into(t, *this);
|
||||
}
|
||||
|
||||
[[deprecated]]
|
||||
void commutative_eat(hash_t t) {
|
||||
state ^= t;
|
||||
}
|
||||
|
|
@ -357,6 +359,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
|
||||
|
|
@ -802,14 +827,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); }
|
||||
|
|
@ -1190,11 +1215,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); }
|
||||
|
|
@ -1359,7 +1384,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);
|
||||
|
|
|
|||
80
kernel/io.cc
80
kernel/io.cc
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef YOSYS_COMMON_H
|
||||
#define YOSYS_COMMON_H
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -598,6 +598,8 @@ struct RenamePass : public Pass {
|
|||
|
||||
for (auto &it : new_cell_names)
|
||||
module->rename(it.first, it.second);
|
||||
|
||||
module->fixup_ports();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "kernel/celltypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
|
@ -291,14 +293,14 @@ struct OptMuxtreeWorker
|
|||
// 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;
|
||||
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)
|
||||
|
|
@ -315,17 +317,18 @@ struct OptMuxtreeWorker
|
|||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
|
||||
++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig];
|
||||
}
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
|
||||
++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig];
|
||||
|
||||
vector<int> parent_muxes;
|
||||
for (int m : muxinfo.ports[port_idx].input_muxes) {
|
||||
if (knowledge.visited_muxes[m])
|
||||
auto it = knowledge.visited_muxes.find(m);
|
||||
if (it != knowledge.visited_muxes.end())
|
||||
continue;
|
||||
knowledge.visited_muxes[m] = true;
|
||||
knowledge.visited_muxes.insert(it, m);
|
||||
parent_muxes.push_back(m);
|
||||
}
|
||||
for (int m : parent_muxes) {
|
||||
|
|
@ -344,16 +347,24 @@ struct OptMuxtreeWorker
|
|||
return;
|
||||
}
|
||||
for (int m : parent_muxes)
|
||||
knowledge.visited_muxes[m] = false;
|
||||
knowledge.visited_muxes.erase(m);
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) {
|
||||
auto it = knowledge.known_active.find(muxinfo.ports[port_idx].ctrl_sig);
|
||||
if (it != knowledge.known_active.end())
|
||||
if (--it->second == 0)
|
||||
knowledge.known_active.erase(it);
|
||||
}
|
||||
|
||||
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)--;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0) {
|
||||
auto it = knowledge.known_inactive.find(muxinfo.ports[i].ctrl_sig);
|
||||
if (it != knowledge.known_inactive.end())
|
||||
if (--it->second == 0)
|
||||
knowledge.known_inactive.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,11 +384,11 @@ struct OptMuxtreeWorker
|
|||
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;
|
||||
}
|
||||
|
|
@ -435,7 +446,7 @@ struct OptMuxtreeWorker
|
|||
portinfo_t &portinfo = muxinfo.ports[port_idx];
|
||||
if (portinfo.const_deactivated)
|
||||
continue;
|
||||
if (knowledge.known_active.at(portinfo.ctrl_sig)) {
|
||||
if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) {
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
return;
|
||||
}
|
||||
|
|
@ -449,7 +460,7 @@ 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);
|
||||
|
||||
|
|
@ -462,10 +473,7 @@ struct OptMuxtreeWorker
|
|||
{
|
||||
log_assert(glob_abort_cnt > 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;
|
||||
knowledge.visited_muxes.insert(mux_idx);
|
||||
eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
20
setup.py
20
setup.py
|
|
@ -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")
|
||||
|
|
@ -87,6 +98,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"):
|
||||
|
|
@ -102,8 +114,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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue