mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-22 08:35:32 +00:00
Update Yosys
This commit is contained in:
commit
c0af4604bc
47 changed files with 5093 additions and 97 deletions
3
.github/actions/setup-build-env/action.yml
vendored
3
.github/actions/setup-build-env/action.yml
vendored
|
@ -14,7 +14,7 @@ runs:
|
|||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm
|
||||
|
||||
- name: Linux runtime environment
|
||||
if: runner.os == 'Linux'
|
||||
|
@ -28,6 +28,7 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm)/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
|
||||
|
|
3
Brewfile
3
Brewfile
|
@ -9,4 +9,5 @@ brew "python3"
|
|||
brew "tcl-tk"
|
||||
brew "xdot"
|
||||
brew "bash"
|
||||
brew 'boost-python3'
|
||||
brew "boost-python3"
|
||||
brew "llvm"
|
||||
|
|
|
@ -8,6 +8,7 @@ RUN apt-get update -qq \
|
|||
&& DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
|
||||
ca-certificates \
|
||||
clang \
|
||||
lld \
|
||||
curl \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
|
|
54
Makefile
54
Makefile
|
@ -34,6 +34,7 @@ ENABLE_GCOV := 0
|
|||
ENABLE_GPROF := 0
|
||||
ENABLE_DEBUG := 0
|
||||
ENABLE_NDEBUG := 1
|
||||
ENABLE_LTO := 1
|
||||
ENABLE_CCACHE := 0
|
||||
# sccache is not always a drop-in replacement for ccache in practice
|
||||
ENABLE_SCCACHE := 0
|
||||
|
@ -52,6 +53,11 @@ SANITIZER =
|
|||
# SANITIZER = undefined
|
||||
# SANITIZER = cfi
|
||||
|
||||
# Prefer using ENABLE_DEBUG over setting these
|
||||
OPT_LEVEL := -O3
|
||||
GCC_LTO :=
|
||||
CLANG_LTO := -flto=thin
|
||||
|
||||
PROGRAM_PREFIX :=
|
||||
|
||||
OS := $(shell uname -s)
|
||||
|
@ -147,7 +153,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.43+34
|
||||
YOSYS_VER := 0.43+86
|
||||
|
||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||
|
@ -211,10 +217,15 @@ ifeq ($(OS), OpenBSD)
|
|||
ABC_ARCHFLAGS += "-DABC_NO_RLIMIT"
|
||||
endif
|
||||
|
||||
# This gets overridden later.
|
||||
LTOFLAGS := $(GCC_LTO)
|
||||
|
||||
ifeq ($(CONFIG),clang)
|
||||
CXX = clang++
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
LINKFLAGS += -fuse-ld=lld
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
||||
LTOFLAGS := $(CLANG_LTO)
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
$(info [Clang Sanitizer] $(SANITIZER))
|
||||
|
@ -230,19 +241,20 @@ endif
|
|||
ifneq ($(findstring cfi,$(SANITIZER)),)
|
||||
CXXFLAGS += -flto
|
||||
LINKFLAGS += -flto
|
||||
LTOFLAGS =
|
||||
endif
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),gcc)
|
||||
CXX = g++
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
||||
|
||||
else ifeq ($(CONFIG),gcc-static)
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -static
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(CXX)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \
|
||||
ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1
|
||||
ifeq ($(DISABLE_ABC_THREADS),1)
|
||||
|
@ -251,12 +263,12 @@ endif
|
|||
|
||||
else ifeq ($(CONFIG),afl-gcc)
|
||||
CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),cygwin)
|
||||
CXX = g++
|
||||
CXXFLAGS += -std=gnu++11 -Os
|
||||
CXXFLAGS += -std=gnu++11 $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),wasi)
|
||||
|
@ -271,7 +283,7 @@ AR = $(WASI_SDK)/bin/ar
|
|||
RANLIB = $(WASI_SDK)/bin/ranlib
|
||||
WASIFLAGS := --sysroot $(WASI_SDK)/share/wasi-sysroot $(WASIFLAGS)
|
||||
endif
|
||||
CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS))
|
||||
CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS))
|
||||
LIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LIBS))
|
||||
ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)"
|
||||
|
@ -289,7 +301,7 @@ endif
|
|||
else ifeq ($(CONFIG),mxe)
|
||||
PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
|
@ -300,7 +312,7 @@ EXE = .exe
|
|||
|
||||
else ifeq ($(CONFIG),msys2-32)
|
||||
CXX = i686-w64-mingw32-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
|
@ -310,7 +322,7 @@ EXE = .exe
|
|||
|
||||
else ifeq ($(CONFIG),msys2-64)
|
||||
CXX = x86_64-w64-mingw32-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
|
@ -319,13 +331,20 @@ ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-
|
|||
EXE = .exe
|
||||
|
||||
else ifeq ($(CONFIG),none)
|
||||
CXXFLAGS += -std=$(CXXSTD) -Os
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
||||
LTOFLAGS =
|
||||
|
||||
else
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, mxe, msys2-32, msys2-64, none)
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(ENABLE_LTO),1)
|
||||
CXXFLAGS += $(LTOFLAGS)
|
||||
LINKFLAGS += $(LTOFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||
TARGETS += libyosys.so
|
||||
endif
|
||||
|
@ -447,16 +466,8 @@ CXXFLAGS += -pg
|
|||
LINKFLAGS += -pg
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_NDEBUG),1)
|
||||
CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os -ggdb,$(CXXFLAGS))
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_DEBUG),1)
|
||||
ifeq ($(CONFIG),clang)
|
||||
CXXFLAGS := -O0 -DDEBUG $(filter-out -Os,$(CXXFLAGS))
|
||||
else
|
||||
CXXFLAGS := -Og -DDEBUG $(filter-out -Os,$(CXXFLAGS))
|
||||
endif
|
||||
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
|
@ -631,7 +642,7 @@ $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h))
|
|||
|
||||
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
|
||||
OBJS += kernel/binding.o
|
||||
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o
|
||||
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o
|
||||
ifeq ($(ENABLE_ZLIB),1)
|
||||
OBJS += kernel/fstdata.o
|
||||
endif
|
||||
|
@ -875,6 +886,7 @@ endif
|
|||
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/microchip && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/rpc && bash run-test.sh
|
||||
+cd tests/memfile && bash run-test.sh
|
||||
+cd tests/verilog && bash run-test.sh
|
||||
|
|
|
@ -79,7 +79,7 @@ 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
|
||||
prerequisites for building yosys:
|
||||
|
||||
$ sudo apt-get install build-essential clang bison flex \
|
||||
$ sudo apt-get install build-essential clang lld 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
|
||||
|
|
|
@ -94,7 +94,7 @@ Installing all prerequisites for Ubuntu 20.04:
|
|||
|
||||
.. code:: console
|
||||
|
||||
sudo sudo apt-get install build-essential clang bison flex \
|
||||
sudo sudo apt-get install build-essential clang lld bison flex \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git make \
|
||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||
libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
yosys = pkgs.clangStdenv.mkDerivation {
|
||||
name = "yosys";
|
||||
src = ./. ;
|
||||
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream ];
|
||||
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream llvmPackages.bintools ];
|
||||
checkInputs = with pkgs; [ gtest ];
|
||||
propagatedBuildInputs = [ abc-verifier ];
|
||||
preConfigure = "make config-clang";
|
||||
|
@ -41,7 +41,7 @@
|
|||
packages.default = yosys;
|
||||
defaultPackage = yosys;
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ];
|
||||
buildInputs = with pkgs; [ clang llvmPackages.bintools bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
@ -59,6 +59,7 @@ USING_YOSYS_NAMESPACE
|
|||
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
#include "vhdl_file.h"
|
||||
#include "VhdlIdDef.h"
|
||||
#include "VhdlUnits.h"
|
||||
#include "NameSpace.h"
|
||||
#endif
|
||||
|
@ -2757,7 +2758,7 @@ void import_all(const char* work, std::map<std::string,Netlist*> *nl_todo, Map *
|
|||
#endif
|
||||
}
|
||||
|
||||
std::set<std::string> import_tops(const char* work, std::map<std::string,Netlist*> *nl_todo, Map *parameters, bool show_message, std::string ppfile YS_MAYBE_UNUSED, std::vector<std::string> &tops)
|
||||
std::set<std::string> import_tops(const char* work, std::map<std::string,Netlist*> *nl_todo, Map *parameters, bool show_message, std::string ppfile YS_MAYBE_UNUSED, std::vector<std::string> &tops, std::string *top = nullptr)
|
||||
{
|
||||
std::set<std::string> top_mod_names;
|
||||
Array *netlists = nullptr;
|
||||
|
@ -2815,6 +2816,12 @@ std::set<std::string> import_tops(const char* work, std::map<std::string,Netlist
|
|||
if (show_message)
|
||||
log("Adding VHDL unit '%s' to elaboration queue.\n", name);
|
||||
vhdl_units.InsertLast(vhdl_unit);
|
||||
if (strcmp(name, vhdl_unit->Id()->OrigName()) != 0) {
|
||||
top_mod_names.erase(name);
|
||||
top_mod_names.insert(vhdl_unit->Id()->OrigName());
|
||||
if (top && *top == name)
|
||||
*top = vhdl_unit->Id()->OrigName();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
@ -2955,7 +2962,7 @@ std::string verific_import(Design *design, const std::map<std::string,std::strin
|
|||
veri_file::RemoveAllLOptions();
|
||||
veri_file::AddLOption("work");
|
||||
#endif
|
||||
top_mod_names = import_tops("work", &nl_todo, &verific_params, false, "", tops) ;
|
||||
top_mod_names = import_tops("work", &nl_todo, &verific_params, false, "", tops, &top) ;
|
||||
}
|
||||
|
||||
if (!verific_error_msg.empty())
|
||||
|
@ -3041,6 +3048,11 @@ bool check_noverific_env()
|
|||
|
||||
struct VerificPass : public Pass {
|
||||
VerificPass() : Pass("import", "load Verilog/SystemVerilog designs using IMPORT") { }
|
||||
|
||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||
void on_register() override { VerificExtensions::Reset(); }
|
||||
#endif
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
|
|
195
kernel/cost.cc
Normal file
195
kernel/cost.cc
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "kernel/cost.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
unsigned int CellCosts::get(RTLIL::Module *mod)
|
||||
{
|
||||
if (mod_cost_cache_.count(mod->name))
|
||||
return mod_cost_cache_.at(mod->name);
|
||||
|
||||
unsigned int module_cost = 1;
|
||||
for (auto c : mod->cells()) {
|
||||
unsigned int new_cost = module_cost + get(c);
|
||||
module_cost = new_cost >= module_cost ? new_cost : INT_MAX;
|
||||
}
|
||||
|
||||
mod_cost_cache_[mod->name] = module_cost;
|
||||
return module_cost;
|
||||
}
|
||||
|
||||
static unsigned int y_coef(RTLIL::IdString type)
|
||||
{
|
||||
if (
|
||||
// equality
|
||||
type.in(ID($bweqx), ID($nex), ID($eqx)) ||
|
||||
// basic logic
|
||||
type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($not)) ||
|
||||
// mux
|
||||
type.in(ID($bwmux), ID($mux)) ||
|
||||
// others
|
||||
type == ID($tribuf)) {
|
||||
return 1;
|
||||
} else if (type == ID($neg)) {
|
||||
return 4;
|
||||
} else if (type == ID($demux)) {
|
||||
return 2;
|
||||
} else if (type == ID($fa)) {
|
||||
return 5;
|
||||
} else if (type.in(ID($add), ID($sub), ID($alu))) {
|
||||
// multi-bit adders
|
||||
return 8;
|
||||
} else if (type.in(ID($shl), ID($sshl))) {
|
||||
// left shift
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int max_inp_coef(RTLIL::IdString type)
|
||||
{
|
||||
if (
|
||||
// binop reduce
|
||||
type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)) ||
|
||||
// others
|
||||
type.in(ID($logic_not), ID($pmux), ID($bmux))) {
|
||||
return 1;
|
||||
} else if (
|
||||
// equality
|
||||
type.in(ID($eq), ID($ne)) ||
|
||||
// logic
|
||||
type.in(ID($logic_and), ID($logic_or))) {
|
||||
return 2;
|
||||
} else if (type == ID($lcu)) {
|
||||
return 5;
|
||||
} else if (type.in(ID($lt), ID($le), ID($ge), ID($gt))) {
|
||||
// comparison
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int sum_coef(RTLIL::IdString type)
|
||||
{
|
||||
if (type.in(ID($shr), ID($sshr))) {
|
||||
// right shift
|
||||
return 4;
|
||||
} else if (type.in(ID($shift), ID($shiftx))) {
|
||||
// shift
|
||||
return 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int is_div_mod(RTLIL::IdString type)
|
||||
{
|
||||
return (type == ID($div) || type == ID($divfloor) || type == ID($mod) || type == ID($modfloor));
|
||||
}
|
||||
|
||||
static bool is_free(RTLIL::IdString type)
|
||||
{
|
||||
return (
|
||||
// tags
|
||||
type.in(ID($overwrite_tag), ID($set_tag), ID($original_tag), ID($get_tag)) ||
|
||||
// formal
|
||||
type.in(ID($check), ID($equiv), ID($initstate), ID($assert), ID($assume), ID($live), ID($cover), ID($fair)) ||
|
||||
type.in(ID($allseq), ID($allconst), ID($anyseq), ID($anyconst), ID($anyinit)) ||
|
||||
// utilities
|
||||
type.in(ID($scopeinfo), ID($print)) ||
|
||||
// real but free
|
||||
type.in(ID($concat), ID($slice), ID($pos)) ||
|
||||
// specify
|
||||
type.in(ID($specrule), ID($specify2), ID($specify3)));
|
||||
}
|
||||
|
||||
unsigned int max_inp_width(RTLIL::Cell *cell)
|
||||
{
|
||||
unsigned int max = 0;
|
||||
RTLIL::IdString input_width_params[] = {
|
||||
ID::WIDTH,
|
||||
ID::A_WIDTH,
|
||||
ID::B_WIDTH,
|
||||
ID::S_WIDTH,
|
||||
};
|
||||
|
||||
if (cell->type == ID($bmux))
|
||||
return cell->getParam(ID::WIDTH).as_int() << cell->getParam(ID::S_WIDTH).as_int();
|
||||
|
||||
for (RTLIL::IdString param : input_width_params)
|
||||
if (cell->hasParam(param))
|
||||
max = std::max(max, (unsigned int)cell->getParam(param).as_int());
|
||||
return max;
|
||||
}
|
||||
|
||||
unsigned int port_width_sum(RTLIL::Cell *cell)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
RTLIL::IdString port_width_params[] = {
|
||||
ID::WIDTH, ID::A_WIDTH, ID::B_WIDTH, ID::S_WIDTH, ID::Y_WIDTH,
|
||||
};
|
||||
|
||||
for (auto param : port_width_params)
|
||||
if (cell->hasParam(param))
|
||||
sum += cell->getParam(param).as_int();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
unsigned int CellCosts::get(RTLIL::Cell *cell)
|
||||
{
|
||||
|
||||
// simple 1-bit cells
|
||||
if (cmos_gate_cost().count(cell->type))
|
||||
return 1;
|
||||
|
||||
if (design_ && design_->module(cell->type) && cell->parameters.empty()) {
|
||||
log_debug("%s is a module, recurse\n", cell->name.c_str());
|
||||
return get(design_->module(cell->type));
|
||||
} else if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
log_assert(cell->hasPort(ID::Q) && "Weird flip flop");
|
||||
log_debug("%s is ff\n", cell->name.c_str());
|
||||
return cell->getParam(ID::WIDTH).as_int();
|
||||
} else if (y_coef(cell->type)) {
|
||||
// linear with Y_WIDTH or WIDTH
|
||||
log_assert((cell->hasParam(ID::Y_WIDTH) || cell->hasParam(ID::WIDTH)) && "Unknown width");
|
||||
auto param = cell->hasParam(ID::Y_WIDTH) ? ID::Y_WIDTH : ID::WIDTH;
|
||||
int width = cell->getParam(param).as_int();
|
||||
if (cell->type == ID($demux))
|
||||
width <<= cell->getParam(ID::S_WIDTH).as_int();
|
||||
log_debug("%s Y*coef %d * %d\n", cell->name.c_str(), width, y_coef(cell->type));
|
||||
return width * y_coef(cell->type);
|
||||
} else if (sum_coef(cell->type)) {
|
||||
// linear with sum of port widths
|
||||
unsigned int sum = port_width_sum(cell);
|
||||
log_debug("%s sum*coef %d * %d\n", cell->name.c_str(), sum, sum_coef(cell->type));
|
||||
return sum * sum_coef(cell->type);
|
||||
} else if (max_inp_coef(cell->type)) {
|
||||
// linear with largest input width
|
||||
unsigned int max = max_inp_width(cell);
|
||||
log_debug("%s max*coef %d * %d\n", cell->name.c_str(), max, max_inp_coef(cell->type));
|
||||
return max * max_inp_coef(cell->type);
|
||||
} else if (is_div_mod(cell->type) || cell->type == ID($mul)) {
|
||||
// quadratic with sum of port widths
|
||||
unsigned int sum = port_width_sum(cell);
|
||||
unsigned int coef = cell->type == ID($mul) ? 3 : 5;
|
||||
log_debug("%s coef*(sum**2) %d * %d\n", cell->name.c_str(), coef, sum * sum);
|
||||
return coef * sum * sum;
|
||||
} else if (cell->type == ID($lut)) {
|
||||
int width = cell->getParam(ID::WIDTH).as_int();
|
||||
unsigned int cost = 1U << (unsigned int)width;
|
||||
log_debug("%s is 2**%d\n", cell->name.c_str(), width);
|
||||
return cost;
|
||||
} else if (cell->type == ID($sop)) {
|
||||
int width = cell->getParam(ID::WIDTH).as_int();
|
||||
int depth = cell->getParam(ID::DEPTH).as_int();
|
||||
log_debug("%s is (2*%d + 1)*%d\n", cell->name.c_str(), width, depth);
|
||||
return (2 * width + 1) * depth;
|
||||
} else if (is_free(cell->type)) {
|
||||
log_debug("%s is free\n", cell->name.c_str());
|
||||
return 0;
|
||||
}
|
||||
// TODO: $fsm $mem.* $macc
|
||||
// ignored: $pow
|
||||
|
||||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
|
||||
return 1;
|
||||
}
|
|
@ -26,7 +26,17 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct CellCosts
|
||||
{
|
||||
|
||||
private:
|
||||
dict<RTLIL::IdString, int> mod_cost_cache_;
|
||||
Design *design_ = nullptr;
|
||||
|
||||
public:
|
||||
CellCosts(RTLIL::Design *design) : design_(design) { }
|
||||
|
||||
static const dict<RTLIL::IdString, int>& default_gate_cost() {
|
||||
// Default size heuristics for several common PDK standard cells
|
||||
// used by abc and stat
|
||||
static const dict<RTLIL::IdString, int> db = {
|
||||
{ ID($_BUF_), 1 },
|
||||
{ ID($_NOT_), 2 },
|
||||
|
@ -43,12 +53,14 @@ struct CellCosts
|
|||
{ ID($_AOI4_), 7 },
|
||||
{ ID($_OAI4_), 7 },
|
||||
{ ID($_MUX_), 4 },
|
||||
{ ID($_NMUX_), 4 }
|
||||
{ ID($_NMUX_), 4 },
|
||||
};
|
||||
return db;
|
||||
}
|
||||
|
||||
static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
|
||||
// Estimated CMOS transistor counts for several common PDK standard cells
|
||||
// used by stat and optionally by abc
|
||||
static const dict<RTLIL::IdString, int> db = {
|
||||
{ ID($_BUF_), 1 },
|
||||
{ ID($_NOT_), 2 },
|
||||
|
@ -65,50 +77,21 @@ struct CellCosts
|
|||
{ ID($_AOI4_), 8 },
|
||||
{ ID($_OAI4_), 8 },
|
||||
{ ID($_MUX_), 12 },
|
||||
{ ID($_NMUX_), 10 }
|
||||
{ ID($_NMUX_), 10 },
|
||||
{ ID($_DFF_P_), 16 },
|
||||
{ ID($_DFF_N_), 16 },
|
||||
};
|
||||
return db;
|
||||
}
|
||||
|
||||
dict<RTLIL::IdString, int> mod_cost_cache;
|
||||
const dict<RTLIL::IdString, int> *gate_cost = nullptr;
|
||||
Design *design = nullptr;
|
||||
|
||||
int get(RTLIL::IdString type) const
|
||||
{
|
||||
if (gate_cost && gate_cost->count(type))
|
||||
return gate_cost->at(type);
|
||||
|
||||
log_warning("Can't determine cost of %s cell.\n", log_id(type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get(RTLIL::Cell *cell)
|
||||
{
|
||||
if (gate_cost && gate_cost->count(cell->type))
|
||||
return gate_cost->at(cell->type);
|
||||
|
||||
if (design && design->module(cell->type) && cell->parameters.empty())
|
||||
{
|
||||
RTLIL::Module *mod = design->module(cell->type);
|
||||
|
||||
if (mod->attributes.count(ID(cost)))
|
||||
return mod->attributes.at(ID(cost)).as_int();
|
||||
|
||||
if (mod_cost_cache.count(mod->name))
|
||||
return mod_cost_cache.at(mod->name);
|
||||
|
||||
int module_cost = 1;
|
||||
for (auto c : mod->cells())
|
||||
module_cost += get(c);
|
||||
|
||||
mod_cost_cache[mod->name] = module_cost;
|
||||
return module_cost;
|
||||
}
|
||||
|
||||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
|
||||
return 1;
|
||||
}
|
||||
// Get the cell cost for a cell based on its parameters.
|
||||
// This cost is an *approximate* upper bound for the number of gates that
|
||||
// the cell will get mapped to with "opt -fast; techmap"
|
||||
// The intended usage is for flattening heuristics and similar situations
|
||||
unsigned int get(RTLIL::Cell *cell);
|
||||
// Sum up the cell costs of all cells in the module
|
||||
// and all its submodules recursively
|
||||
unsigned int get(RTLIL::Module *mod);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -188,6 +188,7 @@ inline unsigned int mkhash(const T &v) {
|
|||
|
||||
inline int hashtable_size(int min_size)
|
||||
{
|
||||
// Primes as generated by https://oeis.org/A175953
|
||||
static std::vector<int> zero_and_some_primes = {
|
||||
0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
|
||||
853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
|
||||
|
@ -196,7 +197,9 @@ inline int hashtable_size(int min_size)
|
|||
897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
|
||||
5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
|
||||
25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217,
|
||||
463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113,
|
||||
1769372713
|
||||
};
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
|
@ -1129,6 +1132,11 @@ public:
|
|||
const_iterator end() const { return const_iterator(*this, offset + size()); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Union-find data structure with a promotion method
|
||||
* mfp stands for "merge, find, promote"
|
||||
* i-prefixed methods operate on indices in parents
|
||||
*/
|
||||
template<typename K, typename OPS>
|
||||
class mfp
|
||||
{
|
||||
|
@ -1142,13 +1150,18 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
// Finds a given element's index. If it isn't in the data structure,
|
||||
// it is added as its own set
|
||||
int operator()(const K &key) const
|
||||
{
|
||||
int i = database(key);
|
||||
// If the lookup caused the database to grow,
|
||||
// also add a corresponding entry in parents initialized to -1 (no parent)
|
||||
parents.resize(database.size(), -1);
|
||||
return i;
|
||||
}
|
||||
|
||||
// Finds an element at given index
|
||||
const K &operator[](int index) const
|
||||
{
|
||||
return database[index];
|
||||
|
@ -1161,6 +1174,11 @@ public:
|
|||
while (parents[p] != -1)
|
||||
p = parents[p];
|
||||
|
||||
// p is now the representative of i
|
||||
// Now we traverse from i up to the representative again
|
||||
// and make p the parent of all the nodes along the way.
|
||||
// This is a side effect and doesn't affect the return value.
|
||||
// It speeds up future find operations
|
||||
while (k != p) {
|
||||
int next_k = parents[k];
|
||||
parents[k] = p;
|
||||
|
@ -1170,6 +1188,7 @@ public:
|
|||
return p;
|
||||
}
|
||||
|
||||
// Merge sets if the given indices belong to different sets
|
||||
void imerge(int i, int j)
|
||||
{
|
||||
i = ifind(i);
|
||||
|
|
|
@ -229,6 +229,13 @@ 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>> {};
|
||||
|
||||
/**
|
||||
* SigMap wraps a union-find "database"
|
||||
* to map SigBits of a module to canonical representative SigBits.
|
||||
* SigBits that are connected share a set in the underlying database.
|
||||
* If a SigBit has a const state (impl: bit.wire is nullptr),
|
||||
* it's promoted to a representative.
|
||||
*/
|
||||
struct SigMap
|
||||
{
|
||||
mfp<SigBit> database;
|
||||
|
@ -249,6 +256,7 @@ struct SigMap
|
|||
database.clear();
|
||||
}
|
||||
|
||||
// Rebuild SigMap for all connections in module
|
||||
void set(RTLIL::Module *module)
|
||||
{
|
||||
int bitcount = 0;
|
||||
|
@ -262,6 +270,7 @@ struct SigMap
|
|||
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));
|
||||
|
@ -287,6 +296,7 @@ struct SigMap
|
|||
}
|
||||
}
|
||||
|
||||
// Add sig as disconnected from anything
|
||||
void add(const RTLIL::SigBit &bit)
|
||||
{
|
||||
const auto &b = database.find(bit);
|
||||
|
@ -302,6 +312,7 @@ 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);
|
||||
|
@ -332,6 +343,7 @@ struct SigMap
|
|||
return sig;
|
||||
}
|
||||
|
||||
// All non-const bits
|
||||
RTLIL::SigSpec allbits() const
|
||||
{
|
||||
RTLIL::SigSpec sig;
|
||||
|
|
|
@ -289,8 +289,6 @@ struct statdata_t
|
|||
|
||||
if (gate_costs.count(ctype))
|
||||
tran_cnt += cnum * gate_costs.at(ctype);
|
||||
else if (ctype.in(ID($_DFF_P_), ID($_DFF_N_)))
|
||||
tran_cnt += cnum * 16;
|
||||
else
|
||||
*tran_cnt_exact = false;
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
OBJS += passes/hierarchy/hierarchy.o
|
||||
OBJS += passes/hierarchy/uniquify.o
|
||||
OBJS += passes/hierarchy/submod.o
|
||||
OBJS += passes/hierarchy/keep_hierarchy.o
|
||||
|
||||
|
|
74
passes/hierarchy/keep_hierarchy.cc
Normal file
74
passes/hierarchy/keep_hierarchy.cc
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.h"
|
||||
#include "kernel/cost.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct KeepHierarchyPass : public Pass {
|
||||
KeepHierarchyPass() : Pass("keep_hierarchy", "add the keep_hierarchy attribute") {}
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" keep_hierarchy [options]\n");
|
||||
log("\n");
|
||||
log("Add the keep_hierarchy attribute.\n");
|
||||
log("\n");
|
||||
log(" -min_cost <min_cost>\n");
|
||||
log(" only add the attribute to modules estimated to have more\n");
|
||||
log(" than <min_cost> gates after simple techmapping. Intended\n");
|
||||
log(" for tuning trade-offs between quality and yosys runtime.\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
unsigned int min_cost = 0;
|
||||
|
||||
log_header(design, "Executing KEEP_HIERARCHY pass.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-min_cost" && argidx+1 < args.size()) {
|
||||
min_cost = std::stoi(args[++argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
CellCosts costs(design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
if (min_cost) {
|
||||
unsigned int cost = costs.get(module);
|
||||
if (cost > min_cost) {
|
||||
log("Marking %s (module too big: %d > %d).\n", log_id(module), cost, min_cost);
|
||||
module->set_bool_attribute(ID::keep_hierarchy);
|
||||
}
|
||||
} else {
|
||||
log("Marking %s.\n", log_id(module));
|
||||
module->set_bool_attribute(ID::keep_hierarchy);
|
||||
}
|
||||
}
|
||||
}
|
||||
} KeepHierarchyPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -37,6 +37,17 @@ $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
|
|||
|
||||
# --------------------------------------
|
||||
|
||||
OBJS += passes/pmgen/microchip_dsp.o
|
||||
GENFILES += passes/pmgen/microchip_dsp_pm.h
|
||||
GENFILES += passes/pmgen/microchip_dsp_CREG_pm.h
|
||||
GENFILES += passes/pmgen/microchip_dsp_cascade_pm.h
|
||||
passes/pmgen/microchip_dsp.o: passes/pmgen/microchip_dsp_pm.h passes/pmgen/microchip_dsp_CREG_pm.h passes/pmgen/microchip_dsp_cascade_pm.h
|
||||
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_pm.h))
|
||||
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_CREG_pm.h))
|
||||
$(eval $(call add_extra_objs,passes/pmgen/microchip_dsp_cascade_pm.h))
|
||||
|
||||
# --------------------------------------
|
||||
|
||||
OBJS += passes/pmgen/peepopt.o
|
||||
GENFILES += passes/pmgen/peepopt_pm.h
|
||||
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
|
||||
|
|
362
passes/pmgen/microchip_dsp.cc
Normal file
362
passes/pmgen/microchip_dsp.cc
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include <deque>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#include "passes/pmgen/microchip_dsp_CREG_pm.h"
|
||||
#include "passes/pmgen/microchip_dsp_cascade_pm.h"
|
||||
#include "passes/pmgen/microchip_dsp_pm.h"
|
||||
|
||||
void microchip_dsp_pack(microchip_dsp_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_microchip_dsp_pack;
|
||||
|
||||
log("Analysing %s.%s for Microchip MACC_PA packing.\n", log_id(pm.module), log_id(st.dsp));
|
||||
|
||||
Cell *cell = st.dsp;
|
||||
// pack pre-adder
|
||||
if (st.preAdderStatic) {
|
||||
SigSpec &pasub = cell->connections_.at(ID(PASUB));
|
||||
log(" static PASUB preadder %s (%s)\n", log_id(st.preAdderStatic), log_id(st.preAdderStatic->type));
|
||||
bool D_SIGNED = st.preAdderStatic->getParam(ID::B_SIGNED).as_bool();
|
||||
bool B_SIGNED = st.preAdderStatic->getParam(ID::A_SIGNED).as_bool();
|
||||
st.sigB.extend_u0(18, B_SIGNED);
|
||||
st.sigD.extend_u0(18, D_SIGNED);
|
||||
if (st.moveBtoA) {
|
||||
cell->setPort(ID::A, st.sigA); // if pre-adder feeds into A, original sigB will be moved to port A
|
||||
}
|
||||
cell->setPort(ID::B, st.sigB);
|
||||
cell->setPort(ID::D, st.sigD);
|
||||
// MACC_PA supports both addition and subtraction with the pre-adder.
|
||||
// Affects the sign of the 'D' port.
|
||||
if (st.preAdderStatic->type == ID($add))
|
||||
pasub[0] = State::S0;
|
||||
else if (st.preAdderStatic->type == ID($sub))
|
||||
pasub[0] = State::S1;
|
||||
else
|
||||
log_assert(!"strange pre-adder type");
|
||||
|
||||
pm.autoremove(st.preAdderStatic);
|
||||
}
|
||||
// pack post-adder
|
||||
if (st.postAdderStatic) {
|
||||
log(" postadder %s (%s)\n", log_id(st.postAdderStatic), log_id(st.postAdderStatic->type));
|
||||
SigSpec &sub = cell->connections_.at(ID(SUB));
|
||||
// Post-adder in MACC_PA also supports subtraction
|
||||
// Determines the sign of the output from the multiplier.
|
||||
if (st.postAdderStatic->type == ID($add))
|
||||
sub[0] = State::S0;
|
||||
else if (st.postAdderStatic->type == ID($sub))
|
||||
sub[0] = State::S1;
|
||||
else
|
||||
log_assert(!"strange post-adder type");
|
||||
|
||||
if (st.useFeedBack) {
|
||||
cell->setPort(ID(CDIN_FDBK_SEL), {State::S0, State::S1});
|
||||
} else {
|
||||
st.sigC.extend_u0(48, st.postAdderStatic->getParam(ID::A_SIGNED).as_bool());
|
||||
cell->setPort(ID::C, st.sigC);
|
||||
}
|
||||
|
||||
pm.autoremove(st.postAdderStatic);
|
||||
}
|
||||
|
||||
// pack registers
|
||||
if (st.clock != SigBit()) {
|
||||
cell->setPort(ID::CLK, st.clock);
|
||||
|
||||
// function to absorb a register
|
||||
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
|
||||
// input/output ports
|
||||
SigSpec D = ff->getPort(ID::D);
|
||||
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
|
||||
|
||||
if (!A.empty())
|
||||
A.replace(Q, D);
|
||||
if (rstport != IdString()) {
|
||||
if (ff->type.in(ID($sdff), ID($sdffe))) {
|
||||
SigSpec srst = ff->getPort(ID::SRST);
|
||||
bool rstpol_n = !ff->getParam(ID::SRST_POLARITY).as_bool();
|
||||
// active low sync rst
|
||||
cell->setPort(rstport, rstpol_n ? srst : pm.module->Not(NEW_ID, srst));
|
||||
} else if (ff->type.in(ID($adff), ID($adffe))) {
|
||||
SigSpec arst = ff->getPort(ID::ARST);
|
||||
bool rstpol_n = !ff->getParam(ID::ARST_POLARITY).as_bool();
|
||||
// active low async rst
|
||||
cell->setPort(rstport, rstpol_n ? arst : pm.module->Not(NEW_ID, arst));
|
||||
} else {
|
||||
// active low async/sync rst
|
||||
cell->setPort(rstport, State::S1);
|
||||
}
|
||||
}
|
||||
if (ff->type.in(ID($dffe), ID($sdffe), ID($adffe))) {
|
||||
SigSpec ce = ff->getPort(ID::EN);
|
||||
bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
|
||||
// enables are all active high
|
||||
cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
|
||||
} else {
|
||||
// enables are all active high
|
||||
cell->setPort(ceport, State::S1);
|
||||
}
|
||||
|
||||
// bypass set to 0
|
||||
cell->setPort(bypass, State::S0);
|
||||
|
||||
for (auto c : Q.chunks()) {
|
||||
auto it = c.wire->attributes.find(ID::init);
|
||||
if (it == c.wire->attributes.end())
|
||||
continue;
|
||||
for (int i = c.offset; i < c.offset + c.width; i++) {
|
||||
log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
|
||||
it->second[i] = State::Sx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: flops are not autoremoved because it is possible that they
|
||||
// are only partially absorbed into DSP, or have fanouts.
|
||||
if (st.ffA) {
|
||||
SigSpec A = cell->getPort(ID::A);
|
||||
if (st.ffA) {
|
||||
f(A, st.ffA, ID(A_EN), ID(A_SRST_N), ID(A_BYPASS));
|
||||
}
|
||||
pm.add_siguser(A, cell);
|
||||
cell->setPort(ID::A, A);
|
||||
}
|
||||
if (st.ffB) {
|
||||
SigSpec B = cell->getPort(ID::B);
|
||||
if (st.ffB) {
|
||||
f(B, st.ffB, ID(B_EN), ID(B_SRST_N), ID(B_BYPASS));
|
||||
}
|
||||
pm.add_siguser(B, cell);
|
||||
cell->setPort(ID::B, B);
|
||||
}
|
||||
if (st.ffD) {
|
||||
SigSpec D = cell->getPort(ID::D);
|
||||
if (st.ffD->type.in(ID($adff), ID($adffe))) {
|
||||
f(D, st.ffD, ID(D_EN), ID(D_ARST_N), ID(D_BYPASS));
|
||||
} else {
|
||||
f(D, st.ffD, ID(D_EN), ID(D_SRST_N), ID(D_BYPASS));
|
||||
}
|
||||
|
||||
pm.add_siguser(D, cell);
|
||||
cell->setPort(ID::D, D);
|
||||
}
|
||||
if (st.ffP) {
|
||||
SigSpec P; // unused
|
||||
f(P, st.ffP, ID(P_EN), ID(P_SRST_N), ID(P_BYPASS));
|
||||
st.ffP->connections_.at(ID::Q).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP)));
|
||||
}
|
||||
|
||||
log(" clock: %s (%s)\n", log_signal(st.clock), "posedge");
|
||||
|
||||
if (st.ffA)
|
||||
log(" \t ffA:%s\n", log_id(st.ffA));
|
||||
if (st.ffB)
|
||||
log(" \t ffB:%s\n", log_id(st.ffB));
|
||||
if (st.ffD)
|
||||
log(" \t ffD:%s\n", log_id(st.ffD));
|
||||
if (st.ffP)
|
||||
log(" \t ffP:%s\n", log_id(st.ffP));
|
||||
}
|
||||
log("\n");
|
||||
|
||||
SigSpec P = st.sigP;
|
||||
if (GetSize(P) < 48)
|
||||
P.append(pm.module->addWire(NEW_ID, 48 - GetSize(P)));
|
||||
cell->setPort(ID::P, P);
|
||||
|
||||
pm.blacklist(cell);
|
||||
}
|
||||
|
||||
// For packing cascaded DSPs
|
||||
void microchip_dsp_packC(microchip_dsp_CREG_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_microchip_dsp_packC;
|
||||
|
||||
log_debug("Analysing %s.%s for Microchip DSP packing (REG_C).\n", log_id(pm.module), log_id(st.dsp));
|
||||
log_debug("ffC: %s\n", log_id(st.ffC, "--"));
|
||||
|
||||
Cell *cell = st.dsp;
|
||||
|
||||
if (st.clock != SigBit()) {
|
||||
cell->setPort(ID::CLK, st.clock);
|
||||
|
||||
// same function as above, used for the last CREG we need to absorb
|
||||
auto f = [&pm, cell](SigSpec &A, Cell *ff, IdString ceport, IdString rstport, IdString bypass) {
|
||||
// input/output ports
|
||||
SigSpec D = ff->getPort(ID::D);
|
||||
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
|
||||
if (!A.empty())
|
||||
A.replace(Q, D);
|
||||
if (rstport != IdString()) {
|
||||
if (ff->type.in(ID($sdff), ID($sdffe))) {
|
||||
SigSpec srst = ff->getPort(ID::SRST);
|
||||
bool rstpol_n = !ff->getParam(ID::SRST_POLARITY).as_bool();
|
||||
// active low sync rst
|
||||
cell->setPort(rstport, rstpol_n ? srst : pm.module->Not(NEW_ID, srst));
|
||||
} else if (ff->type.in(ID($adff), ID($adffe))) {
|
||||
SigSpec arst = ff->getPort(ID::ARST);
|
||||
bool rstpol_n = !ff->getParam(ID::ARST_POLARITY).as_bool();
|
||||
// active low async rst
|
||||
cell->setPort(rstport, rstpol_n ? arst : pm.module->Not(NEW_ID, arst));
|
||||
} else {
|
||||
// active low async/sync rst
|
||||
cell->setPort(rstport, State::S1);
|
||||
}
|
||||
}
|
||||
if (ff->type.in(ID($dffe), ID($sdffe), ID($adffe))) {
|
||||
SigSpec ce = ff->getPort(ID::EN);
|
||||
bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
|
||||
// enables are all active high
|
||||
cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
|
||||
} else {
|
||||
// enables are all active high
|
||||
cell->setPort(ceport, State::S1);
|
||||
}
|
||||
|
||||
// bypass set to 0
|
||||
cell->setPort(bypass, State::S0);
|
||||
|
||||
for (auto c : Q.chunks()) {
|
||||
auto it = c.wire->attributes.find(ID::init);
|
||||
if (it == c.wire->attributes.end())
|
||||
continue;
|
||||
for (int i = c.offset; i < c.offset + c.width; i++) {
|
||||
log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
|
||||
it->second[i] = State::Sx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (st.ffC) {
|
||||
SigSpec C = cell->getPort(ID::C);
|
||||
|
||||
if (st.ffC->type.in(ID($adff), ID($adffe))) {
|
||||
f(C, st.ffC, ID(C_EN), ID(C_ARST_N), ID(C_BYPASS));
|
||||
} else {
|
||||
f(C, st.ffC, ID(C_EN), ID(C_SRST_N), ID(C_BYPASS));
|
||||
}
|
||||
pm.add_siguser(C, cell);
|
||||
cell->setPort(ID::C, C);
|
||||
}
|
||||
|
||||
log(" clock: %s (%s)", log_signal(st.clock), "posedge");
|
||||
|
||||
if (st.ffC)
|
||||
log(" ffC:%s", log_id(st.ffC));
|
||||
log("\n");
|
||||
}
|
||||
|
||||
pm.blacklist(cell);
|
||||
}
|
||||
|
||||
struct MicrochipDspPass : public Pass {
|
||||
MicrochipDspPass() : Pass("microchip_dsp", "MICROCHIP: pack resources into DSPs") {}
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" microchip_dsp [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Pack input registers 'A', 'B', 'C', and 'D' (with optional enable/reset),\n");
|
||||
log("output register 'P' (with optional enable/reset), pre-adder and/or post-adder into\n");
|
||||
log("Microchip DSP resources.\n");
|
||||
log("\n");
|
||||
log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n");
|
||||
log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n");
|
||||
log("used to override the current accumulation result with a new value. This will\n");
|
||||
log("be added to the multiplier result to form the next accumulation result.\n");
|
||||
log("\n");
|
||||
log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n");
|
||||
log("connections (optionally, where 'P' is right-shifted by 17-bits and used as an\n");
|
||||
log("input to the post-adder. This pattern is common for summing partial products to\n");
|
||||
log("implement wide multipliers). Cascade chains are limited to a mazimum length \n");
|
||||
log("of 24 cells, corresponding to PolarFire (pf) devices.\n");
|
||||
log("\n");
|
||||
log("This pass is a no-op if the scratchpad variable 'microchip_dsp.multonly' is set\n");
|
||||
log("to 1.\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log(" -family {polarfire}\n");
|
||||
log(" select the family to target\n");
|
||||
log(" default: polarfire\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing MICROCHIP_DSP pass (pack resources into DSPs).\n");
|
||||
|
||||
std::string family = "polarfire";
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if ((args[argidx] == "-family") && argidx + 1 < args.size()) {
|
||||
family = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
|
||||
if (design->scratchpad_get_bool("microchip_dsp.multonly"))
|
||||
continue;
|
||||
|
||||
{
|
||||
// For more details on PolarFire MACC_PA, consult
|
||||
// the "PolarFire FPGA Macro Library Guide"
|
||||
|
||||
// Main pattern matching step to capture a DSP cell.
|
||||
// Match for pre-adder, post-adder, as well as
|
||||
// registers 'A', 'B', 'D', and 'P'. Additionally,
|
||||
// check for an accumulator pattern based on whether
|
||||
// a post-adder and PREG are both present AND
|
||||
// if PREG feeds into this post-adder.
|
||||
microchip_dsp_pm pm(module, module->selected_cells());
|
||||
pm.run_microchip_dsp_pack(microchip_dsp_pack);
|
||||
}
|
||||
|
||||
// Separating out CREG packing is necessary since there
|
||||
// is no guarantee that the cell ordering corresponds
|
||||
// to the "expected" case (i.e. the order in which
|
||||
// they appear in the source). There existed the possibility
|
||||
// where a register got packed as a CREG into a
|
||||
// downstream DSP that should have otherwise been a
|
||||
// PREG of an upstream DSP that had not been visited
|
||||
// yet
|
||||
{
|
||||
microchip_dsp_CREG_pm pm(module, module->selected_cells());
|
||||
pm.run_microchip_dsp_packC(microchip_dsp_packC);
|
||||
}
|
||||
|
||||
// Lastly, identify and utilise PCOUT -> PCIN chains
|
||||
{
|
||||
microchip_dsp_cascade_pm pm(module, module->selected_cells());
|
||||
pm.run_microchip_dsp_cascade();
|
||||
}
|
||||
}
|
||||
}
|
||||
} MicrochipDspPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
439
passes/pmgen/microchip_dsp.pmg
Normal file
439
passes/pmgen/microchip_dsp.pmg
Normal file
|
@ -0,0 +1,439 @@
|
|||
// ISC License
|
||||
//
|
||||
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
// This file describes the main pattern matcher setup (of three total) that
|
||||
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||
// At a high level, it works as follows:
|
||||
// ( 1) Starting from a DSP cell. Capture DSP configurations as states
|
||||
// ( 2) Match for pre-adder
|
||||
// ( 3) Match for post-adder
|
||||
// ( 4) Match register 'A', 'B', 'D', 'P'
|
||||
// ( 5) If post-adder and PREG both present, check if PREG feeds into post-adder.
|
||||
// This indicates an accumulator situation like the ASCII diagram below:
|
||||
// +--------------------------------+
|
||||
// |_________ |
|
||||
// | /-------\ +----+ |
|
||||
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||
// |MULT|------ | adder | +----+
|
||||
// +----+ \-------/
|
||||
|
||||
pattern microchip_dsp_pack
|
||||
|
||||
state <SigBit> clock
|
||||
state <SigSpec> sigA sigB sigC sigD sigP
|
||||
state <Cell*> ffA ffB ffD ffP
|
||||
state <Cell*> preAdderStatic postAdderStatic
|
||||
state <bool> moveBtoA useFeedBack
|
||||
|
||||
// static ports, used to detect dsp configuration
|
||||
state <SigSpec> bypassA bypassB bypassC bypassD bypassP
|
||||
state <SigSpec> bypassPASUB
|
||||
|
||||
// Variables used for subpatterns
|
||||
state <SigSpec> argQ argD
|
||||
udata <bool> allowAsync
|
||||
udata <SigSpec> dffD dffQ
|
||||
udata <SigBit> dffclock
|
||||
udata <Cell*> dff
|
||||
udata <Cell*> u_preAdderStatic u_postAdderStatic
|
||||
udata <IdString> u_postAddAB
|
||||
state <IdString> postAddAB
|
||||
|
||||
// (1) Starting from a DSP cell
|
||||
match dsp
|
||||
select dsp->type.in(\MACC_PA)
|
||||
endmatch
|
||||
|
||||
// detect existing signals connected to DSP
|
||||
// detect configuration ports
|
||||
code sigA sigB sigC sigD clock sigP
|
||||
//helper function to remove unused bits
|
||||
auto unextend = [](const SigSpec &sig) {
|
||||
int i;
|
||||
for (i = GetSize(sig)-1; i > 0; i--)
|
||||
if (sig[i] != sig[i-1])
|
||||
break;
|
||||
// Do not remove non-const sign bit
|
||||
if (sig[i].wire)
|
||||
++i;
|
||||
return sig.extract(0, i);
|
||||
};
|
||||
|
||||
//unextend to remove unused bits
|
||||
sigA = unextend(port(dsp, \A));
|
||||
sigB = unextend(port(dsp, \B));
|
||||
|
||||
//update signals
|
||||
sigC = port(dsp, \C, SigSpec());
|
||||
sigD = port(dsp, \D, SigSpec());
|
||||
|
||||
|
||||
SigSpec P = port(dsp, \P);
|
||||
// Only care about bits that are used
|
||||
int i;
|
||||
for (i = GetSize(P)-1; i >= 0; i--)
|
||||
if (nusers(P[i]) > 1)
|
||||
break;
|
||||
i++;
|
||||
log_assert(nusers(P.extract_end(i)) <= 1);
|
||||
// This sigP could have no users if downstream sinks (e.g. $add) is
|
||||
// narrower than $mul result, for example
|
||||
if (i == 0)
|
||||
reject;
|
||||
sigP = P.extract(0, i);
|
||||
clock = port(dsp, \CLK, SigBit());
|
||||
|
||||
endcode
|
||||
|
||||
// capture static configuration ports
|
||||
code bypassA bypassB bypassC bypassD bypassPASUB bypassP
|
||||
bypassA = port(dsp, \A_BYPASS, SigSpec());
|
||||
bypassB = port(dsp, \B_BYPASS, SigSpec());
|
||||
bypassC = port(dsp, \C_BYPASS, SigSpec());
|
||||
bypassD = port(dsp, \D_BYPASS, SigSpec());
|
||||
bypassPASUB = port(dsp, \PASUB_BYPASS, SigSpec());
|
||||
bypassP = port(dsp, \P_BYPASS, SigSpec());
|
||||
endcode
|
||||
|
||||
// (2) Match for pre-adder
|
||||
//
|
||||
code sigA sigB sigD preAdderStatic moveBtoA
|
||||
subpattern(preAddMatching);
|
||||
preAdderStatic = u_preAdderStatic;
|
||||
moveBtoA = false;
|
||||
|
||||
if (preAdderStatic) {
|
||||
|
||||
if (port(preAdderStatic, \Y) == sigA)
|
||||
{
|
||||
//used for packing
|
||||
moveBtoA = true;
|
||||
|
||||
// sigA should be the input to the multiplier without the preAdd. sigB and sigD should be
|
||||
//the preAdd inputs. If our "A" input into the multiplier is from the preAdd (not sigA), then
|
||||
// we basically swap it.
|
||||
sigA = sigB;
|
||||
}
|
||||
|
||||
// port B of preAdderStatic must be mapped to port D of DSP for subtraction
|
||||
sigD = port(preAdderStatic, \B);
|
||||
sigB = port(preAdderStatic, \A);
|
||||
}
|
||||
endcode
|
||||
|
||||
// (3) Match for post-adder
|
||||
//
|
||||
code postAdderStatic sigP sigC
|
||||
u_postAdderStatic = nullptr;
|
||||
subpattern(postAddMatching);
|
||||
postAdderStatic = u_postAdderStatic;
|
||||
|
||||
if (postAdderStatic) {
|
||||
//sigC will be whichever input to the postAdder that is NOT from the multiplier
|
||||
// u_postAddAB is the input to the postAdder from the multiplier
|
||||
sigC = port(postAdderStatic, u_postAddAB == \A ? \B : \A);
|
||||
sigP = port(postAdderStatic, \Y);
|
||||
}
|
||||
endcode
|
||||
|
||||
|
||||
// (4) Matching registers
|
||||
//
|
||||
// 'A' input for REG_A
|
||||
code argQ bypassA sigA clock ffA
|
||||
if (bypassA.is_fully_ones()){
|
||||
argQ = sigA;
|
||||
allowAsync = false;
|
||||
subpattern(in_dffe);
|
||||
if (dff) {
|
||||
ffA = dff;
|
||||
clock = dffclock;
|
||||
sigA = dffD;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
// 'B' input for REG_B
|
||||
code argQ bypassB sigB clock ffB
|
||||
if (bypassB.is_fully_ones()){
|
||||
argQ = sigB;
|
||||
allowAsync = false;
|
||||
subpattern(in_dffe);
|
||||
if (dff) {
|
||||
ffB = dff;
|
||||
clock = dffclock;
|
||||
sigB = dffD;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
// 'D' input for REG_D
|
||||
code argQ bypassP sigD clock ffD
|
||||
if (bypassD.is_fully_ones()){
|
||||
argQ = sigD;
|
||||
allowAsync = true;
|
||||
subpattern(in_dffe);
|
||||
if (dff) {
|
||||
ffD = dff;
|
||||
clock = dffclock;
|
||||
sigD = dffD;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
// 'P' output for REG_P
|
||||
code argD ffP sigP clock bypassP
|
||||
if (bypassP.is_fully_ones() && nusers(sigP) == 2) {
|
||||
argD = sigP;
|
||||
allowAsync = false;
|
||||
subpattern(out_dffe);
|
||||
if (dff) {
|
||||
ffP = dff;
|
||||
clock = dffclock;
|
||||
sigP = dffQ;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
// (5) If post-adder and PREG both present, check if PREG feeds into post-adder via port C.
|
||||
// This indicates an accumulator situation. Port C can be freed
|
||||
// +--------------------------------+
|
||||
// |_________ |
|
||||
// | /-------\ +----+ |
|
||||
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||
// |MULT|------ | adder | +----+
|
||||
// +----+ \-------/
|
||||
code useFeedBack
|
||||
useFeedBack = false;
|
||||
if (postAdderStatic && ffP) {
|
||||
if (sigC == sigP) {
|
||||
useFeedBack = true;
|
||||
}
|
||||
}
|
||||
|
||||
endcode
|
||||
|
||||
// if any cells are absorbed, invoke the callback function
|
||||
code
|
||||
if (preAdderStatic || postAdderStatic)
|
||||
accept;
|
||||
if (ffA || ffB || ffD || ffP)
|
||||
accept;
|
||||
endcode
|
||||
|
||||
|
||||
// #######################
|
||||
// Subpattern for matching against post-adder
|
||||
// Match 'P' output that exclusively drives one of two inputs to an $add
|
||||
// cell (post-adder).
|
||||
// The other input to the adder is assumed to come in from the 'C' input
|
||||
|
||||
subpattern postAddMatching
|
||||
arg sigP
|
||||
|
||||
match postAdd
|
||||
|
||||
select postAdd->type.in($add, $sub)
|
||||
select GetSize(port(postAdd, \Y)) <= 48
|
||||
|
||||
// AB is the port that connects MUL to ADD
|
||||
choice <IdString> AB {\A, \B}
|
||||
select nusers(port(postAdd, AB)) == 2
|
||||
|
||||
// has one input coming from multiplier
|
||||
index <SigBit> port(postAdd, AB)[0] === sigP[0]
|
||||
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
|
||||
filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP
|
||||
// Check that remainder of AB is a sign- or zero-extension
|
||||
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) || port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(State::S0, GetSize(port(postAdd, AB))-GetSize(sigP))
|
||||
|
||||
set postAddAB AB
|
||||
// optional
|
||||
endmatch
|
||||
|
||||
code
|
||||
if (postAdd)
|
||||
{
|
||||
if (postAdd->type.in(ID($sub)) && postAddAB == \A) {
|
||||
// if $sub, the multiplier output must match to $sub.B, otherwise no match
|
||||
} else {
|
||||
u_postAddAB = postAddAB;
|
||||
u_postAdderStatic = postAdd;
|
||||
}
|
||||
|
||||
}
|
||||
endcode
|
||||
|
||||
|
||||
// #######################
|
||||
// Subpattern for matching against pre-adder
|
||||
// support static PASUB only
|
||||
|
||||
subpattern preAddMatching
|
||||
arg sigA sigB sigD bypassB bypassD bypassPASUB
|
||||
|
||||
code
|
||||
u_preAdderStatic = nullptr;
|
||||
|
||||
// Ensure that preAdder not already used
|
||||
// Assume we can inspect port D to see if its all zeros.
|
||||
if (!(sigD.empty() || sigD.is_fully_zero())) reject;
|
||||
if (!bypassB.is_fully_ones()) reject;
|
||||
if (!bypassD.is_fully_ones()) reject;
|
||||
if (!bypassPASUB.is_fully_ones()) reject;
|
||||
endcode
|
||||
|
||||
match preAdd
|
||||
|
||||
// can handle add or sub
|
||||
select preAdd->type.in($add, $sub)
|
||||
|
||||
// Output has to be 18 bits or less, and only has single fanout
|
||||
select GetSize(port(preAdd, \Y)) <= 18
|
||||
select nusers(port(preAdd, \Y)) == 2
|
||||
|
||||
// Adder inputs must be 18 bits or less
|
||||
select GetSize(port(preAdd, \A)) <= 18
|
||||
select GetSize(port(preAdd, \B)) <= 18
|
||||
|
||||
// Output feeds into one of multiplier input
|
||||
filter port(preAdd, \Y) == sigB || port(preAdd, \Y) == sigA
|
||||
|
||||
// optional
|
||||
endmatch
|
||||
|
||||
code
|
||||
if (preAdd)
|
||||
{
|
||||
u_preAdderStatic = preAdd;
|
||||
}
|
||||
endcode
|
||||
|
||||
// #######################
|
||||
// Subpattern for matching against input registers, based on knowledge of the
|
||||
// 'Q' input.
|
||||
subpattern in_dffe
|
||||
arg argQ clock
|
||||
|
||||
code
|
||||
dff = nullptr;
|
||||
if (argQ.empty())
|
||||
reject;
|
||||
for (const auto &c : argQ.chunks()) {
|
||||
// Abandon matches when 'Q' is a constant
|
||||
if (!c.wire)
|
||||
reject;
|
||||
// Abandon matches when 'Q' has the keep attribute set
|
||||
if (c.wire->get_bool_attribute(\keep))
|
||||
reject;
|
||||
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||
Const init = c.wire->attributes.at(\init, Const());
|
||||
if (!init.empty())
|
||||
for (auto b : init.extract(c.offset, c.width))
|
||||
if (b != State::Sx && b != State::S0)
|
||||
reject;
|
||||
}
|
||||
endcode
|
||||
|
||||
match ff
|
||||
// reg D has async rst
|
||||
// reg A, B has sync rst
|
||||
select ff->type.in($dff, $dffe, $sdff, $sdffe, $adff, $adffe)
|
||||
// does not support clock inversion
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
|
||||
// it is possible that only part of a dff output matches argQ
|
||||
slice offset GetSize(port(ff, \D))
|
||||
index <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||
|
||||
// Check that the rest of argQ is present
|
||||
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||
|
||||
// only consider async rst flops when flag is set
|
||||
filter !ff->type.in($adff, $adffe) || allowAsync
|
||||
|
||||
// clock must be consistent
|
||||
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||
endmatch
|
||||
|
||||
code argQ
|
||||
// Check that reset value, if present, is fully 0.
|
||||
bool noResetFlop = ff->type.in($dff, $dffe);
|
||||
bool srstZero = ff->type.in($sdff, $sdffe) && param(ff, \SRST_VALUE).is_fully_zero();
|
||||
bool arstZero = ff->type.in($adff, $adffe) && param(ff, \ARST_VALUE).is_fully_zero();
|
||||
bool resetLegal = noResetFlop || srstZero || arstZero;
|
||||
if (resetLegal)
|
||||
{
|
||||
SigSpec Q = port(ff, \Q);
|
||||
dff = ff;
|
||||
dffclock = port(ff, \CLK);
|
||||
dffD = argQ;
|
||||
SigSpec D = port(ff, \D);
|
||||
argQ = Q;
|
||||
dffD.replace(argQ, D);
|
||||
}
|
||||
|
||||
endcode
|
||||
// #######################
|
||||
|
||||
|
||||
subpattern out_dffe
|
||||
arg argD argQ clock
|
||||
|
||||
code
|
||||
dff = nullptr;
|
||||
for (auto c : argD.chunks())
|
||||
// Abandon matches when 'D' has the keep attribute set
|
||||
if (c.wire->get_bool_attribute(\keep))
|
||||
reject;
|
||||
endcode
|
||||
|
||||
match ff
|
||||
select ff->type.in($dff, $dffe, $sdff, $sdffe)
|
||||
// does not support clock inversion
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
|
||||
slice offset GetSize(port(ff, \D))
|
||||
index <SigBit> port(ff, \D)[offset] === argD[0]
|
||||
|
||||
// Check that the rest of argD is present
|
||||
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
|
||||
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
|
||||
|
||||
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||
endmatch
|
||||
|
||||
code argQ
|
||||
SigSpec D = port(ff, \D);
|
||||
SigSpec Q = port(ff, \Q);
|
||||
argQ = argD;
|
||||
argQ.replace(D, Q);
|
||||
|
||||
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||
for (auto c : argQ.chunks()) {
|
||||
Const init = c.wire->attributes.at(\init, Const());
|
||||
if (!init.empty())
|
||||
for (auto b : init.extract(c.offset, c.width))
|
||||
if (b != State::Sx && b != State::S0)
|
||||
reject;
|
||||
}
|
||||
|
||||
dff = ff;
|
||||
dffQ = argQ;
|
||||
dffclock = port(ff, \CLK);
|
||||
endcode
|
168
passes/pmgen/microchip_dsp_CREG.pmg
Normal file
168
passes/pmgen/microchip_dsp_CREG.pmg
Normal file
|
@ -0,0 +1,168 @@
|
|||
// ISC License
|
||||
//
|
||||
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
// This file describes the second of three pattern matcher setups that
|
||||
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||
// At a high level, it works as follows:
|
||||
// (1) Starting from a DSP cell that (a) doesn't have a CREG already,
|
||||
// and (b) uses the 'C' port
|
||||
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
||||
// (attached to at most two $mux cells that implement clock-enable or
|
||||
// reset functionality, using a subpattern discussed below)
|
||||
// Notes:
|
||||
// - Running CREG packing after microchip_dsp_pack is necessary since there is no
|
||||
// guarantee that the cell ordering corresponds to the "expected" case (i.e.
|
||||
// the order in which they appear in the source) thus the possiblity existed
|
||||
// where a register got packed as a CREG into a downstream DSP, while it should
|
||||
// have otherwise been a PREG of an upstream DSP that had not been visited.
|
||||
// yet.
|
||||
// - The reason this is separated out from the microchip_dsp.pmg file is
|
||||
// for efficiency --- each *.pmg file creates a class of the same basename,
|
||||
// which when constructed, creates a custom database tailored to the
|
||||
// pattern(s) contained within. Since the pattern in this file must be
|
||||
// executed after the pattern contained in microchip_dsp.pmg, it is necessary
|
||||
// to reconstruct this database. Separating the two patterns into
|
||||
// independent files causes two smaller, more specific, databases.
|
||||
|
||||
pattern microchip_dsp_packC
|
||||
|
||||
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
||||
state <SigBit> clock
|
||||
state <SigSpec> sigC sigP
|
||||
state <Cell*> ffC
|
||||
|
||||
// Variables used for subpatterns
|
||||
state <SigSpec> argQ argD
|
||||
state <int> ffoffset
|
||||
udata <SigSpec> dffD dffQ
|
||||
udata <SigBit> dffclock
|
||||
udata <Cell*> dff
|
||||
|
||||
// (1) Starting from a DSP cell that (a) doesn't have a CREG already,
|
||||
// and (b) uses the 'C' port
|
||||
match dsp
|
||||
select dsp->type.in(\MACC_PA)
|
||||
select port(dsp, \C_BYPASS, SigSpec()).is_fully_ones()
|
||||
select nusers(port(dsp, \C, SigSpec())) > 1
|
||||
endmatch
|
||||
|
||||
code sigC sigP clock
|
||||
//helper function to remove unused bits
|
||||
unextend = [](const SigSpec &sig) {
|
||||
int i;
|
||||
for (i = GetSize(sig)-1; i > 0; i--)
|
||||
if (sig[i] != sig[i-1])
|
||||
break;
|
||||
// Do not remove non-const sign bit
|
||||
if (sig[i].wire)
|
||||
++i;
|
||||
return sig.extract(0, i);
|
||||
};
|
||||
sigC = unextend(port(dsp, \C, SigSpec()));
|
||||
|
||||
SigSpec P = port(dsp, \P);
|
||||
|
||||
// Only care about those bits that are used
|
||||
int i;
|
||||
for (i = GetSize(P)-1; i >= 0; i--)
|
||||
if (nusers(P[i]) > 1)
|
||||
break;
|
||||
i++;
|
||||
log_assert(nusers(P.extract_end(i)) <= 1);
|
||||
sigP = P.extract(0, i);
|
||||
|
||||
clock = port(dsp, \CLK, SigBit());
|
||||
endcode
|
||||
|
||||
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
||||
// (attached to at most two $mux cells that implement clock-enable or
|
||||
// reset functionality, using the in_dffe subpattern)
|
||||
code argQ ffC sigC clock
|
||||
argQ = sigC;
|
||||
subpattern(in_dffe);
|
||||
if (dff) {
|
||||
ffC = dff;
|
||||
clock = dffclock;
|
||||
sigC = dffD;
|
||||
}
|
||||
endcode
|
||||
|
||||
code
|
||||
if (ffC)
|
||||
accept;
|
||||
endcode
|
||||
|
||||
// #######################
|
||||
|
||||
// Subpattern for matching against input registers, based on knowledge of the
|
||||
// 'Q' input.
|
||||
subpattern in_dffe
|
||||
arg argQ clock
|
||||
|
||||
code
|
||||
dff = nullptr;
|
||||
if (argQ.empty())
|
||||
reject;
|
||||
for (const auto &c : argQ.chunks()) {
|
||||
// Abandon matches when 'Q' is a constant
|
||||
if (!c.wire)
|
||||
reject;
|
||||
// Abandon matches when 'Q' has the keep attribute set
|
||||
if (c.wire->get_bool_attribute(\keep))
|
||||
reject;
|
||||
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||
Const init = c.wire->attributes.at(\init, Const());
|
||||
if (!init.empty())
|
||||
for (auto b : init.extract(c.offset, c.width))
|
||||
if (b != State::Sx && b != State::S0)
|
||||
reject;
|
||||
}
|
||||
endcode
|
||||
|
||||
match ff
|
||||
select ff->type.in($dff, $dffe, $sdff, $sdffe, $adff, $adffe)
|
||||
// does not support clock inversion
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
|
||||
slice offset GetSize(port(ff, \D))
|
||||
index <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||
|
||||
// Check that the rest of argQ is present
|
||||
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||
|
||||
filter clock == SigBit() || port(ff, \CLK)[0] == clock
|
||||
endmatch
|
||||
|
||||
code argQ
|
||||
// Check that reset value, if present, is fully 0.
|
||||
bool noResetFlop = ff->type.in($dff, $dffe);
|
||||
bool srstZero = ff->type.in($sdff, $sdffe) && param(ff, \SRST_VALUE).is_fully_zero();
|
||||
bool arstZero = ff->type.in($adff, $adffe) && param(ff, \ARST_VALUE).is_fully_zero();
|
||||
bool resetLegal = noResetFlop || srstZero || arstZero;
|
||||
if (resetLegal)
|
||||
{
|
||||
SigSpec Q = port(ff, \Q);
|
||||
dff = ff;
|
||||
dffclock = port(ff, \CLK);
|
||||
dffD = argQ;
|
||||
SigSpec D = port(ff, \D);
|
||||
argQ = Q;
|
||||
dffD.replace(argQ, D);
|
||||
}
|
||||
|
||||
endcode
|
236
passes/pmgen/microchip_dsp_cascade.pmg
Normal file
236
passes/pmgen/microchip_dsp_cascade.pmg
Normal file
|
@ -0,0 +1,236 @@
|
|||
// ISC License
|
||||
//
|
||||
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
// This file describes the third of three pattern matcher setups that
|
||||
// forms the `microchip_dsp` pass described in microchip_dsp.cc
|
||||
// At a high level, it works as follows:
|
||||
// (1) Starting from a DSP cell that
|
||||
// (a) CDIN_FDBK_SEL is set to default "00"
|
||||
// (b) doesn't already use the 'PCOUT' port
|
||||
// (2) Match another DSP cell that
|
||||
// (a) does not have the CREG enabled,
|
||||
// (b) 'C' port is driven by the 'P' output of the previous DSP cell
|
||||
// (c) has its 'PCIN' port unused
|
||||
// (3) Recursively go to (2) until no more matches possible, keeping track
|
||||
// of the longest possible chain found
|
||||
// (4) The longest chain is then divided into chunks of no more than
|
||||
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
|
||||
// height of a DSP column) with each DSP in each chunk being rewritten
|
||||
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
|
||||
|
||||
pattern microchip_dsp_cascade
|
||||
|
||||
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
||||
udata <vector<std::tuple<Cell*,int>>> chain longest_chain
|
||||
udata <std::set<Cell*>> visited
|
||||
state <Cell*> next
|
||||
state <SigSpec> clock
|
||||
|
||||
// Variables used for subpatterns
|
||||
state <SigSpec> argQ argD
|
||||
state <int> ffoffset
|
||||
udata <SigSpec> dffD dffQ
|
||||
udata <SigBit> dffclock
|
||||
udata <Cell*> dff
|
||||
|
||||
// Maximum of 24 cascaded blocks
|
||||
code
|
||||
#define MAX_DSP_CASCADE 24
|
||||
endcode
|
||||
|
||||
// NOTE: Chain vector
|
||||
// +--------+ +--------+
|
||||
// | first |----> | next | ----> ...
|
||||
// +--------+ +--------+
|
||||
// first.COUT cascades to next.CIN, so on and so forth
|
||||
|
||||
// Helper function to remove unused bits
|
||||
code
|
||||
unextend = [](const SigSpec &sig) {
|
||||
int i;
|
||||
for (i = GetSize(sig)-1; i > 0; i--)
|
||||
if (sig[i] != sig[i-1])
|
||||
break;
|
||||
// Do not remove non-const sign bit
|
||||
if (sig[i].wire)
|
||||
++i;
|
||||
return sig.extract(0, i);
|
||||
};
|
||||
endcode
|
||||
|
||||
// (1) Starting from a DSP cell that
|
||||
// (a) CDIN_FDBK_SEL is set to default "00"
|
||||
// (b) doesn't already use the 'PCOUT' port
|
||||
match first
|
||||
select first->type.in(\MACC_PA) && port(first, \CDIN_FDBK_SEL, Const(0, 2)) == Const::from_string("00")
|
||||
select nusers(port(first, \CDOUT, SigSpec())) <= 1
|
||||
endmatch
|
||||
|
||||
// (4) The longest chain is then divided into chunks of no more than
|
||||
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
|
||||
// height of a DSP column) with each DSP in each chunk being rewritten
|
||||
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
|
||||
code
|
||||
visited.clear();
|
||||
visited.insert(first);
|
||||
|
||||
longest_chain.clear();
|
||||
chain.emplace_back(first, -1);
|
||||
subpattern(tail);
|
||||
finally
|
||||
|
||||
// longest cascade chain has been found with DSP "first" being the head of the chain
|
||||
// do some post processing
|
||||
|
||||
chain.pop_back();
|
||||
visited.clear();
|
||||
log_assert(chain.empty());
|
||||
|
||||
if (GetSize(longest_chain) > 1) {
|
||||
Cell *dsp = std::get<0>(longest_chain.front());
|
||||
|
||||
Cell *dsp_pcin;
|
||||
int SHIFT = -1;
|
||||
for (int i = 1; i < GetSize(longest_chain); i++) {
|
||||
log_assert(dsp->type.in(\MACC_PA));
|
||||
|
||||
std::tie(dsp_pcin,SHIFT) = longest_chain[i];
|
||||
|
||||
// Chain length exceeds the maximum cascade length, must split it up
|
||||
if (i % MAX_DSP_CASCADE > 0) {
|
||||
Wire *cascade = module->addWire(NEW_ID, 48);
|
||||
|
||||
// zero port C and move wire to cascade
|
||||
dsp_pcin->setPort(ID(C), Const(0, 48));
|
||||
dsp_pcin->setPort(ID(CDIN), cascade);
|
||||
dsp->setPort(ID(CDOUT), cascade);
|
||||
|
||||
// Configure wire to cascade the dsps
|
||||
add_siguser(cascade, dsp_pcin);
|
||||
add_siguser(cascade, dsp);
|
||||
|
||||
// configure mux to use cascade for signal E
|
||||
SigSpec cdin_fdbk_sel = port(dsp_pcin, \CDIN_FDBK_SEL, Const(0, 2));
|
||||
cdin_fdbk_sel[1] = State::S1;
|
||||
dsp_pcin->setPort(\CDIN_FDBK_SEL, cdin_fdbk_sel);
|
||||
|
||||
// check if shifting is required for wide multiplier implmentation
|
||||
if (SHIFT == 17)
|
||||
{
|
||||
dsp_pcin->setPort(\ARSHFT17, State::S1);
|
||||
}
|
||||
|
||||
|
||||
log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
|
||||
|
||||
} else {
|
||||
log_debug(" Blocking %s -> %s cascade (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE);
|
||||
}
|
||||
|
||||
dsp = dsp_pcin;
|
||||
}
|
||||
|
||||
accept;
|
||||
}
|
||||
endcode
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
subpattern tail
|
||||
arg first
|
||||
arg next
|
||||
|
||||
// (2) Match another DSP cell that
|
||||
// (a) does not have the CREG enabled,
|
||||
// (b) 'C' port is driven by the 'P' output of the previous DSP cell
|
||||
// (c) has its 'PCIN' port unused
|
||||
match nextP
|
||||
// find candidates where nextP.C port is driven (maybe partially) by chain's tail DSP.P port
|
||||
// and with no registers in between (since cascade path cannot be pipelined)
|
||||
|
||||
// reg C must not be used
|
||||
select port(nextP, \C_BYPASS, SigSpec()).is_fully_ones()
|
||||
|
||||
// must be same DSP type
|
||||
select nextP->type.in(\MACC_PA)
|
||||
|
||||
// port C should be driven by something
|
||||
select nusers(port(nextP, \C, SigSpec())) > 1
|
||||
|
||||
// CIN must be unused
|
||||
select nusers(port(nextP, \PCIN, SigSpec())) == 0
|
||||
|
||||
// should not have internal feedback connection
|
||||
select port(nextP, \CDIN_FDBK_SEL, SigSpec()).is_fully_zero()
|
||||
|
||||
// SHIFT should be unused
|
||||
select port(nextP, \ARSHFT17_BYPASS).is_fully_ones()
|
||||
select port(nextP, \ARSHFT17).is_fully_zero()
|
||||
select nusers(port(nextP, \ARSHFT17, SigSpec())) == 0
|
||||
|
||||
// current DSP cell can be cascaded with the back of the cascade chain
|
||||
// index <SigBit> port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0] || port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[17]
|
||||
filter port(nextP, \C)[0] == port(std::get<0>(chain.back()), \P)[0] || port(nextP, \C)[0] == port(std::get<0>(chain.back()), \P)[17]
|
||||
|
||||
// semioptional
|
||||
|
||||
optional
|
||||
endmatch
|
||||
|
||||
code next
|
||||
next = nextP;
|
||||
|
||||
// keep DSP type consistent in the chain
|
||||
// currently since we only have one type anyways, this line is always false
|
||||
if (next && next->type != first->type) reject;
|
||||
|
||||
// break infinite recursion when there's a combinational loop
|
||||
if (visited.count(next) > 0) reject;
|
||||
|
||||
endcode
|
||||
|
||||
// (3) Recursively go to (2) until no more matches possible, recording the
|
||||
// longest possible chain
|
||||
code
|
||||
if (next) {
|
||||
SigSpec driver_sigP = port(std::get<0>(chain.back()), \P);
|
||||
int shift = 0;
|
||||
if (port(next, \C)[0] == port(std::get<0>(chain.back()), \P)[17]) shift = 17;
|
||||
|
||||
chain.emplace_back(next, shift);
|
||||
visited.insert(next);
|
||||
|
||||
SigSpec sigC = unextend(port(next, \C));
|
||||
|
||||
// Make sure driverDSP.P === DSP.C
|
||||
if (GetSize(sigC) + shift <= GetSize(driver_sigP) && driver_sigP.extract(shift, GetSize(sigC)) == sigC)
|
||||
{
|
||||
subpattern(tail);
|
||||
}
|
||||
} else {
|
||||
if (GetSize(chain) > GetSize(longest_chain))
|
||||
longest_chain = chain;
|
||||
}
|
||||
finally
|
||||
if (next)
|
||||
{
|
||||
visited.erase(next);
|
||||
chain.pop_back();
|
||||
}
|
||||
|
||||
|
||||
endcode
|
|
@ -23,11 +23,13 @@
|
|||
#include "kernel/consteval.h"
|
||||
#include "kernel/celledges.h"
|
||||
#include "kernel/macc.h"
|
||||
#include "kernel/cost.h"
|
||||
#include <algorithm>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
static int bloat_factor = 1;
|
||||
static uint32_t xorshift32_state = 123456789;
|
||||
|
||||
static uint32_t xorshift32(uint32_t limit) {
|
||||
|
@ -37,7 +39,7 @@ static uint32_t xorshift32(uint32_t limit) {
|
|||
return xorshift32_state % limit;
|
||||
}
|
||||
|
||||
static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode, bool muxdiv)
|
||||
static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode, bool muxdiv)
|
||||
{
|
||||
RTLIL::Module *module = design->addModule(ID(gold));
|
||||
RTLIL::Cell *cell = module->addCell(ID(UUT), cell_type);
|
||||
|
@ -45,7 +47,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type.in(ID($mux), ID($pmux)))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
int swidth = cell_type == ID($mux) ? 1 : 1 + xorshift32(8);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
|
@ -71,8 +73,8 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($bmux))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int swidth = 1 + xorshift32(4);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
int swidth = 1 + xorshift32(4 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = width << swidth;
|
||||
|
@ -92,8 +94,8 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($demux))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int swidth = 1 + xorshift32(6);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
int swidth = 1 + xorshift32(6 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = width;
|
||||
|
@ -113,7 +115,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($fa))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = width;
|
||||
|
@ -143,7 +145,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($lcu))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::P);
|
||||
wire->width = width;
|
||||
|
@ -168,7 +170,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
if (cell_type == ID($macc))
|
||||
{
|
||||
Macc macc;
|
||||
int width = 1 + xorshift32(8);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
int depth = 1 + xorshift32(6);
|
||||
int mulbits_a = 0, mulbits_b = 0;
|
||||
|
||||
|
@ -215,7 +217,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($lut))
|
||||
{
|
||||
int width = 1 + xorshift32(6);
|
||||
int width = 1 + xorshift32(6 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = width;
|
||||
|
@ -235,8 +237,8 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type == ID($sop))
|
||||
{
|
||||
int width = 1 + xorshift32(8);
|
||||
int depth = 1 + xorshift32(8);
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
int depth = 1 + xorshift32(8 * bloat_factor);
|
||||
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = width;
|
||||
|
@ -270,7 +272,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type_flags.find('A') != std::string::npos) {
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = 1 + xorshift32(8);
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::A, wire);
|
||||
}
|
||||
|
@ -278,9 +280,9 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
if (cell_type_flags.find('B') != std::string::npos) {
|
||||
wire = module->addWire(ID::B);
|
||||
if (cell_type_flags.find('h') != std::string::npos)
|
||||
wire->width = 1 + xorshift32(6);
|
||||
wire->width = 1 + xorshift32(6 * bloat_factor);
|
||||
else
|
||||
wire->width = 1 + xorshift32(8);
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::B, wire);
|
||||
}
|
||||
|
@ -301,7 +303,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
|
||||
if (cell_type_flags.find('Y') != std::string::npos) {
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = 1 + xorshift32(8);
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
@ -380,6 +382,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
|
|||
module->fixup_ports();
|
||||
cell->fixup_parameters();
|
||||
cell->check();
|
||||
return cell;
|
||||
}
|
||||
|
||||
static void run_edges_test(RTLIL::Design *design, bool verbose)
|
||||
|
@ -752,6 +755,9 @@ struct TestCellPass : public Pass {
|
|||
log(" -noeval\n");
|
||||
log(" do not check const-eval models\n");
|
||||
log("\n");
|
||||
log(" -noopt\n");
|
||||
log(" do not opt tecchmapped design\n");
|
||||
log("\n");
|
||||
log(" -edges\n");
|
||||
log(" test cell edges db creator against sat-based implementation\n");
|
||||
log("\n");
|
||||
|
@ -760,6 +766,11 @@ struct TestCellPass : public Pass {
|
|||
log("\n");
|
||||
log(" -vlog {filename}\n");
|
||||
log(" create a Verilog test bench to test simlib and write_verilog\n");
|
||||
log(" -bloat {factor}\n");
|
||||
log(" increase cell size limits b{factor} times where possible\n");
|
||||
log(" -check_cost\n");
|
||||
log(" check if the estimated cell cost is a valid upper bound for\n");
|
||||
log(" the techmapped cell count \n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design*) override
|
||||
|
@ -774,7 +785,9 @@ struct TestCellPass : public Pass {
|
|||
bool constmode = false;
|
||||
bool nosat = false;
|
||||
bool noeval = false;
|
||||
bool noopt = false;
|
||||
bool edges = false;
|
||||
bool check_cost = false;
|
||||
|
||||
int argidx;
|
||||
for (argidx = 1; argidx < GetSize(args); argidx++)
|
||||
|
@ -828,6 +841,10 @@ struct TestCellPass : public Pass {
|
|||
noeval = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noopt") {
|
||||
noopt = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-edges") {
|
||||
edges = true;
|
||||
continue;
|
||||
|
@ -842,6 +859,14 @@ struct TestCellPass : public Pass {
|
|||
log_cmd_error("Failed to open output file `%s'.\n", args[argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-bloat" && argidx+1 < GetSize(args)) {
|
||||
bloat_factor = atoi(args[++argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-check_cost") {
|
||||
check_cost = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -965,21 +990,30 @@ struct TestCellPass : public Pass {
|
|||
|
||||
std::vector<std::string> uut_names;
|
||||
|
||||
for (auto cell_type : selected_cell_types)
|
||||
for (auto cell_type : selected_cell_types) {
|
||||
// Cells that failed cell cost check
|
||||
int failed = 0;
|
||||
// How much bigger is the worst offender than estimated?
|
||||
int worst_abs = 0;
|
||||
// How many times is it bigger than estimated?
|
||||
float worst_rel = 0.0;
|
||||
for (int i = 0; i < num_iter; i++)
|
||||
{
|
||||
Cell* uut = nullptr;
|
||||
RTLIL::Design *design = new RTLIL::Design;
|
||||
if (cell_type == ID(rtlil))
|
||||
Frontend::frontend_call(design, NULL, std::string(), "rtlil " + rtlil_file);
|
||||
else
|
||||
create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
|
||||
uut = create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
|
||||
if (!write_prefix.empty()) {
|
||||
Pass::call(design, stringf("write_rtlil %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
|
||||
} else if (edges) {
|
||||
Pass::call(design, "dump gold");
|
||||
run_edges_test(design, verbose);
|
||||
} else {
|
||||
Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
|
||||
Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..", techmap_cmd.c_str()));
|
||||
if (!noopt)
|
||||
Pass::call(design, "opt -fast gate");
|
||||
if (!nosat)
|
||||
Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
|
||||
if (verbose)
|
||||
|
@ -997,10 +1031,44 @@ struct TestCellPass : public Pass {
|
|||
}
|
||||
if (!noeval)
|
||||
run_eval_test(design, verbose, nosat, uut_name, vlog_file);
|
||||
if (check_cost && uut) {
|
||||
Pass::call(design, "select gate");
|
||||
int num_cells = 0;
|
||||
for (auto mod : design->selected_modules()) {
|
||||
// Expected to run once
|
||||
for (auto cell : mod->selected_cells()) {
|
||||
(void) cell;
|
||||
num_cells++;
|
||||
}
|
||||
}
|
||||
CellCosts costs(design);
|
||||
Pass::call(design, "select gold");
|
||||
for (auto mod : design->selected_modules()) {
|
||||
log_assert(mod->name.str() == "\\gold");
|
||||
// Expected to run once
|
||||
int num_cells_estimate = costs.get(uut);
|
||||
if (num_cells <= num_cells_estimate) {
|
||||
log_debug("Correct upper bound for %s: %d <= %d\n", cell_type.c_str(), num_cells, num_cells_estimate);
|
||||
} else {
|
||||
failed++;
|
||||
if (worst_abs < num_cells - num_cells_estimate) {
|
||||
worst_abs = num_cells - num_cells_estimate;
|
||||
worst_rel = (float)(num_cells - num_cells_estimate) / (float)num_cells_estimate;
|
||||
}
|
||||
log_warning("Upper bound violated for %s: %d > %d\n", cell_type.c_str(), num_cells, num_cells_estimate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete design;
|
||||
}
|
||||
|
||||
if (check_cost && failed) {
|
||||
log_warning("Cell type %s cost underestimated in %.1f%% cases "
|
||||
"with worst offender being by %d (%.1f%%)\n",
|
||||
cell_type.c_str(), 100 * (float)failed / (float)num_iter,
|
||||
worst_abs, 100 * worst_rel);
|
||||
}
|
||||
}
|
||||
if (vlog_file.is_open()) {
|
||||
vlog_file << "\nmodule testbench;\n";
|
||||
for (auto &uut : uut_names)
|
||||
|
|
191
techlibs/microchip/LSRAM.txt
Normal file
191
techlibs/microchip/LSRAM.txt
Normal file
|
@ -0,0 +1,191 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
|
||||
|
||||
# LSRAM true dual-port
|
||||
ram block $__LSRAM_TDP_ {
|
||||
|
||||
# Cost of a given cell is assumed to be:
|
||||
# (cost-widthscale) + [widthscale * (used_bits/14)]
|
||||
cost 129;
|
||||
|
||||
# INIT is supported
|
||||
init any;
|
||||
|
||||
# port A and port B are allowed to have different widths, but they MUST have
|
||||
# WIDTH values of the same set.
|
||||
# Example: Port A has a Data Width of 1. Then Port B's Data Width must be either
|
||||
# 1, 2, 4, 8, or 16 (both values are in the 'WIDTH_1' set).
|
||||
# WIDTH_1 = {1, 2, 4, 8, 16}
|
||||
# WIDTH_2 = {5, 10, 20}
|
||||
|
||||
# "byte" specifies how many data bits correspond to one write enable bit.
|
||||
# "byte" must be larger than width, or width must be a multipler of "byte"
|
||||
# if "byte" > WIDTH, a single enable wire is inferred
|
||||
# otherwise, WIDTH/byte number of enable wires are inferred
|
||||
#
|
||||
# WIDTH = {1, 2, 4, 5, 8, 10} requires 1 enable wire
|
||||
# WIDTH = {16, 20} requires 2 enable wire
|
||||
|
||||
option "WIDTH_CONFIG" "REGULAR" {
|
||||
|
||||
# Data-Width| Address bits
|
||||
# 1 | 14
|
||||
# 2 | 13
|
||||
# 4 | 12
|
||||
# 8 | 11
|
||||
# 16 | 10
|
||||
|
||||
# 14 address bits
|
||||
abits 14;
|
||||
|
||||
widths 1 2 4 8 16 per_port;
|
||||
byte 8;
|
||||
}
|
||||
option "WIDTH_CONFIG" "ALIGN" {
|
||||
|
||||
# Data-Width| Address bits
|
||||
# 5 | 12
|
||||
# 10 | 11
|
||||
# 20 | 10
|
||||
|
||||
# Quick "hack" to fix address bit alignment by setting address bits to 12.
|
||||
# If abits=14, tool will think there are 14 bits for width=5, 13 bits for width=10, 12 bits for width=20
|
||||
# THe LSRAM_map.v file detects if this option is being used, and adjusts the address port alignments accordingly.
|
||||
abits 12;
|
||||
|
||||
widths 5 10 20 per_port;
|
||||
byte 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
port srsw "A" "B" {
|
||||
|
||||
# read & write width must be same
|
||||
width tied;
|
||||
|
||||
# clock polarity is rising
|
||||
clock posedge;
|
||||
|
||||
# A/B read-enable
|
||||
rden;
|
||||
|
||||
|
||||
# initial value of read port data (not supported)
|
||||
rdinit none;
|
||||
|
||||
# write modes (<A/B>_WMODE)
|
||||
# 1. Simple Write: read-data port holds prev value (similar to "NO_CHANGE" for RAMB18E1)
|
||||
# 2. Feed-through: read-data port takes new write value (similar to "WRITE_FIRST" for RAMB18E1)
|
||||
# 3. Read-Before-Write: read-data port holds old value while being written (similar to "READ_FIRST" for RAMB18E1)
|
||||
|
||||
portoption "WRITE_MODE" "NO_CHANGE" {
|
||||
|
||||
# Read-write interaction
|
||||
rdwr no_change;
|
||||
|
||||
# Write transparency:
|
||||
# For write ports, define behaviour when another synchronous read port
|
||||
# reads from the same memory cell that said write port is writing to at the same time.
|
||||
wrtrans all old;
|
||||
}
|
||||
portoption "WRITE_MODE" "WRITE_FIRST" {
|
||||
# bits corresponding to high A/B_WEN are updated
|
||||
rdwr new_only;
|
||||
wrtrans all new;
|
||||
}
|
||||
portoption "WRITE_MODE" "READ_FIRST" {
|
||||
rdwr old;
|
||||
|
||||
wrtrans all old;
|
||||
}
|
||||
|
||||
# generate params to indicate if read or write is used for each port
|
||||
optional_rw;
|
||||
}
|
||||
}
|
||||
|
||||
# two-port configuration
|
||||
ram block $__LSRAM_SDP_ {
|
||||
|
||||
# since two-port configuration is dedicated for wide-read/write,
|
||||
# we want to prioritize this configuration over TDP to avoid tool picking multiple TDP RAMs
|
||||
# inplace of a single SDP RAM for wide read/write. This means the cost of a single SDP should
|
||||
# be less than 2 TDP.
|
||||
cost 129;
|
||||
init any;
|
||||
|
||||
option "WIDTH_CONFIG" "REGULAR" {
|
||||
|
||||
# Data-Width| Address bits
|
||||
# 1 | 14
|
||||
# 2 | 13
|
||||
# 4 | 12
|
||||
# 8 | 11
|
||||
# 16 | 10
|
||||
# 32 | 9
|
||||
|
||||
abits 14;
|
||||
|
||||
widths 1 2 4 8 16 32 per_port;
|
||||
|
||||
# width = 32, byte-write size is 8, ignore other widths
|
||||
byte 8;
|
||||
|
||||
}
|
||||
option "WIDTH_CONFIG" "ALIGN" {
|
||||
|
||||
# Data-Width| Address bits
|
||||
# 5 | 12
|
||||
# 10 | 11
|
||||
# 20 | 10
|
||||
# 40 | 9
|
||||
|
||||
# Same trick as TSP RAM for alignment
|
||||
abits 12;
|
||||
widths 5 10 20 40 per_port;
|
||||
byte 10;
|
||||
}
|
||||
|
||||
port sw "W" {
|
||||
|
||||
# only consider wide write
|
||||
|
||||
option "WIDTH_CONFIG" "REGULAR" width 32;
|
||||
option "WIDTH_CONFIG" "ALIGN" width 40;
|
||||
|
||||
clock posedge;
|
||||
|
||||
# only simple write supported for two-port mode
|
||||
wrtrans all old;
|
||||
|
||||
optional;
|
||||
}
|
||||
port sr "R" {
|
||||
|
||||
option "WIDTH_CONFIG" "REGULAR" width 32;
|
||||
option "WIDTH_CONFIG" "ALIGN" width 40;
|
||||
|
||||
|
||||
clock posedge;
|
||||
rden;
|
||||
rdinit none;
|
||||
optional;
|
||||
}
|
||||
}
|
320
techlibs/microchip/LSRAM_map.v
Normal file
320
techlibs/microchip/LSRAM_map.v
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// See document PolarFire Family Fabric User Guide
|
||||
// section 4.1 for port list.
|
||||
|
||||
|
||||
//LSRAM true dual-port
|
||||
module $__LSRAM_TDP_ (...);
|
||||
|
||||
parameter INIT = 0;
|
||||
parameter ADDR_BITS = 14;
|
||||
|
||||
parameter OPTION_WIDTH_CONFIG = "A";
|
||||
|
||||
parameter PORT_A_WIDTH = 1;
|
||||
parameter PORT_A_WR_EN_WIDTH = 1;
|
||||
parameter PORT_A_RD_USED = 0;
|
||||
parameter PORT_A_WR_USED = 0;
|
||||
parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
|
||||
|
||||
parameter PORT_B_WIDTH = 1;
|
||||
parameter PORT_B_WR_EN_WIDTH = 1;
|
||||
parameter PORT_B_RD_USED = 0;
|
||||
parameter PORT_B_WR_USED = 0;
|
||||
parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
|
||||
|
||||
|
||||
input PORT_A_CLK;
|
||||
input PORT_A_RD_EN;
|
||||
input [ADDR_BITS-1:0] PORT_A_ADDR;
|
||||
input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
|
||||
input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
|
||||
output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
|
||||
|
||||
|
||||
input PORT_B_CLK;
|
||||
input PORT_B_RD_EN;
|
||||
input [ADDR_BITS-1:0] PORT_B_ADDR;
|
||||
input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
|
||||
input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
|
||||
output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
|
||||
|
||||
|
||||
`include "brams_defs.vh"
|
||||
|
||||
// address wires
|
||||
wire [ADDR_BITS-1:0] A_address;
|
||||
wire [ADDR_BITS-1:0] B_address;
|
||||
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_A_ADDR : {PORT_A_ADDR, 2'b00};
|
||||
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_B_ADDR : {PORT_B_ADDR, 2'b00};
|
||||
|
||||
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
|
||||
parameter PORT_A_RD_USED = 0;
|
||||
parameter PORT_A_WR_USED = 0;
|
||||
wire [2:0] A_BLK_SEL = (PORT_A_RD_USED == 1 || PORT_A_WR_USED == 1) ? 3'b111 : 3'b000;
|
||||
wire [2:0] B_BLK_SEL = (PORT_B_RD_USED == 1 || PORT_B_WR_USED == 1) ? 3'b111 : 3'b000;
|
||||
|
||||
// wires for write data
|
||||
generate
|
||||
wire [19:0] A_write_data;
|
||||
wire [19:0] B_write_data;
|
||||
if (PORT_A_WIDTH == 16) begin
|
||||
assign A_write_data[7:0] = PORT_A_WR_DATA[7:0];
|
||||
assign A_write_data[17:10] = PORT_A_WR_DATA[15:8];
|
||||
assign A_write_data[9:8] = 2'b0;
|
||||
assign A_write_data[19:18] = 2'b0;
|
||||
end else begin
|
||||
assign A_write_data[PORT_A_WIDTH-1:0] = PORT_A_WR_DATA;
|
||||
end
|
||||
|
||||
if (PORT_B_WIDTH == 16) begin
|
||||
assign B_write_data[7:0] = PORT_B_WR_DATA[7:0];
|
||||
assign B_write_data[17:10] = PORT_B_WR_DATA[15:8];
|
||||
assign B_write_data[9:8] = 2'b0;
|
||||
assign B_write_data[19:18] = 2'b0;
|
||||
end else begin
|
||||
assign B_write_data[PORT_B_WIDTH-1:0] = PORT_B_WR_DATA;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// wires for read data
|
||||
wire [19:0] A_read_data;
|
||||
assign PORT_A_RD_DATA = A_read_data[PORT_A_WIDTH-1:0];
|
||||
wire [19:0] B_read_data;
|
||||
assign PORT_B_RD_DATA = B_read_data[PORT_B_WIDTH-1:0];
|
||||
|
||||
// byte-write enables
|
||||
wire [1:0] A_write_EN = (PORT_A_WR_EN_WIDTH == 1) ? {1'b0, PORT_A_WR_EN} : PORT_A_WR_EN;
|
||||
wire [1:0] B_write_EN = (PORT_B_WR_EN_WIDTH == 1) ? {1'b0, PORT_B_WR_EN} : PORT_B_WR_EN;
|
||||
|
||||
// port width
|
||||
wire [2:0] A_width = (PORT_A_WIDTH == 1) ? 3'b000 :
|
||||
(PORT_A_WIDTH == 2) ? 3'b001 :
|
||||
(PORT_A_WIDTH == 4 || PORT_A_WIDTH == 5) ? 3'b010 :
|
||||
(PORT_A_WIDTH == 8 || PORT_A_WIDTH == 10) ? 3'b011 : 3'b100;
|
||||
wire [2:0] B_width = (PORT_B_WIDTH == 1) ? 3'b000 :
|
||||
(PORT_B_WIDTH == 2) ? 3'b001 :
|
||||
(PORT_B_WIDTH == 4 || PORT_B_WIDTH == 5) ? 3'b010 :
|
||||
(PORT_B_WIDTH == 8 || PORT_B_WIDTH == 10) ? 3'b011 : 3'b100;
|
||||
|
||||
// write modes
|
||||
wire [1:0] A_write_mode = PORT_A_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
|
||||
PORT_A_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
|
||||
wire [1:0] B_write_mode = PORT_B_OPTION_WRITE_MODE == "NO_CHANGE" ? 2'b00 :
|
||||
PORT_B_OPTION_WRITE_MODE == "WRITE_FIRST" ? 2'b01 : 2'b10;
|
||||
|
||||
RAM1K20 #(
|
||||
`PARAMS_INIT_LSRAM
|
||||
) _TECHMAP_REPLACE_ (
|
||||
|
||||
// port A
|
||||
.A_ADDR(A_address),
|
||||
.A_BLK_EN(A_BLK_SEL),
|
||||
.A_CLK(PORT_A_CLK),
|
||||
.A_DIN(A_write_data),
|
||||
.A_DOUT(A_read_data),
|
||||
.A_WEN(A_write_EN),
|
||||
.A_REN(PORT_A_RD_EN),
|
||||
.A_WIDTH(A_width),
|
||||
.A_WMODE(A_write_mode),
|
||||
.A_BYPASS(1'b1),
|
||||
.A_DOUT_EN(1'b1),
|
||||
.A_DOUT_SRST_N(1'b1),
|
||||
.A_DOUT_ARST_N(1'b1),
|
||||
|
||||
// port B
|
||||
.B_ADDR(B_address),
|
||||
.B_BLK_EN(B_BLK_SEL),
|
||||
.B_CLK(PORT_B_CLK),
|
||||
.B_DIN(B_write_data),
|
||||
.B_DOUT(B_read_data),
|
||||
.B_WEN(B_write_EN),
|
||||
.B_REN(PORT_B_RD_EN),
|
||||
.B_WIDTH(B_width),
|
||||
.B_WMODE(B_write_mode),
|
||||
.B_BYPASS(1'b1),
|
||||
.B_DOUT_EN(1'b1),
|
||||
.B_DOUT_SRST_N(1'b1),
|
||||
.B_DOUT_ARST_N(1'b1),
|
||||
|
||||
// Disable ECC for TDP
|
||||
.ECC_EN(1'b0),
|
||||
.ECC_BYPASS(1'b1),
|
||||
.BUSY_FB(1'b0)
|
||||
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
// single dual port configuration
|
||||
module $__LSRAM_SDP_ (...);
|
||||
|
||||
parameter INIT = 0;
|
||||
parameter OPTION_WIDTH_CONFIG = "REGULAR";
|
||||
parameter ADDR_BITS = 14;
|
||||
|
||||
parameter PORT_W_WIDTH = 1;
|
||||
parameter PORT_W_WR_EN_WIDTH = 4;
|
||||
parameter PORT_W_USED = 1;
|
||||
|
||||
parameter PORT_R_WIDTH = 1;
|
||||
parameter PORT_R_USED = 0;
|
||||
|
||||
input PORT_W_CLK;
|
||||
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||
input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
|
||||
|
||||
input PORT_R_CLK;
|
||||
input PORT_R_RD_EN;
|
||||
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||
input PORT_R_RD_SRST;
|
||||
|
||||
`include "brams_defs.vh"
|
||||
|
||||
|
||||
// address wires
|
||||
wire [ADDR_BITS-1:0] A_address;
|
||||
wire [ADDR_BITS-1:0] B_address;
|
||||
assign A_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_R_ADDR : {PORT_R_ADDR, 2'b00};
|
||||
assign B_address = (OPTION_WIDTH_CONFIG == "REGULAR") ? PORT_W_ADDR : {PORT_W_ADDR, 2'b00};
|
||||
|
||||
// if port is not used, set block sel to 0 to disable it (read-data output is set to 0)
|
||||
// port A is for read, port B for write
|
||||
parameter PORT_W_USED = 0;
|
||||
parameter PORT_R_USED = 0;
|
||||
wire [2:0] A_BLK_SEL = (PORT_R_USED == 1) ? 3'b111 : 3'b000;
|
||||
wire [2:0] B_BLK_SEL = (PORT_W_USED == 1) ? 3'b111 : 3'b000;
|
||||
|
||||
// read/write data & write enables
|
||||
// Currently support only wide write, width = {32, 40}
|
||||
generate
|
||||
wire [19:0] A_write_data;
|
||||
wire [19:0] B_write_data;
|
||||
wire [1:0] A_write_EN;
|
||||
wire [1:0] B_write_EN;
|
||||
|
||||
// write port (A provides MSB)
|
||||
if (PORT_W_WIDTH == 32) begin
|
||||
|
||||
assign B_write_data[3:0] = PORT_W_WR_DATA[3:0];
|
||||
assign B_write_data[8:5] = PORT_W_WR_DATA[7:4];
|
||||
assign B_write_data[13:10] = PORT_W_WR_DATA[11:8];
|
||||
assign B_write_data[18:15] = PORT_W_WR_DATA[15:12];
|
||||
assign B_write_data[4] = 1'b0;
|
||||
assign B_write_data[9] = 1'b0;
|
||||
assign B_write_data[14] = 1'b0;
|
||||
assign B_write_data[19] = 1'b0;
|
||||
|
||||
assign A_write_data[3:0] = PORT_W_WR_DATA[19:16];
|
||||
assign A_write_data[8:5] = PORT_W_WR_DATA[23:20];
|
||||
assign A_write_data[13:10] = PORT_W_WR_DATA[27:24];
|
||||
assign A_write_data[18:15] = PORT_W_WR_DATA[31:28];
|
||||
assign A_write_data[4] = 1'b0;
|
||||
assign A_write_data[9] = 1'b0;
|
||||
assign A_write_data[14] = 1'b0;
|
||||
assign A_write_data[19] = 1'b0;
|
||||
|
||||
end else if (PORT_W_WIDTH == 40) begin
|
||||
assign B_write_data = PORT_W_WR_DATA[19:0];
|
||||
assign A_write_data = PORT_W_WR_DATA[39:20];
|
||||
end
|
||||
|
||||
// byte-write enables
|
||||
assign A_write_EN = PORT_W_WR_EN[1:0];
|
||||
assign B_write_EN = PORT_W_WR_EN[3:2];
|
||||
|
||||
// read ports (A provides MSB)
|
||||
wire [19:0] A_read_data;
|
||||
wire [19:0] B_read_data;
|
||||
if (PORT_R_WIDTH == 32) begin
|
||||
assign PORT_R_RD_DATA[3:0] = B_read_data[3:0];
|
||||
assign PORT_R_RD_DATA[8:5] = B_read_data[7:4];
|
||||
assign PORT_R_RD_DATA[13:10] = B_read_data[11:8];
|
||||
assign PORT_R_RD_DATA[18:15] = B_read_data[15:12];
|
||||
|
||||
assign PORT_R_RD_DATA[19:16] = A_read_data[3:0];
|
||||
assign PORT_R_RD_DATA[23:20] = A_read_data[8:5];
|
||||
assign PORT_R_RD_DATA[27:24] = A_read_data[13:10];
|
||||
assign PORT_R_RD_DATA[31:28] = A_read_data[18:15];
|
||||
end else if (PORT_R_WIDTH == 40) begin
|
||||
assign PORT_R_RD_DATA[19:0] = B_read_data[19:0];
|
||||
assign PORT_R_RD_DATA[39:20] = A_read_data[19:0];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// port width
|
||||
wire [2:0] A_width = (PORT_R_WIDTH == 1) ? 3'b000 :
|
||||
(PORT_R_WIDTH == 2) ? 3'b001 :
|
||||
(PORT_R_WIDTH == 4 || PORT_R_WIDTH == 5) ? 3'b010 :
|
||||
(PORT_R_WIDTH == 8 || PORT_R_WIDTH == 10) ? 3'b011 :
|
||||
(PORT_R_WIDTH == 16 || PORT_R_WIDTH == 20) ? 3'b100 : 3'b101;
|
||||
wire [2:0] B_width = (PORT_W_WIDTH == 1) ? 3'b000 :
|
||||
(PORT_W_WIDTH == 2) ? 3'b001 :
|
||||
(PORT_W_WIDTH == 4 || PORT_W_WIDTH == 5) ? 3'b010 :
|
||||
(PORT_W_WIDTH == 8 || PORT_W_WIDTH == 10) ? 3'b011 :
|
||||
(PORT_W_WIDTH == 16 || PORT_W_WIDTH == 20) ? 3'b100 : 3'b101;
|
||||
|
||||
// write modes
|
||||
wire [1:0] A_write_mode = 2'b00;
|
||||
wire [1:0] B_write_mode = 2'b00;
|
||||
|
||||
RAM1K20 #(
|
||||
`PARAMS_INIT_LSRAM
|
||||
) _TECHMAP_REPLACE_ (
|
||||
// port A - read
|
||||
.A_ADDR(A_address),
|
||||
.A_BLK_EN(A_BLK_SEL),
|
||||
.A_CLK(PORT_R_CLK),
|
||||
.A_DIN(A_write_data),
|
||||
.A_DOUT(A_read_data),
|
||||
.A_WEN(A_write_EN),
|
||||
.A_REN(PORT_R_RD_EN),
|
||||
.A_WIDTH(A_width),
|
||||
.A_WMODE(A_write_mode),
|
||||
.A_BYPASS(1'b1),
|
||||
.A_DOUT_EN(1'b1),
|
||||
.A_DOUT_SRST_N(1'b1),
|
||||
.A_DOUT_ARST_N(1'b1),
|
||||
|
||||
// port B - write
|
||||
.B_ADDR(B_address),
|
||||
.B_BLK_EN(B_BLK_SEL),
|
||||
.B_CLK(PORT_W_CLK),
|
||||
.B_DIN(B_write_data),
|
||||
.B_DOUT(B_read_data),
|
||||
.B_WEN(B_write_EN),
|
||||
.B_REN(PORT_R_RD_EN),
|
||||
.B_WIDTH(B_width),
|
||||
.B_WMODE(B_write_mode),
|
||||
.B_BYPASS(1'b1),
|
||||
.B_DOUT_EN(1'b1),
|
||||
.B_DOUT_SRST_N(1'b1),
|
||||
.B_DOUT_ARST_N(1'b1),
|
||||
|
||||
// Disable ECC for SDP
|
||||
.ECC_EN(1'b0),
|
||||
.ECC_BYPASS(1'b1),
|
||||
.BUSY_FB(1'b0)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
31
techlibs/microchip/Makefile.inc
Normal file
31
techlibs/microchip/Makefile.inc
Normal file
|
@ -0,0 +1,31 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
|
||||
OBJS += techlibs/microchip/synth_microchip.o
|
||||
OBJS += techlibs/microchip/microchip_dffopt.o
|
||||
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/arith_map.v))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_map.v))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/cells_sim.v))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/polarfire_dsp_map.v))
|
||||
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/brams_defs.vh))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM_map.v))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/LSRAM.txt))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM_map.v))
|
||||
$(eval $(call add_share_file,share/microchip,techlibs/microchip/uSRAM.txt))
|
105
techlibs/microchip/arith_map.v
Normal file
105
techlibs/microchip/arith_map.v
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Based on Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||
// NOTE: prefix module names with \$__ so that mapping prioritizes these cells over internal Yosys cells
|
||||
|
||||
|
||||
(* techmap_celltype = "$_MUX4_" *)
|
||||
module \$__microchip_MUX4_ (A, B, C, D, S, T, Y);
|
||||
input A, B, C, D, S, T;
|
||||
output Y;
|
||||
MX4 _TECHMAP_REPLACE_.MUX4(.D3(D), .D2(C), .D1(B), .D0(A), .S1(T), .S0(S), .Y(Y));
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
(* techmap_celltype = "$reduce_xor" *)
|
||||
module \$__microchip_XOR8_ (A, Y);
|
||||
parameter A_SIGNED = 1;
|
||||
parameter A_WIDTH = 8;
|
||||
parameter Y_WIDTH = 1;
|
||||
|
||||
input [A_WIDTH-1:0] A;
|
||||
output [Y_WIDTH-1:0] Y;
|
||||
|
||||
// check if mapping should proceed
|
||||
generate
|
||||
if (A_WIDTH != 8 || A_SIGNED || Y_WIDTH != 1) begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
XOR8 _TECHMAP_REPLACE_.XOR8 (.A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .G(A[6]), .H(A[7]), .Y(Y));
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
(* techmap_celltype = "$alu" *)
|
||||
module \$__SF2_ALU (A, B, CI, BI, X, Y, CO);
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 1;
|
||||
parameter B_WIDTH = 1;
|
||||
parameter Y_WIDTH = 1;
|
||||
|
||||
(* force_downto *)
|
||||
input [A_WIDTH-1:0] A;
|
||||
(* force_downto *)
|
||||
input [B_WIDTH-1:0] B;
|
||||
(* force_downto *)
|
||||
output [Y_WIDTH-1:0] X, Y;
|
||||
|
||||
input CI, BI;
|
||||
(* force_downto *)
|
||||
output [Y_WIDTH-1:0] CO;
|
||||
|
||||
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
|
||||
|
||||
(* force_downto *)
|
||||
wire [Y_WIDTH-1:0] AA, BB;
|
||||
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(AA));
|
||||
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(BB));
|
||||
|
||||
(* force_downto *)
|
||||
wire [Y_WIDTH-1:0] C = {CO, CI};
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
|
||||
ARI1 #(
|
||||
// See section 1.4 of PolarFire Macro Library
|
||||
|
||||
// G = F1 = A[i] & (B[i]^BI)
|
||||
// Y = F0 = A[i]^B[i]^BI
|
||||
// P = Y
|
||||
// ADCB
|
||||
.INIT(20'b 01_11_0010_1000_1001_0110)
|
||||
) carry (
|
||||
.A(1'b0),
|
||||
.B(AA[i]),
|
||||
.C(BB[i]),
|
||||
.D(BI),
|
||||
.FCI(C[i]),
|
||||
.Y(X[i]),
|
||||
.S(Y[i]),
|
||||
.FCO(CO[i])
|
||||
);
|
||||
end endgenerate
|
||||
endmodule
|
||||
|
69
techlibs/microchip/brams_defs.vh
Normal file
69
techlibs/microchip/brams_defs.vh
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
`define PARAMS_INIT_LSRAM \
|
||||
.INIT0(slice_init_LSRAM(00)), \
|
||||
.INIT1(slice_init_LSRAM(01)), \
|
||||
.INIT2(slice_init_LSRAM(02)), \
|
||||
.INIT3(slice_init_LSRAM(03)), \
|
||||
.INIT4(slice_init_LSRAM(04)), \
|
||||
.INIT5(slice_init_LSRAM(05)), \
|
||||
.INIT6(slice_init_LSRAM(06)), \
|
||||
.INIT7(slice_init_LSRAM(07)), \
|
||||
.INIT8(slice_init_LSRAM(08)), \
|
||||
.INIT9(slice_init_LSRAM(09)), \
|
||||
.INIT10(slice_init_LSRAM(10)), \
|
||||
.INIT11(slice_init_LSRAM(11)), \
|
||||
.INIT12(slice_init_LSRAM(12)), \
|
||||
.INIT13(slice_init_LSRAM(13)), \
|
||||
.INIT14(slice_init_LSRAM(14)), \
|
||||
.INIT15(slice_init_LSRAM(15)), \
|
||||
.INIT16(slice_init_LSRAM(16)), \
|
||||
.INIT17(slice_init_LSRAM(17)), \
|
||||
.INIT18(slice_init_LSRAM(18)), \
|
||||
.INIT19(slice_init_LSRAM(19))
|
||||
|
||||
`define PARAMS_INIT_uSRAM \
|
||||
.INIT0(slice_init_uSRAM(00)), \
|
||||
.INIT1(slice_init_uSRAM(01)), \
|
||||
.INIT2(slice_init_uSRAM(02)), \
|
||||
.INIT3(slice_init_uSRAM(03)), \
|
||||
.INIT4(slice_init_uSRAM(04)), \
|
||||
.INIT5(slice_init_uSRAM(05)), \
|
||||
.INIT6(slice_init_uSRAM(06)), \
|
||||
.INIT7(slice_init_uSRAM(07)), \
|
||||
.INIT8(slice_init_uSRAM(08)), \
|
||||
.INIT9(slice_init_uSRAM(09)), \
|
||||
.INIT10(slice_init_uSRAM(10)), \
|
||||
.INIT11(slice_init_uSRAM(11)) \
|
||||
|
||||
// Helper function for initializing the LSRAM
|
||||
function [1023:0] slice_init_LSRAM;
|
||||
input integer slice_idx;
|
||||
integer i;
|
||||
for (i = 0; i < 1024; i = i + 1)
|
||||
slice_init_LSRAM[i] = INIT[(slice_idx * 1024 + i)];
|
||||
endfunction
|
||||
|
||||
// Helper function for initializing the uSRAM
|
||||
function [63:0] slice_init_uSRAM;
|
||||
input integer slice_idx;
|
||||
integer i;
|
||||
for (i = 0; i < 64; i = i + 1)
|
||||
slice_init_uSRAM[i] = INIT[(slice_idx * 64 + i)];
|
||||
endfunction
|
104
techlibs/microchip/cells_map.v
Normal file
104
techlibs/microchip/cells_map.v
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// DFFs
|
||||
module \$_DFFE_PN0P_ (input D, C, R, E, output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||
endmodule
|
||||
|
||||
module \$_DFFE_PN1P_ (input D, C, R, E, output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||
endmodule
|
||||
|
||||
// for sync set/reset registers, we can pass them into ABC9. So we need to follow the simplification idiom
|
||||
// and map to intermediate cell types
|
||||
module \$_SDFFCE_PN0P_ (input D, C, R, E, output Q);
|
||||
MICROCHIP_SYNC_RESET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Reset(R), .En(E), .Q(Q));
|
||||
endmodule
|
||||
|
||||
module \$_SDFFCE_PN1P_ (input D, C, R, E, output Q);
|
||||
MICROCHIP_SYNC_SET_DFF _TECHMAP_REPLACE_ (.D(D), .CLK(C), .Set(R), .En(E), .Q(Q));
|
||||
endmodule
|
||||
|
||||
|
||||
// LATCHES
|
||||
|
||||
module \$_DLATCH_PN0_ (input D, R, E, output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||
endmodule
|
||||
|
||||
module \$_DLATCH_PN1_ (input D, R, E, output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||
endmodule
|
||||
|
||||
module \$_DLATCH_P_ (input D, E, output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(1'b1), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q));
|
||||
endmodule
|
||||
|
||||
// map intermediate flops to SLE
|
||||
`ifdef FINAL_MAP
|
||||
module MICROCHIP_SYNC_SET_DFF(
|
||||
input D,
|
||||
input CLK,
|
||||
input Set,
|
||||
input En,
|
||||
output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Set), .SD(1'b1), .LAT(1'b0), .Q(Q));
|
||||
endmodule
|
||||
|
||||
module MICROCHIP_SYNC_RESET_DFF(
|
||||
input D,
|
||||
input CLK,
|
||||
input Reset,
|
||||
input En,
|
||||
output Q);
|
||||
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(CLK), .EN(En), .ALn(1'b1), .ADn(1'b0), .SLn(Reset), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||
endmodule
|
||||
`endif
|
||||
|
||||
|
||||
// LUT
|
||||
|
||||
`ifndef NO_LUT
|
||||
module \$lut (A, Y);
|
||||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
(* force_downto *)
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
generate
|
||||
if (WIDTH == 1) begin
|
||||
CFG1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]));
|
||||
end else
|
||||
if (WIDTH == 2) begin
|
||||
CFG2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]));
|
||||
end else
|
||||
if (WIDTH == 3) begin
|
||||
CFG3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]));
|
||||
end else
|
||||
if (WIDTH == 4) begin
|
||||
CFG4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
|
||||
end else begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
`endif
|
||||
|
719
techlibs/microchip/cells_sim.v
Normal file
719
techlibs/microchip/cells_sim.v
Normal file
|
@ -0,0 +1,719 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Macro Library for PolarFire https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||
|
||||
module AND2 (
|
||||
input A, B,
|
||||
output Y
|
||||
);
|
||||
assign Y = A & B;
|
||||
endmodule
|
||||
|
||||
module AND3 (
|
||||
input A, B, C,
|
||||
output Y
|
||||
);
|
||||
assign Y = A & B & C;
|
||||
endmodule
|
||||
|
||||
module AND4 (
|
||||
input A, B, C, D,
|
||||
output Y
|
||||
);
|
||||
assign Y = A & B & C & D;
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=1 *)
|
||||
module CFG1 (
|
||||
output Y,
|
||||
input A
|
||||
);
|
||||
parameter [1:0] INIT = 2'h0;
|
||||
assign Y = INIT >> A;
|
||||
specify
|
||||
(A => Y) = 127;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=1 *)
|
||||
module CFG2 (
|
||||
output Y,
|
||||
input A,
|
||||
input B
|
||||
);
|
||||
parameter [3:0] INIT = 4'h0;
|
||||
assign Y = INIT >> {B, A};
|
||||
specify
|
||||
(A => Y) = 238;
|
||||
(B => Y) = 127;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=1 *)
|
||||
module CFG3 (
|
||||
output Y,
|
||||
input A,
|
||||
input B,
|
||||
input C
|
||||
);
|
||||
parameter [7:0] INIT = 8'h0;
|
||||
assign Y = INIT >> {C, B, A};
|
||||
specify
|
||||
(A => Y) = 407;
|
||||
(B => Y) = 238;
|
||||
(C => Y) = 127;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_lut=1 *)
|
||||
module CFG4 (
|
||||
output Y,
|
||||
input A,
|
||||
input B,
|
||||
input C,
|
||||
input D
|
||||
);
|
||||
parameter [15:0] INIT = 16'h0;
|
||||
assign Y = INIT >> {D, C, B, A};
|
||||
specify
|
||||
(A => Y) = 472;
|
||||
(B => Y) = 407;
|
||||
(C => Y) = 238;
|
||||
(D => Y) = 127;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
module BUFF (
|
||||
input A,
|
||||
output Y
|
||||
);
|
||||
assign Y = A;
|
||||
endmodule
|
||||
|
||||
module BUFD (
|
||||
input A,
|
||||
output Y
|
||||
);
|
||||
assign Y = A;
|
||||
endmodule
|
||||
|
||||
module CLKINT (
|
||||
input A,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
assign Y = A;
|
||||
endmodule
|
||||
|
||||
module CLKINT_PRESERVE (
|
||||
input A,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
assign Y = A;
|
||||
endmodule
|
||||
|
||||
module GCLKINT (
|
||||
input A, EN,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
assign Y = A & EN;
|
||||
endmodule
|
||||
|
||||
module RCLKINT (
|
||||
input A,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
assign Y = A;
|
||||
endmodule
|
||||
|
||||
module RGCLKINT (
|
||||
input A, EN,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
assign Y = A & EN;
|
||||
endmodule
|
||||
|
||||
// sequential elements
|
||||
|
||||
// MICROCHIP_SYNC_SET_DFF and MICROCHIP_SYNC_RESET_DFF are intermediate cell types to implement the simplification idiom for abc9 flow
|
||||
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/abc_flow.html
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module MICROCHIP_SYNC_SET_DFF(
|
||||
input D,
|
||||
input CLK,
|
||||
input Set,
|
||||
input En,
|
||||
output reg Q);
|
||||
parameter [0:0] INIT = 1'b0; // unused
|
||||
|
||||
always @(posedge CLK) begin
|
||||
if (En == 1) begin
|
||||
if (Set == 0)
|
||||
Q <= 1;
|
||||
else
|
||||
Q <= D;
|
||||
end
|
||||
end
|
||||
|
||||
specify
|
||||
$setup(D , posedge CLK &&& En && Set, 0); // neg setup not supported?
|
||||
$setup(En, posedge CLK, 109);
|
||||
$setup(Set, posedge CLK &&& En, 404);
|
||||
if (En && !Set) (posedge CLK => (Q : 1'b1)) = 303;
|
||||
if (En && Set) (posedge CLK => (Q : D)) = 303;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* abc9_flop, lib_whitebox *)
|
||||
module MICROCHIP_SYNC_RESET_DFF(
|
||||
input D,
|
||||
input CLK,
|
||||
input Reset,
|
||||
input En,
|
||||
output reg Q);
|
||||
parameter [0:0] INIT = 1'b0; // unused
|
||||
|
||||
always @(posedge CLK) begin
|
||||
if (En == 1) begin
|
||||
if (Reset == 0)
|
||||
Q <= 0;
|
||||
else
|
||||
Q <= D;
|
||||
end
|
||||
end
|
||||
|
||||
specify
|
||||
$setup(D , posedge CLK &&& En && Reset, 0); // neg setup not supported?
|
||||
$setup(En, posedge CLK, 109);
|
||||
$setup(Reset, posedge CLK &&& En, 404);
|
||||
if (En && !Reset) (posedge CLK => (Q : 1'b0)) = 303;
|
||||
if (En && Reset) (posedge CLK => (Q : D)) = 303;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
module SLE (
|
||||
output Q,
|
||||
input ADn,
|
||||
input ALn,
|
||||
(* clkbuf_sink *)
|
||||
input CLK,
|
||||
input D,
|
||||
input LAT,
|
||||
input SD,
|
||||
input EN,
|
||||
input SLn
|
||||
);
|
||||
reg q_latch, q_ff;
|
||||
|
||||
always @(posedge CLK, negedge ALn) begin
|
||||
if (!ALn) begin
|
||||
q_ff <= !ADn;
|
||||
end else if (EN) begin
|
||||
if (!SLn)
|
||||
q_ff <= SD;
|
||||
else
|
||||
q_ff <= D;
|
||||
end
|
||||
end
|
||||
|
||||
always @* begin
|
||||
if (!ALn) begin
|
||||
q_latch <= !ADn;
|
||||
end else if (CLK && EN) begin
|
||||
if (!SLn)
|
||||
q_ff <= SD;
|
||||
else
|
||||
q_ff <= D;
|
||||
end
|
||||
end
|
||||
|
||||
assign Q = LAT ? q_latch : q_ff;
|
||||
endmodule
|
||||
|
||||
(* abc9_box, lib_whitebox *)
|
||||
module ARI1 (
|
||||
(* abc9_carry *)
|
||||
input FCI,
|
||||
(* abc9_carry *)
|
||||
output FCO,
|
||||
|
||||
input A, B, C, D,
|
||||
output Y, S
|
||||
);
|
||||
parameter [19:0] INIT = 20'h0;
|
||||
wire [2:0] Fsel = {D, C, B};
|
||||
wire F0 = INIT[Fsel];
|
||||
wire F1 = INIT[8 + Fsel];
|
||||
wire Yout = A ? F1 : F0;
|
||||
assign Y = Yout;
|
||||
assign S = FCI ^ Yout;
|
||||
wire G = INIT[16] ? (INIT[17] ? F1 : F0) : INIT[17];
|
||||
wire P = INIT[19] ? 1'b1 : (INIT[18] ? Yout : 1'b0);
|
||||
assign FCO = P ? FCI : G;
|
||||
|
||||
specify
|
||||
//pin to pin path delay
|
||||
(A => Y ) = 472;
|
||||
(B => Y ) = 407;
|
||||
(C => Y ) = 238;
|
||||
(D => Y ) = 127;
|
||||
(A => S ) = 572;
|
||||
(B => S ) = 507;
|
||||
(C => S ) = 338;
|
||||
(D => S ) = 227;
|
||||
(FCI => S ) = 100;
|
||||
(A => FCO ) = 522;
|
||||
(B => FCO ) = 457;
|
||||
(C => FCO ) = 288;
|
||||
(D => FCO ) = 177;
|
||||
(FCI => FCO ) = 50;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module GCLKBUF (
|
||||
(* iopad_external_pin *)
|
||||
input PAD,
|
||||
input EN,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module GCLKBUF_DIFF (
|
||||
(* iopad_external_pin *)
|
||||
input PADP,
|
||||
(* iopad_external_pin *)
|
||||
input PADN,
|
||||
input EN,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
endmodule
|
||||
|
||||
module INV (
|
||||
input A,
|
||||
output Y
|
||||
);
|
||||
assign Y = !A;
|
||||
endmodule
|
||||
|
||||
module INVD (
|
||||
input A,
|
||||
output Y
|
||||
);
|
||||
assign Y = !A;
|
||||
endmodule
|
||||
|
||||
module MX2 (
|
||||
input A, B, S,
|
||||
output Y
|
||||
);
|
||||
assign Y = S ? B : A;
|
||||
endmodule
|
||||
|
||||
module MX4 (
|
||||
input D0, D1, D2, D3, S0, S1,
|
||||
output Y
|
||||
);
|
||||
assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
|
||||
endmodule
|
||||
|
||||
module NAND2 (
|
||||
input A, B,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A & B);
|
||||
endmodule
|
||||
|
||||
module NAND3 (
|
||||
input A, B, C,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A & B & C);
|
||||
endmodule
|
||||
|
||||
module NAND4 (
|
||||
input A, B, C, D,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A & B & C & D);
|
||||
endmodule
|
||||
|
||||
module NOR2 (
|
||||
input A, B,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A | B);
|
||||
endmodule
|
||||
|
||||
module NOR3 (
|
||||
input A, B, C,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A | B | C);
|
||||
endmodule
|
||||
|
||||
module NOR4 (
|
||||
input A, B, C, D,
|
||||
output Y
|
||||
);
|
||||
assign Y = !(A | B | C | D);
|
||||
endmodule
|
||||
|
||||
module OR2 (
|
||||
input A, B,
|
||||
output Y
|
||||
);
|
||||
assign Y = A | B;
|
||||
endmodule
|
||||
|
||||
module OR3 (
|
||||
input A, B, C,
|
||||
output Y
|
||||
);
|
||||
assign Y = A | B | C;
|
||||
endmodule
|
||||
|
||||
module OR4 (
|
||||
input A, B, C, D,
|
||||
output Y
|
||||
);
|
||||
assign Y = A | B | C | D;
|
||||
endmodule
|
||||
|
||||
module XOR2 (
|
||||
input A, B,
|
||||
output Y
|
||||
);
|
||||
assign Y = A ^ B;
|
||||
endmodule
|
||||
|
||||
module XOR3 (
|
||||
input A, B, C,
|
||||
output Y
|
||||
);
|
||||
assign Y = A ^ B ^ C;
|
||||
endmodule
|
||||
|
||||
module XOR4 (
|
||||
input A, B, C, D,
|
||||
output Y
|
||||
);
|
||||
assign Y = A ^ B ^ C ^ D;
|
||||
endmodule
|
||||
|
||||
module XOR8 (
|
||||
input A, B, C, D, E, F, G, H,
|
||||
output Y
|
||||
);
|
||||
assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
|
||||
endmodule
|
||||
|
||||
// module UJTAG
|
||||
|
||||
module BIBUF (
|
||||
input D,
|
||||
input E,
|
||||
(* iopad_external_pin *)
|
||||
inout PAD,
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign PAD = E ? D : 1'bz;
|
||||
assign Y = PAD;
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module BIBUF_DIFF (
|
||||
input D,
|
||||
input E,
|
||||
(* iopad_external_pin *)
|
||||
inout PADP,
|
||||
(* iopad_external_pin *)
|
||||
inout PADN,
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
endmodule
|
||||
|
||||
module CLKBIBUF (
|
||||
input D,
|
||||
input E,
|
||||
(* iopad_external_pin *)
|
||||
inout PAD,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign PAD = E ? D : 1'bz;
|
||||
assign Y = PAD;
|
||||
endmodule
|
||||
|
||||
module CLKBUF (
|
||||
(* iopad_external_pin *)
|
||||
input PAD,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign Y = PAD;
|
||||
specify
|
||||
(PAD => Y) = 50;
|
||||
endspecify
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module CLKBUF_DIFF (
|
||||
(* iopad_external_pin *)
|
||||
input PADP,
|
||||
(* iopad_external_pin *)
|
||||
input PADN,
|
||||
(* clkbuf_driver *)
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
endmodule
|
||||
|
||||
module INBUF (
|
||||
(* iopad_external_pin *)
|
||||
input PAD,
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign Y = PAD;
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module INBUF_DIFF (
|
||||
(* iopad_external_pin *)
|
||||
input PADP,
|
||||
(* iopad_external_pin *)
|
||||
input PADN,
|
||||
output Y
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
endmodule
|
||||
|
||||
module OUTBUF (
|
||||
input D,
|
||||
(* iopad_external_pin *)
|
||||
output PAD
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign PAD = D;
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module OUTBUF_DIFF (
|
||||
input D,
|
||||
(* iopad_external_pin *)
|
||||
output PADP,
|
||||
(* iopad_external_pin *)
|
||||
output PADN
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
endmodule
|
||||
|
||||
module TRIBUFF (
|
||||
input D,
|
||||
input E,
|
||||
(* iopad_external_pin *)
|
||||
output PAD
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
assign PAD = E ? D : 1'bz;
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module TRIBUFF_DIFF (
|
||||
input D,
|
||||
input E,
|
||||
(* iopad_external_pin *)
|
||||
output PADP,
|
||||
(* iopad_external_pin *)
|
||||
output PADN
|
||||
);
|
||||
parameter IOSTD = "";
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module MACC_PA (
|
||||
input DOTP,
|
||||
input SIMD,
|
||||
input OVFL_CARRYOUT_SEL,
|
||||
input CLK,
|
||||
input AL_N,
|
||||
input [17:0] A,
|
||||
input A_BYPASS,
|
||||
input A_SRST_N,
|
||||
input A_EN,
|
||||
input [17:0] B,
|
||||
input B_BYPASS,
|
||||
input B_SRST_N,
|
||||
input B_EN,
|
||||
input [17:0] D,
|
||||
input D_BYPASS,
|
||||
input D_ARST_N,
|
||||
input D_SRST_N,
|
||||
input D_EN,
|
||||
input CARRYIN,
|
||||
input [47:0] C,
|
||||
input C_BYPASS,
|
||||
input C_ARST_N,
|
||||
input C_SRST_N,
|
||||
input C_EN,
|
||||
input [47:0] CDIN,
|
||||
output [47:0] P,
|
||||
output OVFL_CARRYOUT,
|
||||
input P_BYPASS,
|
||||
input P_SRST_N,
|
||||
input P_EN,
|
||||
output [47:0] CDOUT,
|
||||
input PASUB,
|
||||
input PASUB_BYPASS,
|
||||
input PASUB_AD_N,
|
||||
input PASUB_SL_N,
|
||||
input PASUB_SD_N,
|
||||
input PASUB_EN,
|
||||
input [1:0] CDIN_FDBK_SEL,
|
||||
input CDIN_FDBK_SEL_BYPASS,
|
||||
input [1:0] CDIN_FDBK_SEL_AD_N,
|
||||
input CDIN_FDBK_SEL_SL_N,
|
||||
input [1:0] CDIN_FDBK_SEL_SD_N,
|
||||
input CDIN_FDBK_SEL_EN,
|
||||
input ARSHFT17,
|
||||
input ARSHFT17_BYPASS,
|
||||
input ARSHFT17_AD_N,
|
||||
input ARSHFT17_SL_N,
|
||||
input ARSHFT17_SD_N,
|
||||
input ARSHFT17_EN,
|
||||
input SUB,
|
||||
input SUB_BYPASS,
|
||||
input SUB_AD_N,
|
||||
input SUB_SL_N,
|
||||
input SUB_SD_N,
|
||||
input SUB_EN
|
||||
);
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module RAM1K20 (
|
||||
input [13:0] A_ADDR,
|
||||
input [2:0] A_BLK_EN,
|
||||
input A_CLK,
|
||||
input [19:0] A_DIN,
|
||||
output [19:0] A_DOUT,
|
||||
input [1:0] A_WEN,
|
||||
input A_REN,
|
||||
input [2:0] A_WIDTH,
|
||||
input [1:0] A_WMODE,
|
||||
input A_BYPASS,
|
||||
input A_DOUT_EN,
|
||||
input A_DOUT_SRST_N,
|
||||
input A_DOUT_ARST_N,
|
||||
input [13:0] B_ADDR,
|
||||
input [2:0] B_BLK_EN,
|
||||
input B_CLK,
|
||||
input [19:0] B_DIN,
|
||||
output [19:0] B_DOUT,
|
||||
input [1:0] B_WEN,
|
||||
input B_REN,
|
||||
input [2:0] B_WIDTH,
|
||||
input [1:0] B_WMODE,
|
||||
input B_BYPASS,
|
||||
input B_DOUT_EN,
|
||||
input B_DOUT_SRST_N,
|
||||
input B_DOUT_ARST_N,
|
||||
input ECC_EN,
|
||||
input ECC_BYPASS,
|
||||
output SB_CORRECT,
|
||||
output DB_DETECT,
|
||||
input BUSY_FB,
|
||||
output ACCESS_BUSY
|
||||
);
|
||||
parameter INIT0 = 1024'h0;
|
||||
parameter INIT1 = 1024'h0;
|
||||
parameter INIT2 = 1024'h0;
|
||||
parameter INIT3 = 1024'h0;
|
||||
parameter INIT4 = 1024'h0;
|
||||
parameter INIT5 = 1024'h0;
|
||||
parameter INIT6 = 1024'h0;
|
||||
parameter INIT7 = 1024'h0;
|
||||
parameter INIT8 = 1024'h0;
|
||||
parameter INIT9 = 1024'h0;
|
||||
parameter INIT10 = 1024'h0;
|
||||
parameter INIT11 = 1024'h0;
|
||||
parameter INIT12 = 1024'h0;
|
||||
parameter INIT13 = 1024'h0;
|
||||
parameter INIT14 = 1024'h0;
|
||||
parameter INIT15 = 1024'h0;
|
||||
parameter INIT16 = 1024'h0;
|
||||
parameter INIT17 = 1024'h0;
|
||||
parameter INIT18 = 1024'h0;
|
||||
parameter INIT19 = 1024'h0;
|
||||
endmodule
|
||||
|
||||
(* blackbox *)
|
||||
module RAM64x12 (
|
||||
input R_CLK,
|
||||
input [5:0] R_ADDR,
|
||||
input R_ADDR_BYPASS,
|
||||
input R_ADDR_EN,
|
||||
input R_ADDR_SL_N,
|
||||
input R_ADDR_SD,
|
||||
input R_ADDR_AL_N,
|
||||
input R_ADDR_AD_N,
|
||||
input BLK_EN,
|
||||
output [11:0] R_DATA,
|
||||
input R_DATA_BYPASS,
|
||||
input R_DATA_EN,
|
||||
input R_DATA_SL_N,
|
||||
input R_DATA_SD,
|
||||
input R_DATA_AL_N,
|
||||
input R_DATA_AD_N,
|
||||
|
||||
input W_CLK,
|
||||
input [5:0] W_ADDR,
|
||||
input [11:0]W_DATA,
|
||||
input W_EN,
|
||||
|
||||
input BUSY_FB,
|
||||
output ACCESS_BUSY
|
||||
);
|
||||
parameter INIT0 = 64'h0;
|
||||
parameter INIT1 = 64'h0;
|
||||
parameter INIT2 = 64'h0;
|
||||
parameter INIT3 = 64'h0;
|
||||
parameter INIT4 = 64'h0;
|
||||
parameter INIT5 = 64'h0;
|
||||
parameter INIT6 = 64'h0;
|
||||
parameter INIT7 = 64'h0;
|
||||
parameter INIT8 = 64'h0;
|
||||
parameter INIT9 = 64'h0;
|
||||
parameter INIT10 = 64'h0;
|
||||
parameter INIT11 = 64'h0;
|
||||
|
||||
endmodule
|
343
techlibs/microchip/microchip_dffopt.cc
Normal file
343
techlibs/microchip/microchip_dffopt.cc
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::pair<Const, std::vector<SigBit>> LutData;
|
||||
|
||||
// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
|
||||
bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size)
|
||||
{
|
||||
// First, gather input signals -- insert new signals at the beginning
|
||||
// of the vector, so they don't disturb the likely-critical D LUT input
|
||||
// timings.
|
||||
result.second = data.second;
|
||||
// D lut inputs initially start at 0.
|
||||
int idx_data = 0;
|
||||
// Now add the control input LUT inputs.
|
||||
std::vector<int> idx_sel;
|
||||
for (auto bit : select.second) {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < GetSize(result.second); i++)
|
||||
if (result.second[i] == bit)
|
||||
idx = i;
|
||||
if (idx == -1) {
|
||||
idx = 0;
|
||||
// Insert new signal at the beginning and bump all indices.
|
||||
result.second.insert(result.second.begin(), bit);
|
||||
idx_data++;
|
||||
for (int &sidx : idx_sel)
|
||||
sidx++;
|
||||
}
|
||||
idx_sel.push_back(idx);
|
||||
}
|
||||
// Insert the Q signal, if any, to the slowest input -- it will have
|
||||
// no problem meeting timing.
|
||||
// This is to emulate CLK_EN, where output data is retained
|
||||
int idx_alt = -1;
|
||||
if (alt_data.wire) {
|
||||
// Check if we already have it.
|
||||
for (int i = 0; i < GetSize(result.second); i++)
|
||||
if (result.second[i] == alt_data)
|
||||
idx_alt = i;
|
||||
// If not, add it.
|
||||
if (idx_alt == -1) {
|
||||
idx_alt = 0;
|
||||
result.second.insert(result.second.begin(), alt_data);
|
||||
idx_data++;
|
||||
for (int &sidx : idx_sel)
|
||||
sidx++;
|
||||
}
|
||||
}
|
||||
|
||||
// If LUT would be too large, bail.
|
||||
if (GetSize(result.second) > max_lut_size)
|
||||
return false;
|
||||
|
||||
// Okay, we're doing it — compute the LUT mask.
|
||||
result.first = Const(0, 1 << GetSize(result.second));
|
||||
for (int i = 0; i < GetSize(result.first); i++) {
|
||||
int sel_lut_idx = 0;
|
||||
for (int j = 0; j < GetSize(select.second); j++)
|
||||
if (i & 1 << idx_sel[j])
|
||||
sel_lut_idx |= 1 << j;
|
||||
bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
|
||||
bool new_bit;
|
||||
if (select_val ^ select_inv) {
|
||||
// Use alt_data.
|
||||
if (alt_data.wire)
|
||||
new_bit = (i & 1 << idx_alt) != 0;
|
||||
else
|
||||
new_bit = alt_data.data == State::S1;
|
||||
} else {
|
||||
// Use original LUT.
|
||||
int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1);
|
||||
new_bit = data.first.bits[lut_idx] == State::S1;
|
||||
}
|
||||
result.first.bits[i] = new_bit ? State::S1 : State::S0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MicrochipDffOptPass : public Pass {
|
||||
MicrochipDffOptPass() : Pass("microchip_dffopt", "MICROCHIP: optimize FF control signal usage") {}
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" microchip_dffopt [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
|
||||
log("using LUTs, if doing so would improve area. Operates on post-techmap LUT, DFF\n");
|
||||
log("cells. \n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing MICROCHIP_DFFOPT pass (optimize FF control signal usage).\n");
|
||||
|
||||
size_t argidx = 1;
|
||||
int max_lut_size = 4;
|
||||
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
log("Optimizing FFs in %s.\n", log_id(module));
|
||||
|
||||
SigMap sigmap(module);
|
||||
dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
|
||||
dict<SigBit, int> bit_uses;
|
||||
|
||||
// Gather LUTs.
|
||||
for (auto cell : module->selected_cells()) {
|
||||
for (auto port : cell->connections())
|
||||
for (auto bit : port.second)
|
||||
bit_uses[sigmap(bit)]++;
|
||||
if (cell->get_bool_attribute(ID::keep))
|
||||
continue;
|
||||
if (cell->type == ID(INV)) {
|
||||
SigBit sigout = sigmap(cell->getPort(ID::Y));
|
||||
SigBit sigin = sigmap(cell->getPort(ID::A));
|
||||
bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell); // INIT = 01
|
||||
} else if (cell->type.in(ID(CFG1), ID(CFG2), ID(CFG3), ID(CFG4))) {
|
||||
SigBit sigout = sigmap(cell->getPort(ID::Y));
|
||||
const Const &init = cell->getParam(ID::INIT);
|
||||
std::vector<SigBit> sigin;
|
||||
sigin.push_back(sigmap(cell->getPort(ID(A))));
|
||||
if (cell->type == ID(CFG1))
|
||||
goto lut_sigin_done;
|
||||
sigin.push_back(sigmap(cell->getPort(ID(B))));
|
||||
if (cell->type == ID(CFG2))
|
||||
goto lut_sigin_done;
|
||||
sigin.push_back(sigmap(cell->getPort(ID(C))));
|
||||
if (cell->type == ID(CFG3))
|
||||
goto lut_sigin_done;
|
||||
sigin.push_back(sigmap(cell->getPort(ID(D))));
|
||||
|
||||
lut_sigin_done:
|
||||
bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
|
||||
}
|
||||
}
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_output || wire->port_input)
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
bit_uses[sigmap(SigBit(wire, i))]++;
|
||||
|
||||
// Iterate through FFs.
|
||||
for (auto cell : module->selected_cells()) {
|
||||
|
||||
if (!cell->type.in(ID(SLE))) // not a SLE
|
||||
continue;
|
||||
if (cell->getPort(ID(LAT)).is_fully_ones()) // skip latch
|
||||
continue;
|
||||
if (cell->get_bool_attribute(ID::keep)) // keep attribute
|
||||
continue;
|
||||
if (!cell->getPort(ID(ALn)).is_fully_ones()) // async FF
|
||||
continue;
|
||||
|
||||
const bool hasSyncLoad = cell->getPort(ID(SLn)).is_wire();
|
||||
const bool has_s = hasSyncLoad && cell->getPort(ID(SD)).is_fully_ones();
|
||||
const bool has_r = hasSyncLoad && cell->getPort(ID(SD)).is_fully_zero();
|
||||
|
||||
// SLE cannot have both synchronous set and reset implemented at the same time
|
||||
log_assert(!(has_s && has_r));
|
||||
|
||||
// Don't bother if D has more than one use.
|
||||
SigBit sig_D = sigmap(cell->getPort(ID::D));
|
||||
if (bit_uses[sig_D] > 2)
|
||||
continue;
|
||||
|
||||
// Find the D LUT.
|
||||
auto it_D = bit_to_lut.find(sig_D);
|
||||
if (it_D == bit_to_lut.end())
|
||||
continue;
|
||||
LutData lut_d = it_D->second.first;
|
||||
Cell *cell_d = it_D->second.second;
|
||||
|
||||
LutData lut_d_post_ce;
|
||||
LutData lut_d_post_s;
|
||||
LutData lut_d_post_r;
|
||||
bool worthy_post_ce = false;
|
||||
bool worthy_post_s = false;
|
||||
bool worthy_post_r = false;
|
||||
|
||||
// First, unmap CE.
|
||||
SigBit sig_Q = sigmap(cell->getPort(ID::Q));
|
||||
SigBit sig_CE = sigmap(cell->getPort(ID(EN)));
|
||||
LutData lut_ce = LutData(Const(2, 2), {sig_CE}); // INIT = 10
|
||||
auto it_CE = bit_to_lut.find(sig_CE);
|
||||
if (it_CE != bit_to_lut.end())
|
||||
lut_ce = it_CE->second.first;
|
||||
if (sig_CE.wire) {
|
||||
// Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
|
||||
if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
|
||||
continue;
|
||||
|
||||
// If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset
|
||||
// as well.
|
||||
if (it_CE != bit_to_lut.end())
|
||||
worthy_post_ce = true;
|
||||
} else if (sig_CE.data != State::S1) {
|
||||
// Strange. Should not happen in a reasonable flow, so bail.
|
||||
log_assert(false); // This DFF is always off
|
||||
continue;
|
||||
} else {
|
||||
lut_d_post_ce = lut_d;
|
||||
}
|
||||
|
||||
// Second, unmap S, if any.
|
||||
lut_d_post_s = lut_d_post_ce;
|
||||
if (has_s) {
|
||||
SigBit sig_S = sigmap(cell->getPort(ID(SLn)));
|
||||
LutData lut_s = LutData(Const(2, 2), {sig_S}); // INIT = 10
|
||||
bool inv_s = true; // active low
|
||||
auto it_S = bit_to_lut.find(sig_S);
|
||||
if (it_S != bit_to_lut.end())
|
||||
lut_s = it_S->second.first;
|
||||
if (sig_S.wire) {
|
||||
// Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
|
||||
if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
|
||||
goto unmap;
|
||||
// If this gets rid of an S LUT, it's worth it.
|
||||
if (it_S != bit_to_lut.end())
|
||||
worthy_post_s = true;
|
||||
} else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
|
||||
// Strange. Should not happen in a reasonable flow, so bail.
|
||||
log_assert(false); // DFF is always in set mode
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Third, unmap R, if any.
|
||||
lut_d_post_r = lut_d_post_s;
|
||||
if (has_r) {
|
||||
SigBit sig_R = sigmap(cell->getPort(ID(SLn)));
|
||||
LutData lut_r = LutData(Const(2, 2), {sig_R}); // INIT = 10
|
||||
bool inv_r = true; // active low
|
||||
auto it_R = bit_to_lut.find(sig_R);
|
||||
if (it_R != bit_to_lut.end())
|
||||
lut_r = it_R->second.first;
|
||||
if (sig_R.wire) {
|
||||
// Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
|
||||
if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
|
||||
goto unmap;
|
||||
// If this gets rid of an S LUT, it's worth it.
|
||||
if (it_R != bit_to_lut.end())
|
||||
worthy_post_r = true;
|
||||
} else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
|
||||
// Strange. Should not happen in a reasonable flow, so bail.
|
||||
log_assert(false); // DFF is always in reset mode
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unmap:
|
||||
|
||||
// SLE cannot have both synchronous set and reset implemented at the same time
|
||||
log_assert(!(worthy_post_r && worthy_post_s));
|
||||
|
||||
LutData final_lut;
|
||||
if (worthy_post_r) {
|
||||
final_lut = lut_d_post_r;
|
||||
} else if (worthy_post_s) {
|
||||
final_lut = lut_d_post_s;
|
||||
} else if (worthy_post_ce) {
|
||||
final_lut = lut_d_post_ce;
|
||||
} else {
|
||||
// Nothing to do here.
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ports;
|
||||
if (worthy_post_r)
|
||||
ports += " + R";
|
||||
if (worthy_post_s)
|
||||
ports += " + S";
|
||||
if (worthy_post_ce)
|
||||
ports += " + CE";
|
||||
log(" Merging D%s LUTs for %s/%s (%d -> %d)\n", ports.c_str(), log_id(cell), log_id(sig_Q.wire),
|
||||
GetSize(lut_d.second), GetSize(final_lut.second));
|
||||
|
||||
// Okay, we're doing it. Unmap ports.
|
||||
if ((has_s && worthy_post_s) || worthy_post_r) {
|
||||
cell->setPort(ID(SLn), Const(1, 1));
|
||||
}
|
||||
|
||||
// if we made it this far, clk enable is always merged into D
|
||||
cell->setPort(ID(EN), Const(1, 1));
|
||||
|
||||
// Create the new LUT.
|
||||
Cell *lut_cell = nullptr;
|
||||
switch (GetSize(final_lut.second)) {
|
||||
case 1:
|
||||
lut_cell = module->addCell(NEW_ID, ID(CFG1));
|
||||
break;
|
||||
case 2:
|
||||
lut_cell = module->addCell(NEW_ID, ID(CFG2));
|
||||
break;
|
||||
case 3:
|
||||
lut_cell = module->addCell(NEW_ID, ID(CFG3));
|
||||
break;
|
||||
case 4:
|
||||
lut_cell = module->addCell(NEW_ID, ID(CFG4));
|
||||
break;
|
||||
default:
|
||||
log_assert(!"unknown lut size");
|
||||
}
|
||||
lut_cell->attributes = cell_d->attributes;
|
||||
Wire *lut_out = module->addWire(NEW_ID);
|
||||
lut_cell->setParam(ID::INIT, final_lut.first);
|
||||
cell->setPort(ID::D, lut_out);
|
||||
lut_cell->setPort(ID::Y, lut_out);
|
||||
lut_cell->setPort(ID(A), final_lut.second[0]);
|
||||
if (GetSize(final_lut.second) >= 2)
|
||||
lut_cell->setPort(ID(B), final_lut.second[1]);
|
||||
if (GetSize(final_lut.second) >= 3)
|
||||
lut_cell->setPort(ID(C), final_lut.second[2]);
|
||||
if (GetSize(final_lut.second) >= 4)
|
||||
lut_cell->setPort(ID(D), final_lut.second[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} MicrochipDffOptPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
95
techlibs/microchip/polarfire_dsp_map.v
Normal file
95
techlibs/microchip/polarfire_dsp_map.v
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 0;
|
||||
parameter B_WIDTH = 0;
|
||||
parameter Y_WIDTH = 0;
|
||||
|
||||
wire [47:0] P_48;
|
||||
// For pin descriptions, see Section 9 of PolarFire FPGA Macro Library Guide:
|
||||
// https://coredocs.s3.amazonaws.com/Libero/2021_2/Tool/pf_mlg.pdf
|
||||
MACC_PA _TECHMAP_REPLACE_ (
|
||||
.DOTP(1'b0),
|
||||
.SIMD(1'b0),
|
||||
.OVFL_CARRYOUT_SEL(1'b0),
|
||||
|
||||
.AL_N(1'b1),
|
||||
.A(A),
|
||||
.A_BYPASS(1'b1),
|
||||
.A_SRST_N(1'b1),
|
||||
.A_EN(1'b1),
|
||||
|
||||
.B(B),
|
||||
.B_BYPASS(1'b1),
|
||||
.B_SRST_N(1'b1),
|
||||
.B_EN(1'b1),
|
||||
|
||||
.D(18'b0),
|
||||
.D_BYPASS(1'b1),
|
||||
.D_ARST_N(1'b1),
|
||||
.D_SRST_N(1'b1),
|
||||
.D_EN(1'b1),
|
||||
|
||||
.CARRYIN(1'b0),
|
||||
.C(48'b0),
|
||||
.C_BYPASS(1'b1),
|
||||
.C_ARST_N(1'b1),
|
||||
.C_SRST_N(1'b1),
|
||||
.C_EN(1'b1),
|
||||
|
||||
|
||||
.P(P_48),
|
||||
|
||||
.P_BYPASS(1'b1),
|
||||
.P_SRST_N(1'b1),
|
||||
.P_EN(1'b1),
|
||||
|
||||
.PASUB(1'b0),
|
||||
.PASUB_BYPASS(1'b1),
|
||||
.PASUB_AD_N(1'b0),
|
||||
.PASUB_SL_N(1'b1),
|
||||
.PASUB_SD_N(1'b0),
|
||||
.PASUB_EN(1'b1),
|
||||
|
||||
.CDIN_FDBK_SEL(2'b00),
|
||||
.CDIN_FDBK_SEL_BYPASS(1'b1),
|
||||
.CDIN_FDBK_SEL_AD_N(2'b00),
|
||||
.CDIN_FDBK_SEL_SL_N(1'b1),
|
||||
.CDIN_FDBK_SEL_SD_N(2'b00),
|
||||
.CDIN_FDBK_SEL_EN(1'b1),
|
||||
|
||||
.ARSHFT17(1'b0),
|
||||
.ARSHFT17_BYPASS(1'b1),
|
||||
.ARSHFT17_AD_N(1'b0),
|
||||
.ARSHFT17_SL_N(1'b1),
|
||||
.ARSHFT17_SD_N(1'b0),
|
||||
.ARSHFT17_EN(1'b1),
|
||||
|
||||
.SUB(1'b0),
|
||||
.SUB_BYPASS(1'b1),
|
||||
.SUB_AD_N(1'b0),
|
||||
.SUB_SL_N(1'b1),
|
||||
.SUB_SD_N(1'b0),
|
||||
.SUB_EN(1'b1)
|
||||
|
||||
);
|
||||
assign Y = P_48;
|
||||
endmodule
|
553
techlibs/microchip/synth_microchip.cc
Normal file
553
techlibs/microchip/synth_microchip.cc
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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/celltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct SynthMicrochipPass : public ScriptPass {
|
||||
SynthMicrochipPass() : ScriptPass("synth_microchip", "synthesis for Microchip FPGAs") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_microchip [options]\n");
|
||||
log("\n");
|
||||
log("This command runs synthesis for Microchip FPGAs. This command creates \n");
|
||||
log("netlists that are compatible with Microchip PolarFire devices. \n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as the top module\n");
|
||||
log("\n");
|
||||
log(" -family <family>\n");
|
||||
log(" Run synthesis for the specified Microchip architecture. \n");
|
||||
log(" Generate the synthesis netlist for the specified family.\n");
|
||||
log(" supported values:\n");
|
||||
log(" - polarfire: PolarFire\n");
|
||||
log("\n");
|
||||
log(" -edif <file>\n");
|
||||
log(" Write the design to the specified edif file. Writing of an output file\n");
|
||||
log(" is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -blif <file>\n");
|
||||
log(" Write the design to the specified BLIF file. Writing of an output file\n");
|
||||
log(" is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -vlog <file>\n");
|
||||
log(" write the design to the specified Verilog file. writing of an output\n");
|
||||
log(" file is omitted if this parameter is not specified.\n");
|
||||
log(" -nobram\n");
|
||||
log(" Do not use block RAM cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nocarry\n");
|
||||
log(" Do not use ARI1 cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nodsp\n");
|
||||
log(" Do not use MATH blocks to implement multipliers and associated logic\n");
|
||||
log("\n");
|
||||
log(" -noiopad\n");
|
||||
log(" Disable I/O buffer insertion (useful for hierarchical or \n");
|
||||
log(" out-of-context flows)\n");
|
||||
log("\n");
|
||||
log(" -noclkbuf\n");
|
||||
log(" Disable automatic clock buffer insertion\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\n");
|
||||
log(" Only run the commands between the labels (see below). an empty\n");
|
||||
log(" 'from_label' is synonymous to 'begin', and empty 'to_label' is\n");
|
||||
log(" synonymous to the end of the command list.\n");
|
||||
log("\n");
|
||||
log(" -noflatten\n");
|
||||
log(" do not flatten design before synthesis\n");
|
||||
log("\n");
|
||||
log(" -dff\n");
|
||||
log(" Run 'abc'/'abc9' with -dff option\n");
|
||||
log("\n");
|
||||
log(" -retime\n");
|
||||
log(" Run 'abc' with '-D 1' option to enable flip-flop retiming.\n");
|
||||
log(" implies -dff.\n");
|
||||
log("\n");
|
||||
log(" -noabc9\n");
|
||||
log(" Use classic ABC flow instead of ABC9\n");
|
||||
log("\n");
|
||||
log(" -discard-ffinit\n");
|
||||
log(" discard FF init value instead of emitting an error\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
|
||||
std::string top_opt, edif_file, blif_file, vlog_file, family;
|
||||
bool flatten, retime, noiopad, noclkbuf, nobram, nocarry, nowidelut, nodsp;
|
||||
bool abc9, dff;
|
||||
bool discard_ffinit;
|
||||
int lut_size;
|
||||
|
||||
// debug dump switches
|
||||
bool debug_memory, debug_carry;
|
||||
|
||||
void clear_flags() override
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
edif_file.clear();
|
||||
blif_file.clear();
|
||||
vlog_file.clear();
|
||||
family = "polarfire";
|
||||
flatten = true;
|
||||
retime = false;
|
||||
noiopad = false;
|
||||
noclkbuf = false;
|
||||
nocarry = false;
|
||||
nobram = false;
|
||||
nowidelut = false;
|
||||
nodsp = false;
|
||||
abc9 = true;
|
||||
dff = false;
|
||||
lut_size = 4;
|
||||
discard_ffinit = false;
|
||||
|
||||
debug_memory = false;
|
||||
debug_carry = false;
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
std::string run_from, run_to;
|
||||
clear_flags();
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx + 1 < args.size()) {
|
||||
family = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-edif" && argidx + 1 < args.size()) {
|
||||
edif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-blif" && argidx + 1 < args.size()) {
|
||||
blif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vlog" && argidx + 1 < args.size()) {
|
||||
vlog_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||
size_t pos = args[argidx + 1].find(':');
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
run_from = args[++argidx].substr(0, pos);
|
||||
run_to = args[argidx].substr(pos + 1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-retime") {
|
||||
dff = true;
|
||||
retime = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nocarry") {
|
||||
nocarry = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nowidelut") {
|
||||
nowidelut = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-iopad") {
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noiopad") {
|
||||
noiopad = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noclkbuf") {
|
||||
noclkbuf = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nocarry") {
|
||||
nocarry = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noabc9") {
|
||||
abc9 = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodsp") {
|
||||
nodsp = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-dff") {
|
||||
dff = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-debug_memory") {
|
||||
debug_memory = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-debug_carry") {
|
||||
debug_carry = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-discard-ffinit") {
|
||||
discard_ffinit = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (family == "polarfire") {
|
||||
lut_size = 4;
|
||||
} else {
|
||||
log_cmd_error("Invalid Microchip -family setting: '%s'.\n", family.c_str());
|
||||
}
|
||||
|
||||
if (!design->full_selection())
|
||||
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||
|
||||
if (abc9 && retime)
|
||||
log_cmd_error("-retime option not currently compatible with -abc9!\n");
|
||||
|
||||
log_header(design, "Executing SYNTH_MICROCHIP pass.\n");
|
||||
log_push();
|
||||
|
||||
run_script(design, run_from, run_to);
|
||||
|
||||
log_pop();
|
||||
}
|
||||
|
||||
void script() override
|
||||
{
|
||||
std::string lut_size_s = std::to_string(lut_size);
|
||||
if (help_mode)
|
||||
lut_size_s = "[4]";
|
||||
|
||||
if (check_label("begin")) {
|
||||
std::string read_args;
|
||||
read_args += " -lib -specify +/microchip/cells_sim.v";
|
||||
run("read_verilog" + read_args);
|
||||
|
||||
run(stringf("hierarchy -check %s", top_opt.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("prepare")) {
|
||||
run("proc");
|
||||
if (flatten || help_mode)
|
||||
run("flatten", "(with '-flatten')");
|
||||
if (active_design)
|
||||
active_design->scratchpad_unset("tribuf.added_something");
|
||||
run("tribuf -logic");
|
||||
if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
|
||||
log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
|
||||
run("deminout");
|
||||
run("opt_expr");
|
||||
run("opt_clean");
|
||||
run("check");
|
||||
run("opt -nodffe -nosdff");
|
||||
run("fsm");
|
||||
run("opt");
|
||||
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
}
|
||||
|
||||
if (check_label("map_dsp", "(skip if '-nodsp')")) {
|
||||
if (!nodsp || help_mode) {
|
||||
run("memory_dff"); // microchip_dsp will merge registers, reserve memory port registers first
|
||||
if (help_mode)
|
||||
run("techmap -map +/mul2dsp.v -map +/microchip/{family}_dsp_map.v {options}");
|
||||
else if (family == "polarfire") // Microchip - map multipliers to DSP
|
||||
run("techmap -map +/mul2dsp.v -map +/microchip/polarfire_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
|
||||
"-D DSP_A_MAXWIDTH_PARTIAL=18 " // Partial multipliers are intentionally
|
||||
// limited to 18x18 in order to take
|
||||
// advantage of the (PCOUT >> 17) -> PCIN
|
||||
// dedicated cascade chain capability
|
||||
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
|
||||
"-D DSP_Y_MINWIDTH=9 "
|
||||
"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
|
||||
|
||||
run("select a:mul2dsp");
|
||||
run("setattr -unset mul2dsp");
|
||||
run("opt_expr -fine");
|
||||
run("wreduce");
|
||||
run("select -clear");
|
||||
if (help_mode)
|
||||
run("microchip_dsp -family <family>");
|
||||
else if (family == "polarfire") // Microchip - absorb cells into DSP
|
||||
run("microchip_dsp -family " + family);
|
||||
|
||||
run("chtype -set $mul t:$__soft_mul");
|
||||
}
|
||||
}
|
||||
|
||||
if (check_label("coarse")) {
|
||||
run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=" + lut_size_s);
|
||||
run("alumacc");
|
||||
run("share");
|
||||
run("opt");
|
||||
run("memory -nomap");
|
||||
run("opt_clean");
|
||||
if (discard_ffinit || help_mode)
|
||||
run("attrmap -remove init", "(only if -discard-ffinit)");
|
||||
}
|
||||
|
||||
if (check_label("map_memory")) {
|
||||
std::string params = "";
|
||||
std::string LSRAM_map = "+/microchip/LSRAM_map.v";
|
||||
std::string uSRAM_map = "+/microchip/uSRAM_map.v";
|
||||
if (debug_memory)
|
||||
run("write_verilog -noexpr memory_map_pre.vm");
|
||||
if (help_mode) {
|
||||
params = " [...]";
|
||||
} else {
|
||||
|
||||
if (family == "polarfire") {
|
||||
// cost of a single bit for memory lowered to soft logic
|
||||
params += " -logic-cost-rom 0.015625";
|
||||
|
||||
params += " -lib +/microchip/LSRAM.txt";
|
||||
params += " -lib +/microchip/uSRAM.txt";
|
||||
LSRAM_map = "+/microchip/LSRAM_map.v";
|
||||
uSRAM_map = "+/microchip/uSRAM_map.v";
|
||||
}
|
||||
if (nobram)
|
||||
params += " -no-auto-block";
|
||||
}
|
||||
|
||||
// transform memories into intermediate cells
|
||||
// Cost based transformation. The cost is assigned by us for each cell.
|
||||
run("memory_libmap" + params);
|
||||
if (debug_memory)
|
||||
run("write_verilog -noexpr memory_map_libmap.vm");
|
||||
|
||||
// map intermediate cells to actual RAM macros
|
||||
// NOTE: order doesnt matter here
|
||||
run("techmap -map " + LSRAM_map);
|
||||
run("techmap -map " + uSRAM_map);
|
||||
if (debug_memory)
|
||||
run("write_verilog -noexpr memory_map_final.vm");
|
||||
}
|
||||
|
||||
if (check_label("map_ffram")) {
|
||||
run("opt -fast -full");
|
||||
|
||||
// blast unmapped RAM to flops or LUTs
|
||||
run("memory_map");
|
||||
}
|
||||
|
||||
if (check_label("fine")) {
|
||||
run("opt -full");
|
||||
|
||||
if (debug_carry)
|
||||
run("write_verilog -noexpr ARI1_cells.vm");
|
||||
|
||||
if (!nocarry) {
|
||||
// converts $mux -> $_MUX_ to allow muxcover to work
|
||||
run("simplemap t:$mux");
|
||||
|
||||
// converts $and/$or/$xor to gate representation for extract_reduce to work
|
||||
run("simplemap t:$xor"); // only mapping reduce_xor
|
||||
|
||||
// mapping based on Yosys internal gates
|
||||
if (debug_carry)
|
||||
run("write_verilog -noexpr ARI1_pre.vm");
|
||||
|
||||
// collapse $_AND_/$_OR_/$_XOR_ chains into reduction cells
|
||||
run("extract_reduce");
|
||||
|
||||
if (debug_carry)
|
||||
run("write_verilog -noexpr ARI1_extract_reduce.vm");
|
||||
|
||||
// pack mux trees into $_MUX4_
|
||||
run("muxcover -nodecode -mux4=220");
|
||||
|
||||
if (debug_carry)
|
||||
run("write_verilog -noexpr ARI1_muxcover.vm");
|
||||
|
||||
run("techmap -map +/microchip/arith_map.v");
|
||||
if (debug_carry)
|
||||
run("write_verilog -noexpr ARI1_post.vm");
|
||||
}
|
||||
|
||||
// convert all remaining cells to gates
|
||||
run("techmap -map +/techmap.v");
|
||||
|
||||
run("opt -fast");
|
||||
}
|
||||
|
||||
if (check_label("map_cells")) {
|
||||
// Needs to be done before logic optimization, so that inverters (inserted
|
||||
// here because of negative-polarity output enable) are handled.
|
||||
if (help_mode || !noiopad) {
|
||||
run("iopadmap -bits -inpad INBUF Y:PAD -outpad OUTBUF D:PAD -toutpad TRIBUFF E:D:PAD -tinoutpad BIBUF E:Y:D:PAD",
|
||||
"(unless -noiobs)");
|
||||
}
|
||||
|
||||
std::string techmap_args = "-map +/techmap.v -map +/microchip/cells_map.v";
|
||||
run("techmap " + techmap_args);
|
||||
run("clean");
|
||||
}
|
||||
|
||||
if (check_label("map_ffs")) {
|
||||
// dfflegalize : Converts FFs to types supported by the target
|
||||
// this can convert less capable cells into more capable cells (e.g. dff -> dffe)
|
||||
|
||||
// Based on PolarFire® FPGA Macro Library Guide
|
||||
// D-flop:
|
||||
// active high enable
|
||||
// active low clear or active low set
|
||||
// Latch:
|
||||
// active low clear or active low set
|
||||
// SLE (can implement D-flop/Latch):
|
||||
// active high EN
|
||||
// active low async load (set/reset) with static load configuration via ADn (Q = ~ADn)
|
||||
// active low sync load (set/reset) with static load configuration via SD
|
||||
// static latch configuration bit
|
||||
// init not supported
|
||||
|
||||
// Yosys internal cell description
|
||||
// see: https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/formats/cell_library.html
|
||||
// see: common/simcells.v
|
||||
// $_DFF_[NP]_ (regular dff)
|
||||
// $_DFFE_[NP][NP]_ (enable)
|
||||
// $_DFF_[NP][NP][01]_ (async reset to 0/1)
|
||||
// $_DFFE_[NP][NP][01][NP]_ (async reset to 0/1 + enable)
|
||||
// $_ALDFF_[NP][NP]_ (async load)
|
||||
// $_ALDFFE_[NP][NP][NP]_ (async load + enable)
|
||||
// $_DFFSR_[NP][NP][NP]_ (async set & reset)
|
||||
// $_DFFSRE_[NP][NP][NP][NP]_ (async set & reset + enable)
|
||||
// $_SDFF_[NP][NP][01]_ (sync reset to 0/1)
|
||||
// $_SDFFE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, reset prioritize over enable)
|
||||
// $_SDFFCE_[NP][NP][01][NP]_ (sync reset to 0/1 + enable, enable prioritize over reset)
|
||||
// $_SR_[NP][NP]_ (set/reset latch)
|
||||
// $_DLATCH_[NP]_ (D-latch)
|
||||
// $_DLATCH_[NP][NP][01]_ (D-latch + reset to 0/1)
|
||||
// $_DLATCHSR_[NP][NP][NP]_ (D-latch + set + reset)
|
||||
|
||||
if (family == "polarfire") {
|
||||
std::string params = "";
|
||||
|
||||
// D-flop with async reset and enable
|
||||
// posedge CLK, active low reset to 1 or 0, active high EN
|
||||
params += " -cell $_DFFE_PN?P_ x";
|
||||
|
||||
// D-flop with sync reset and enable, enable takes priority over reset
|
||||
// posedge CLK, active low reset to 1 or 0, active high EN
|
||||
params += " -cell $_SDFFCE_PN?P_ x";
|
||||
|
||||
// D-latch + reset to 0/1
|
||||
// posedge CLK, active low reset to 1 or 0
|
||||
params += " -cell $_DLATCH_PN?_ x";
|
||||
|
||||
run("dfflegalize" + params, "(Converts FFs to supported types)");
|
||||
}
|
||||
|
||||
if (abc9 || help_mode) {
|
||||
if (dff || help_mode)
|
||||
run("zinit -all w:* t:$_SDFFCE_*", "('-dff' only)");
|
||||
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "('-abc9' only)");
|
||||
}
|
||||
}
|
||||
|
||||
if (check_label("map_luts")) {
|
||||
run("opt_expr -mux_undef -noclkinv");
|
||||
if (help_mode)
|
||||
run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')");
|
||||
else if (abc9) {
|
||||
|
||||
std::string abc9_opts;
|
||||
// for the if command in abc to specify wire delay between adjacent LUTs (default = 0)
|
||||
// NOTE: should not have 0 wire delay between LUTs,
|
||||
// otherwise abc might use LUT2+LUT3 instead of single LUT4
|
||||
abc9_opts += " -W 300";
|
||||
if (nowidelut)
|
||||
abc9_opts += stringf(" -maxlut %d", lut_size);
|
||||
if (dff)
|
||||
abc9_opts += " -dff";
|
||||
run("abc9" + abc9_opts);
|
||||
} else {
|
||||
std::string abc_opts = " -lut " + lut_size_s;
|
||||
if (dff)
|
||||
abc_opts += " -dff";
|
||||
if (retime)
|
||||
abc_opts += " -D 1";
|
||||
run("abc" + abc_opts);
|
||||
}
|
||||
run("clean");
|
||||
|
||||
if (help_mode || !abc9)
|
||||
run("techmap -D NO_LUT -map +/microchip/cells_map.v", "(only if not '-abc9')");
|
||||
std::string techmap_args = "-map +/microchip/cells_map.v -D FINAL_MAP";
|
||||
techmap_args += " -D LUT_WIDTH=" + lut_size_s;
|
||||
run("techmap " + techmap_args);
|
||||
|
||||
if (help_mode || lut_size == 4)
|
||||
run("microchip_dffopt");
|
||||
}
|
||||
|
||||
run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD");
|
||||
|
||||
run("clean -purge");
|
||||
|
||||
if (check_label("check")) {
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
run("blackbox =A:whitebox");
|
||||
}
|
||||
|
||||
if (check_label("edif")) {
|
||||
if (!edif_file.empty() || help_mode)
|
||||
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("blif")) {
|
||||
if (!blif_file.empty() || help_mode)
|
||||
run(stringf("write_blif %s", blif_file.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("vlog"))
|
||||
{
|
||||
if (!vlog_file.empty() || help_mode)
|
||||
run(stringf("write_verilog %s", help_mode ? "<file-name>" : vlog_file.c_str()));
|
||||
}
|
||||
}
|
||||
} SynthMicrochipPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
69
techlibs/microchip/uSRAM.txt
Normal file
69
techlibs/microchip/uSRAM.txt
Normal file
|
@ -0,0 +1,69 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
# asynchronous read
|
||||
ram block $__uSRAM_AR_ {
|
||||
|
||||
#(LSRAM cost)/3
|
||||
cost 43;
|
||||
|
||||
# INIT supported
|
||||
init any;
|
||||
|
||||
abits 6;
|
||||
widths 12 per_port;
|
||||
|
||||
# single write enable wire
|
||||
port sw "W" {
|
||||
clock posedge;
|
||||
|
||||
# collision not supported, but write takes precedence and read data is invalid while writing to
|
||||
# the same address
|
||||
wrtrans all new;
|
||||
|
||||
optional;
|
||||
}
|
||||
port ar "R" {
|
||||
optional;
|
||||
}
|
||||
}
|
||||
|
||||
# synchronous read
|
||||
# NOTE: synchronous read can be realized by the address pipeline register or data pipeline register.
|
||||
# This assumes address is synchronized
|
||||
ram block $__uSRAM_SR_ {
|
||||
|
||||
cost 42;
|
||||
|
||||
init any;
|
||||
abits 6;
|
||||
widths 12 per_port;
|
||||
|
||||
port sw "W" {
|
||||
clock posedge;
|
||||
|
||||
# collision not supported
|
||||
wrtrans all new;
|
||||
|
||||
optional;
|
||||
}
|
||||
port sr "R" {
|
||||
clock posedge;
|
||||
rden;
|
||||
rdinit none;
|
||||
optional;
|
||||
}
|
||||
}
|
126
techlibs/microchip/uSRAM_map.v
Normal file
126
techlibs/microchip/uSRAM_map.v
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// See document PolarFire Family Fabric User Guide
|
||||
// section 4.2 for port list.
|
||||
|
||||
// Asynchronous read
|
||||
module $__uSRAM_AR_ (...);
|
||||
|
||||
parameter INIT = 0;
|
||||
parameter ADDR_BITS = 6;
|
||||
|
||||
parameter PORT_W_WIDTH = 12;
|
||||
parameter PORT_R_WIDTH = 12;
|
||||
parameter PORT_R_USED = 0;
|
||||
parameter PORT_W_USED = 0;
|
||||
|
||||
input PORT_W_CLK;
|
||||
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||
input PORT_W_WR_EN;
|
||||
|
||||
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||
|
||||
`include "brams_defs.vh"
|
||||
|
||||
RAM64x12 #(
|
||||
`PARAMS_INIT_uSRAM
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.R_ADDR(PORT_R_ADDR),
|
||||
.R_ADDR_BYPASS(1'b1),
|
||||
.R_ADDR_EN(1'b0),
|
||||
.R_ADDR_SL_N(1'b1),
|
||||
.R_ADDR_SD(1'b0),
|
||||
.R_ADDR_AL_N(1'b1),
|
||||
.R_ADDR_AD_N(1'b0),
|
||||
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
|
||||
.R_DATA(PORT_R_RD_DATA),
|
||||
.R_DATA_BYPASS(1'b1),
|
||||
.R_DATA_EN(1'b0),
|
||||
.R_DATA_SL_N(1'b1),
|
||||
.R_DATA_SD(1'b0),
|
||||
.R_DATA_AL_N(1'b1),
|
||||
.R_DATA_AD_N(1'b0),
|
||||
|
||||
.W_CLK(PORT_W_CLK),
|
||||
.W_ADDR(PORT_W_ADDR),
|
||||
.W_DATA(PORT_W_WR_DATA),
|
||||
.W_EN(PORT_W_WR_EN),
|
||||
|
||||
.BUSY_FB(1'b0)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
// Synchronous read
|
||||
module $__uSRAM_SR_ (...);
|
||||
|
||||
parameter INIT = 0;
|
||||
parameter ADDR_BITS = 6;
|
||||
|
||||
parameter PORT_W_WIDTH = 12;
|
||||
parameter PORT_R_WIDTH = 12;
|
||||
parameter PORT_R_USED = 0;
|
||||
parameter PORT_W_USED = 0;
|
||||
|
||||
input PORT_W_CLK;
|
||||
input [ADDR_BITS-1:0] PORT_W_ADDR;
|
||||
input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
|
||||
input PORT_W_WR_EN;
|
||||
|
||||
// Read port clock and enable signal
|
||||
// that async read uSRAM doesn't have
|
||||
input PORT_R_CLK;
|
||||
input PORT_R_RD_EN;
|
||||
input [ADDR_BITS-1:0] PORT_R_ADDR;
|
||||
output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
|
||||
|
||||
`include "brams_defs.vh"
|
||||
|
||||
RAM64x12 #(
|
||||
`PARAMS_INIT_uSRAM
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.R_CLK(PORT_R_CLK),
|
||||
.R_ADDR(PORT_R_ADDR),
|
||||
.R_ADDR_BYPASS(1'b0),
|
||||
.R_ADDR_EN(PORT_R_RD_EN),
|
||||
.R_ADDR_SL_N(1'b1),
|
||||
.R_ADDR_SD(1'b0),
|
||||
.R_ADDR_AL_N(1'b1),
|
||||
.R_ADDR_AD_N(1'b0),
|
||||
.BLK_EN(PORT_R_USED ? 1'b1 : 1'b0),
|
||||
.R_DATA(PORT_R_RD_DATA),
|
||||
.R_DATA_BYPASS(1'b1),
|
||||
.R_DATA_EN(1'b0),
|
||||
.R_DATA_SL_N(1'b1),
|
||||
.R_DATA_SD(1'b0),
|
||||
.R_DATA_AL_N(1'b1),
|
||||
.R_DATA_AD_N(1'b0),
|
||||
|
||||
.W_CLK(PORT_W_CLK),
|
||||
.W_ADDR(PORT_W_ADDR),
|
||||
.W_DATA(PORT_W_WR_DATA),
|
||||
.W_EN(PORT_W_WR_EN),
|
||||
|
||||
.BUSY_FB(1'b0)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
4
tests/arch/microchip/.gitignore
vendored
Normal file
4
tests/arch/microchip/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
*.log
|
||||
/run-test.mk
|
||||
*.vm
|
||||
|
76
tests/arch/microchip/dff.ys
Normal file
76
tests/arch/microchip/dff.ys
Normal file
|
@ -0,0 +1,76 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
# active low async reset with enable
|
||||
read_verilog <<EOT
|
||||
module top(
|
||||
input clk,
|
||||
input en,
|
||||
input rst,
|
||||
input D,
|
||||
output reg Q
|
||||
);
|
||||
always @(posedge clk, negedge rst) begin
|
||||
if (rst == 0) begin
|
||||
Q <= 1;
|
||||
end else if(en) begin
|
||||
Q <= D;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top top -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||
|
||||
design -reset
|
||||
read_verilog -D NO_INIT ../common/dffs.v
|
||||
synth_microchip -top dff -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||
|
||||
design -reset
|
||||
read_verilog -D NO_INIT ../common/dffs.v
|
||||
synth_microchip -top dffe -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||
|
||||
design -reset
|
||||
read_verilog -D NO_INIT ../common/adffs.v
|
||||
synth_microchip -top adff -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-count 1 t:CFG1
|
||||
select -assert-none t:SLE t:CLKBUF t:CFG1 %% t:* %D
|
||||
|
||||
design -reset
|
||||
read_verilog -D NO_INIT ../common/adffs.v
|
||||
synth_microchip -top adffn -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-none t:SLE t:CLKBUF %% t:* %D
|
||||
|
||||
design -reset
|
||||
read_verilog -D NO_INIT ../common/adffs.v
|
||||
synth_microchip -top dffs -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-count 1 t:CFG1
|
||||
select -assert-none t:SLE t:CLKBUF t:CFG1 %% t:* %D
|
42
tests/arch/microchip/dff_opt.ys
Normal file
42
tests/arch/microchip/dff_opt.ys
Normal file
|
@ -0,0 +1,42 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
# reset can be merged into D LUT
|
||||
read_verilog <<EOT
|
||||
module dff_opt(
|
||||
input clk,
|
||||
input [1:0] D_comb,
|
||||
input [1:0] EN_comb,
|
||||
input [1:0] RST_comb,
|
||||
output bar
|
||||
);
|
||||
reg foo;
|
||||
assign bar = foo;
|
||||
always@(posedge clk) begin
|
||||
if (&RST_comb) begin
|
||||
foo <= 0;
|
||||
end else begin
|
||||
foo <= &D_comb;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top dff_opt -family polarfire -noiopad
|
||||
select -assert-count 1 t:SLE
|
||||
select -assert-count 1 t:CFG4
|
||||
select -assert-count 1 t:CLKBUF
|
||||
select -assert-none t:SLE t:CFG4 t:CLKBUF %% t:* %D
|
211
tests/arch/microchip/dsp.ys
Normal file
211
tests/arch/microchip/dsp.ys
Normal file
|
@ -0,0 +1,211 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
# pre-adder
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module pre_adder(
|
||||
input signed [5:0] in_A,
|
||||
input signed [4:0] in_B,
|
||||
input signed [4:0] in_D,
|
||||
output [11:0] out_Y
|
||||
);
|
||||
assign out_Y = in_A * (in_B + in_D);
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top pre_adder -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# post-adder
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module post_adder(
|
||||
input signed[17:0] in_A,
|
||||
input signed [17:0] in_B,
|
||||
input signed [17:0] in_C,
|
||||
output signed [35:0] out_Y
|
||||
);
|
||||
assign out_Y = (in_B*in_A)+in_C;
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top post_adder -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# pre-adder + post-adder
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module pre_post_adder(
|
||||
input signed[5:0] in_A,
|
||||
input signed [4:0] in_B,
|
||||
input signed [11:0] in_C,
|
||||
input signed [4:0] in_D,
|
||||
output signed [12:0] out_Y
|
||||
);
|
||||
assign out_Y = ((in_D + in_B)*in_A)+in_C;
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top pre_post_adder -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
|
||||
# multiply accumulate
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module mac(
|
||||
input clk,
|
||||
input signed [4:0] in_A,
|
||||
input signed [4:0] in_B,
|
||||
input signed [4:0] in_D,
|
||||
input srst_P,
|
||||
output reg signed [11:0] out_P
|
||||
);
|
||||
always@(posedge clk) begin
|
||||
if (~srst_P) begin
|
||||
out_P <= 12'h000;
|
||||
end else begin
|
||||
out_P <= in_A * (in_B + in_D) + out_P;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top mac -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
|
||||
# cascade
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module cas(
|
||||
input signed [5:0] in_A,
|
||||
input signed [4:0] in_B,
|
||||
input signed [4:0] in_D,
|
||||
input signed [4:0] casA,
|
||||
input signed [4:0] casB,
|
||||
output signed [11:0] out_P
|
||||
);
|
||||
wire signed [9:0] cascade;
|
||||
assign cascade = casA * casB;
|
||||
assign out_P = in_A * (in_B + in_D) + cascade;
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top cas -family polarfire -noiopad
|
||||
select -assert-count 2 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# carryout
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module carryout (cout,out,a, b,c);
|
||||
parameter n = 6;
|
||||
parameter k = 2;
|
||||
output reg [k*(n+1)-1:0] out;
|
||||
output reg cout;
|
||||
input [n:0] a;
|
||||
input [n:0] b;
|
||||
input [n-1:0] c;
|
||||
always @(*)
|
||||
begin
|
||||
{cout,out} = a * b + c;
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top carryout -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# pipeline registers
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module pipeline(
|
||||
input clk,
|
||||
input srst_A,
|
||||
input srst_B,
|
||||
input srst_D,
|
||||
input srst_P,
|
||||
input arst_D,
|
||||
input srst_C,
|
||||
input signed [5:0] in_A,
|
||||
input signed [4:0] in_B,
|
||||
input signed [4:0] in_C,
|
||||
input signed [4:0] in_D,
|
||||
output reg [11:0] out_P
|
||||
);
|
||||
wire srst_A_N;
|
||||
wire srst_B_N;
|
||||
wire srst_C_N;
|
||||
wire srst_D_N;
|
||||
wire srst_P_N;
|
||||
assign srst_A_N = ~srst_A;
|
||||
assign srst_B_N = ~srst_B;
|
||||
assign srst_C_N = ~srst_C;
|
||||
assign srst_D_N = ~srst_D;
|
||||
assign srst_P_N = ~srst_P;
|
||||
|
||||
reg signed [5:0] reg_A;
|
||||
reg signed [4:0] reg_B;
|
||||
reg signed [4:0] reg_C;
|
||||
reg signed [4:0] reg_D;
|
||||
|
||||
always@(posedge clk) begin // sync reset A
|
||||
// if (~srst_A_N) begin
|
||||
if (srst_A_N) begin
|
||||
reg_A = 6'b000000;
|
||||
end else begin
|
||||
reg_A = in_A;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge clk) begin // sync reset B
|
||||
if (srst_B_N) begin
|
||||
reg_B = 5'b00000;
|
||||
end else begin
|
||||
reg_B = in_B;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge clk, negedge arst_D) begin // async reset D
|
||||
if (~arst_D) begin
|
||||
reg_D = 5'b00000;
|
||||
end else begin
|
||||
reg_D = in_D;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge clk) begin // sync reset C
|
||||
if (srst_C_N) begin
|
||||
reg_C = 5'b00000;
|
||||
end else begin
|
||||
reg_C = in_C;
|
||||
end
|
||||
end
|
||||
|
||||
// sync reset P
|
||||
always@(posedge clk) begin
|
||||
if (srst_P_N) begin
|
||||
out_P = 12'h000;
|
||||
end else begin
|
||||
out_P = reg_A * (reg_B + reg_D) + reg_C;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top pipeline -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
51
tests/arch/microchip/mult.ys
Normal file
51
tests/arch/microchip/mult.ys
Normal file
|
@ -0,0 +1,51 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
# regular unsigned multiply
|
||||
read_verilog ../common/mul.v
|
||||
chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16
|
||||
hierarchy -top top
|
||||
proc
|
||||
synth_microchip -family polarfire -noiopad
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# regular signed multiply
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module signed_mult(
|
||||
input signed [17:0] in_A,
|
||||
input signed [17:0] in_B,
|
||||
output signed [35:0] out_Y
|
||||
);
|
||||
assign out_Y = in_A * in_B;
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top signed_mult -family polarfire -noiopad
|
||||
select -assert-count 1 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
||||
|
||||
# wide multiply
|
||||
design -reset
|
||||
read_verilog ../common/mul.v
|
||||
chparam -set X_WIDTH 30 -set Y_WIDTH 16 -set A_WIDTH 46
|
||||
hierarchy -top top
|
||||
proc
|
||||
synth_microchip -family polarfire -noiopad
|
||||
cd top # Constrain all select calls below inside the top module
|
||||
select -assert-count 2 t:MACC_PA
|
||||
select -assert-none t:MACC_PA %% t:* %D
|
50
tests/arch/microchip/ram_SDP.ys
Normal file
50
tests/arch/microchip/ram_SDP.ys
Normal file
|
@ -0,0 +1,50 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module ram_SDP(data,waddr,we,clk,q);
|
||||
parameter d_width = 32;
|
||||
parameter addr_width = 8;
|
||||
parameter mem_depth = 256;
|
||||
input [d_width-1:0] data;
|
||||
input [addr_width-1:0] waddr;
|
||||
input we, clk;
|
||||
output reg [d_width-1:0] q;
|
||||
|
||||
reg [d_width-1:0] mem [mem_depth-1:0];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (we) begin
|
||||
mem[waddr] <= data;
|
||||
end else begin
|
||||
q <= mem[waddr];
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top ram_SDP -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM1K20
|
||||
select -assert-count 1 t:CFG1
|
||||
select -assert-none t:RAM1K20 t:CFG1 %% t:* %D
|
||||
|
||||
# very similar to ram_SDP.v, except read enable is always active
|
||||
design -reset
|
||||
read_verilog ../common/blockram.v
|
||||
hierarchy -top sync_ram_sdp
|
||||
chparam -set DATA_WIDTH 32 -set ADDRESS_WIDTH 8
|
||||
synth_microchip -top sync_ram_sdp -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM1K20
|
||||
select -assert-none t:RAM1K20 %% t:* %D
|
64
tests/arch/microchip/ram_TDP.ys
Normal file
64
tests/arch/microchip/ram_TDP.ys
Normal file
|
@ -0,0 +1,64 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module ram_TDP (clka,clkb,wea,addra,dataina,qa,web,addrb,datainb,qb);
|
||||
parameter addr_width = 10;
|
||||
parameter data_width = 2;
|
||||
input clka,clkb,wea,web;
|
||||
input [data_width - 1 : 0] dataina,datainb;
|
||||
input [addr_width - 1 : 0] addra,addrb;
|
||||
output reg [data_width - 1 : 0] qa,qb;
|
||||
reg [addr_width - 1 : 0] addra_reg, addrb_reg;
|
||||
reg [data_width - 1 : 0] mem [(2**addr_width) - 1 : 0];
|
||||
|
||||
always @ (posedge clka)
|
||||
begin
|
||||
addra_reg <= addra;
|
||||
|
||||
if(wea) begin
|
||||
mem[addra] <= dataina;
|
||||
qa <= dataina;
|
||||
end else begin
|
||||
qa <= mem[addra];
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clkb)
|
||||
begin
|
||||
addrb_reg <= addrb;
|
||||
if(web) begin
|
||||
mem[addrb] <= datainb;
|
||||
qb <= datainb;
|
||||
end else begin
|
||||
qb <= mem[addrb];
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top ram_TDP -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM1K20
|
||||
select -assert-none t:RAM1K20 %% t:* %D
|
||||
|
||||
# similar to ram_TDP.v, but different write mode and read_enable=~write_enable
|
||||
design -reset
|
||||
read_verilog ../common/blockram.v
|
||||
hierarchy -top sync_ram_tdp
|
||||
chparam -set DATA_WIDTH 2 -set ADDRESS_WIDTH 10
|
||||
synth_microchip -top sync_ram_tdp -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM1K20
|
||||
select -assert-count 2 t:CFG1
|
||||
select -assert-none t:RAM1K20 t:CFG1 %% t:* %D
|
28
tests/arch/microchip/reduce.ys
Normal file
28
tests/arch/microchip/reduce.ys
Normal file
|
@ -0,0 +1,28 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module reduce(
|
||||
input [7:0] data,
|
||||
output Y
|
||||
);
|
||||
assign Y = ^data;
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top reduce -family polarfire -noiopad
|
||||
select -assert-count 1 t:XOR8
|
||||
select -assert-none t:XOR8 %% t:* %D
|
||||
|
4
tests/arch/microchip/run-test.sh
Executable file
4
tests/arch/microchip/run-test.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
22
tests/arch/microchip/simple_ram.ys
Normal file
22
tests/arch/microchip/simple_ram.ys
Normal file
|
@ -0,0 +1,22 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog ../common/blockram.v
|
||||
hierarchy -top sync_ram_sp
|
||||
chparam -set DATA_WIDTH 20 -set ADDRESS_WIDTH 10
|
||||
synth_microchip -top sync_ram_sp -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM1K20
|
||||
select -assert-none t:RAM1K20 %% t:* %D
|
40
tests/arch/microchip/uram_ar.ys
Normal file
40
tests/arch/microchip/uram_ar.ys
Normal file
|
@ -0,0 +1,40 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module uram_ar(data,waddr,we,clk,q);
|
||||
parameter d_width = 12;
|
||||
parameter addr_width = 2;
|
||||
parameter mem_depth = 12;
|
||||
input [d_width-1:0] data;
|
||||
input [addr_width-1:0] waddr;
|
||||
input we, clk;
|
||||
output [d_width-1:0] q;
|
||||
|
||||
reg [d_width-1:0] mem [mem_depth-1:0];
|
||||
assign q = mem[waddr];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (we)
|
||||
mem[waddr] <= data;
|
||||
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
synth_microchip -top uram_ar -family polarfire -noiopad
|
||||
select -assert-count 1 t:RAM64x12
|
||||
select -assert-none t:RAM64x12 %% t:* %D
|
45
tests/arch/microchip/uram_sr.ys
Normal file
45
tests/arch/microchip/uram_sr.ys
Normal file
|
@ -0,0 +1,45 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module uram_sr(clk, wr, raddr, din, waddr, dout);
|
||||
input clk;
|
||||
input [11:0] din;
|
||||
input wr;
|
||||
input [5:0] waddr, raddr;
|
||||
output [11:0] dout;
|
||||
reg [5:0] raddr_reg;
|
||||
reg [11:0] mem [0:63];
|
||||
assign dout = mem[raddr_reg];
|
||||
integer i;
|
||||
initial begin
|
||||
for (i = 0; i < 64; i = i + 1) begin
|
||||
mem[i] = 12'hfff;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge clk) begin
|
||||
raddr_reg <= raddr;
|
||||
if(wr)
|
||||
mem[waddr]<= din;
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
synth_microchip -top uram_sr -family polarfire -noiopad
|
||||
|
||||
select -assert-count 1 t:RAM64x12
|
||||
select -assert-none t:RAM64x12 %% t:* %D
|
41
tests/arch/microchip/widemux.ys
Normal file
41
tests/arch/microchip/widemux.ys
Normal file
|
@ -0,0 +1,41 @@
|
|||
# ISC License
|
||||
#
|
||||
# Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
|
||||
#
|
||||
# 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.
|
||||
|
||||
read_verilog <<EOT
|
||||
module widemux(
|
||||
input [3:0] data,
|
||||
input S0,
|
||||
input S1,
|
||||
output Y
|
||||
);
|
||||
assign Y = S1 ? (S0 ? data[3] : data[1]) : (S0 ? data[2] : data[0]);
|
||||
endmodule
|
||||
EOT
|
||||
synth_microchip -top widemux -family polarfire -noiopad
|
||||
select -assert-count 1 t:MX4
|
||||
select -assert-none t:MX4 %% t:* %D
|
||||
|
||||
# RTL style is different here forming a different structure
|
||||
read_verilog ../common/mux.v
|
||||
design -save read
|
||||
|
||||
hierarchy -top mux4
|
||||
proc
|
||||
equiv_opt -assert -map +/microchip/cells_sim.v synth_microchip -top mux4 -family polarfire -noiopad
|
||||
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||
cd mux4 # Constrain all select calls below inside the top module
|
||||
select -assert-count 3 t:CFG3
|
||||
select -assert-none t:CFG3 %% t:* %D
|
|
@ -33,7 +33,7 @@ hierarchy -auto-top
|
|||
|
||||
design -save orig
|
||||
proc
|
||||
select -assert-count 1 t:$memrd_v2
|
||||
select -assert-count 1 t:$memrd_v2 a:src %i
|
||||
memory
|
||||
opt_dff
|
||||
design -stash postopt
|
||||
|
@ -80,7 +80,7 @@ hierarchy -auto-top
|
|||
|
||||
design -save orig
|
||||
proc
|
||||
select -assert-count 1 t:$memrd_v2
|
||||
select -assert-count 1 t:$memrd_v2 a:src %i
|
||||
memory
|
||||
opt_dff
|
||||
design -stash postopt
|
||||
|
@ -127,7 +127,7 @@ hierarchy -auto-top
|
|||
|
||||
design -save orig
|
||||
proc
|
||||
select -assert-count 1 t:$memrd_v2
|
||||
select -assert-count 1 t:$memrd_v2 a:src %i
|
||||
memory
|
||||
opt_dff
|
||||
design -stash postopt
|
||||
|
@ -175,7 +175,7 @@ hierarchy -auto-top
|
|||
|
||||
design -save orig
|
||||
proc
|
||||
select -assert-count 1 t:$memrd_v2
|
||||
select -assert-count 1 t:$memrd_v2 a:src %i
|
||||
memory
|
||||
opt_dff
|
||||
design -stash postopt
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue