Merge remote-tracking branch 'origin/master' into xaig_arrival

This commit is contained in:
Eddie Hung 2019-08-23 11:26:55 -07:00
commit d672b1ddec
28 changed files with 1110 additions and 114 deletions

View File

@ -6,3 +6,4 @@ brew "git"
brew "graphviz" brew "graphviz"
brew "pkg-config" brew "pkg-config"
brew "python3" brew "python3"
brew "tcl-tk"

View File

@ -1,4 +1,4 @@
Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@ -91,8 +91,10 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
ifneq ($(shell which brew),) ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt BREW_PREFIX := $(shell brew --prefix)/opt
$(info $$BREW_PREFIX is [${BREW_PREFIX}]) $(info $$BREW_PREFIX is [${BREW_PREFIX}])
ifeq ($(ENABLE_PYOSYS),1)
CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
LDFLAGS += -L$(BREW_PREFIX)/boost/lib LDFLAGS += -L$(BREW_PREFIX)/boost/lib
endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)

View File

@ -1,7 +1,7 @@
``` ```
yosys -- Yosys Open SYnthesis Suite yosys -- Yosys Open SYnthesis Suite
Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@ -69,11 +69,14 @@ prerequisites for building yosys:
graphviz xdot pkg-config python3 libboost-system-dev \ graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: Similarily, on Mac OS X Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle $ brew tap Homebrew/bundle && brew bundle
or MacPorts:
$ sudo port install bison flex readline gawk libffi \ $ sudo port install bison flex readline gawk libffi \
git graphviz pkgconfig python36 boost zlib git graphviz pkgconfig python36 boost zlib tcl
On FreeBSD use the following command to install all prerequisites: On FreeBSD use the following command to install all prerequisites:

View File

@ -150,6 +150,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true; reg->is_reg = true;
reg->is_signed = node->is_signed; reg->is_signed = node->is_signed;
for (auto &it : node->attributes)
if (it.first != ID(mem2reg))
reg->attributes.emplace(it.first, it.second->clone());
reg->filename = node->filename;
reg->linenum = node->linenum;
children.push_back(reg); children.push_back(reg);
while (reg->simplify(true, false, false, 1, -1, false, false)) { } while (reg->simplify(true, false, false, 1, -1, false, false)) { }
} }

View File

@ -129,7 +129,7 @@ void yosys_banner()
log(" | |\n"); log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n"); log(" | |\n");
log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n"); log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n"); log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n");

View File

@ -532,10 +532,10 @@ struct EquivMakePass : public Pass {
log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str()); log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str());
if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes()) if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes())
log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes()) if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes())
log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
worker.read_blacklists(); worker.read_blacklists();
worker.read_encfiles(); worker.read_encfiles();

View File

@ -369,7 +369,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : module->cells()) for (auto cell : module->cells())
if (design->selected(module, cell) && cell->type[0] == '$') { if (design->selected(module, cell) && cell->type[0] == '$') {
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) &&
cell->getPort(ID::A).size() == 1 && cell->getPort(ID::Y).size() == 1) GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A)); invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A));
if (cell->type.in(ID($mux), ID($_MUX_)) && if (cell->type.in(ID($mux), ID($_MUX_)) &&
cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0)) cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0))
@ -740,12 +740,34 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else else
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID::Y).size())); replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y))));
goto next_cell; goto next_cell;
} }
} }
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 && if (cell->type.in(ID($shiftx), ID($shift))) {
SigSpec sig_a = assign_map(cell->getPort(ID::A));
int width;
bool trim_x = cell->type == ID($shiftx) || !keepdc;
bool trim_0 = cell->type == ID($shift);
for (width = GetSize(sig_a); width > 1; width--) {
if ((trim_x && sig_a[width-1] == State::Sx) ||
(trim_0 && sig_a[width-1] == State::S0))
continue;
break;
}
if (width < GetSize(sig_a)) {
cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str());
sig_a.remove(width, GetSize(sig_a)-width);
cell->setPort(ID::A, sig_a);
cell->setParam(ID(A_WIDTH), width);
did_something = true;
goto next_cell;
}
}
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 &&
invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { invert_map.count(assign_map(cell->getPort(ID::A))) != 0) {
cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A))));
@ -1142,7 +1164,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { if (mux_undef && cell->type.in(ID($mux), ID($pmux))) {
RTLIL::SigSpec new_a, new_b, new_s; RTLIL::SigSpec new_a, new_b, new_s;
int width = cell->getPort(ID::A).size(); int width = GetSize(cell->getPort(ID::A));
if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) ||
cell->getPort(ID(S)).is_fully_undef()) { cell->getPort(ID(S)).is_fully_undef()) {
cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());

View File

@ -4,7 +4,7 @@
# -------------------------------------- # --------------------------------------
OBJS += passes/pmgen/test_pmgen.o OBJS += passes/pmgen/test_pmgen.o
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# -------------------------------------- # --------------------------------------

View File

@ -1,7 +1,7 @@
OBJS += techlibs/anlogic/synth_anlogic.o OBJS += techlibs/anlogic/synth_anlogic.o
OBJS += techlibs/anlogic/anlogic_eqn.o OBJS += techlibs/anlogic/anlogic_eqn.o
OBJS += techlibs/anlogic/anlogic_determine_init.o OBJS += techlibs/anlogic/anlogic_fixcarry.o
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v))

View File

@ -1,72 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*
* 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/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct AnlogicDetermineInitPass : public Pass {
AnlogicDetermineInitPass() : Pass("anlogic_determine_init", "Anlogic: Determine the init value of cells") { }
void help() YS_OVERRIDE
{
log("\n");
log(" anlogic_determine_init [selection]\n");
log("\n");
log("Determine the init value of cells that doesn't allow unknown init value.\n");
log("\n");
}
Const determine_init(Const init)
{
for (int i = 0; i < GetSize(init); i++) {
if (init[i] != State::S0 && init[i] != State::S1)
init[i] = State::S0;
}
return init;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ANLOGIC_DETERMINE_INIT pass (determine init value for cells).\n");
extra_args(args, args.size(), design);
int cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
{
if (cell->type == "\\EG_LOGIC_DRAM16X4")
{
cell->setParam("\\INIT_D0", determine_init(cell->getParam("\\INIT_D0")));
cell->setParam("\\INIT_D1", determine_init(cell->getParam("\\INIT_D1")));
cell->setParam("\\INIT_D2", determine_init(cell->getParam("\\INIT_D2")));
cell->setParam("\\INIT_D3", determine_init(cell->getParam("\\INIT_D3")));
cnt++;
}
}
}
log_header(design, "Updated %d cells with determined init value.\n", cnt);
}
} AnlogicDetermineInitPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,130 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.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/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static SigBit get_bit_or_zero(const SigSpec &sig)
{
if (GetSize(sig) == 0)
return State::S0;
return sig[0];
}
static void fix_carry_chain(Module *module)
{
SigMap sigmap(module);
pool<SigBit> ci_bits;
dict<SigBit, SigBit> mapping_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\AL_MAP_ADDER") {
if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
if (bit_i0 == State::S0 && bit_i1== State::S0) {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigSpec o = cell->getPort("\\o");
if (GetSize(o) == 2) {
SigBit bit_o = o[0];
ci_bits.insert(bit_ci);
mapping_bits[bit_ci] = bit_o;
}
}
}
}
vector<Cell*> adders_to_fix_cells;
for (auto cell : module->cells())
{
if (cell->type == "\\AL_MAP_ADDER") {
if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
SigBit canonical_bit = sigmap(bit_ci);
if (!ci_bits.count(canonical_bit))
continue;
if (bit_i0 == State::S0 && bit_i1== State::S0)
continue;
adders_to_fix_cells.push_back(cell);
log("Found %s cell named %s with invalid 'c' signal.\n", log_id(cell->type), log_id(cell));
}
}
for (auto cell : adders_to_fix_cells)
{
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigBit canonical_bit = sigmap(bit_ci);
auto bit = mapping_bits.at(canonical_bit);
log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER");
SigBit new_bit = module->addWire(NEW_ID);
SigBit dummy_bit = module->addWire(NEW_ID);
SigSpec bits;
bits.append(dummy_bit);
bits.append(new_bit);
c->setParam("\\ALUTYPE", Const("ADD_CARRY"));
c->setPort("\\a", bit);
c->setPort("\\b", State::S0);
c->setPort("\\c", State::S0);
c->setPort("\\o", bits);
cell->setPort("\\c", new_bit);
}
}
struct AnlogicCarryFixPass : public Pass {
AnlogicCarryFixPass() : Pass("anlogic_fixcarry", "Anlogic: fix carry chain") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" anlogic_fixcarry [options] [selection]\n");
log("\n");
log("Add Anlogic adders to fix carry chain if needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing anlogic_fixcarry pass (fix invalid carry chain).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
fix_carry_chain(module);
}
} AnlogicCarryFixPass;
PRIVATE_NAMESPACE_END

View File

@ -31,7 +31,10 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
output CO; output [Y_WIDTH-1:0] CO;
wire CIx;
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
@ -41,15 +44,16 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH-1:0] C = { COx, CIx };
wire [Y_WIDTH+2:0] C = {COx, CI};
wire dummy; wire dummy;
AL_MAP_ADDER #( AL_MAP_ADDER #(
.ALUTYPE("ADD_CARRY")) .ALUTYPE("ADD_CARRY"))
adder_cin ( adder_cin (
.a(C[0]), .a(CI),
.o({COx[0], dummy}) .b(1'b0),
.c(1'b0),
.o({CIx, dummy})
); );
genvar i; genvar i;
@ -59,18 +63,22 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
) adder_i ( ) adder_i (
.a(AA[i]), .a(AA[i]),
.b(BB[i]), .b(BB[i]),
.c(C[i+1]), .c(C[i]),
.o({COx[i+1],Y[i]}) .o({COx[i],Y[i]})
); );
end: slice
wire cout;
AL_MAP_ADDER #(
.ALUTYPE("ADD"))
adder_cout (
.a(1'b0),
.b(1'b0),
.c(COx[i]),
.o({cout, CO[i]})
);
end: slice
endgenerate endgenerate
/* End implementation */
AL_MAP_ADDER #( /* End implementation */
.ALUTYPE("ADD")) assign X = AA ^ BB;
adder_cout ( endmodule
.c(C[Y_WIDTH+1]),
.o(COx[Y_WIDTH+1])
);
assign CO = COx[Y_WIDTH+1];
assign X = AA ^ BB;
endmodule

View File

@ -154,7 +154,7 @@ struct SynthAnlogicPass : public ScriptPass
{ {
run("memory_bram -rules +/anlogic/drams.txt"); run("memory_bram -rules +/anlogic/drams.txt");
run("techmap -map +/anlogic/drams_map.v"); run("techmap -map +/anlogic/drams_map.v");
run("anlogic_determine_init"); run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
} }
if (check_label("fine")) if (check_label("fine"))
@ -186,6 +186,11 @@ struct SynthAnlogicPass : public ScriptPass
{ {
run("techmap -map +/anlogic/cells_map.v"); run("techmap -map +/anlogic/cells_map.v");
run("clean"); run("clean");
}
if (check_label("map_anlogic"))
{
run("anlogic_fixcarry");
run("anlogic_eqn"); run("anlogic_eqn");
} }

View File

@ -17,10 +17,12 @@ endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, lib_whitebox *) (* abc_box_id=1, lib_whitebox *)
module CCU2C( module CCU2C(
(* abc_carry *) input CIN, (* abc_carry *)
input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1, input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1, output S0, S1,
(* abc_carry *) output COUT (* abc_carry *)
output COUT
); );
parameter [15:0] INIT0 = 16'h0000; parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000; parameter [15:0] INIT1 = 16'h0000;
@ -113,7 +115,8 @@ module TRELLIS_DPR16X4 (
input WRE, input WRE,
input WCK, input WCK,
input [3:0] RAD, input [3:0] RAD,
/* (* abc_arrival=<TODO> *) */ output [3:0] DO /* (* abc_arrival=<TODO> *) */
output [3:0] DO
); );
parameter WCKMUX = "WCK"; parameter WCKMUX = "WCK";
parameter WREMUX = "WRE"; parameter WREMUX = "WRE";

View File

@ -0,0 +1,10 @@
OBJS += techlibs/efinix/synth_efinix.o
OBJS += techlibs/efinix/efinix_gbuf.o
OBJS += techlibs/efinix/efinix_fixcarry.o
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt))

View File

@ -0,0 +1,79 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* 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.
*
*/
(* techmap_celltype = "$alu" *)
module _80_efinix_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;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] X, Y;
input CI, BI;
output [Y_WIDTH-1:0] CO;
wire CIx;
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH-1:0] C = { COx, CIx };
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_cin (
.I0(CI),
.I1(1'b1),
.CI(1'b0),
.CO(CIx)
);
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_i (
.I0(AA[i]),
.I1(BB[i]),
.CI(C[i]),
.O(Y[i]),
.CO(COx[i])
);
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_cout (
.I0(1'b0),
.I1(1'b0),
.CI(COx[i]),
.O(CO[i])
);
end: slice
endgenerate
/* End implementation */
assign X = AA ^ BB;
endmodule

32
techlibs/efinix/bram.txt Normal file
View File

@ -0,0 +1,32 @@
bram $__EFINIX_5K
init 1
abits 8 @a8d16
dbits 16 @a8d16
abits 9 @a9d8
dbits 8 @a9d8
abits 10 @a10d4
dbits 4 @a10d4
abits 11 @a11d2
dbits 2 @a11d2
abits 12 @a12d1
dbits 1 @a12d1
abits 8 @a8d20
dbits 20 @a8d20
abits 9 @a9d10
dbits 10 @a9d10
groups 2
ports 1 1
wrmode 1 0
enable 1 1
transp 0 2
clocks 2 3
clkpol 2 3
endbram
match $__EFINIX_5K
min bits 256
min efficiency 5
shuffle_enable B
endmatch

View File

@ -0,0 +1,65 @@
module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 8;
parameter CFG_DBITS = 20;
parameter CFG_ENABLE_A = 1;
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
parameter [5119:0] INIT = 5119'bx;
parameter TRANSP2 = 0;
input CLK2;
input CLK3;
input [CFG_ABITS-1:0] A1ADDR;
input [CFG_DBITS-1:0] A1DATA;
input [CFG_ENABLE_A-1:0] A1EN;
input [CFG_ABITS-1:0] B1ADDR;
output [CFG_DBITS-1:0] B1DATA;
input B1EN;
localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST";
EFX_RAM_5K #(
.READ_WIDTH(CFG_DBITS),
.WRITE_WIDTH(CFG_DBITS),
.OUTPUT_REG(1'b0),
.RCLK_POLARITY(1'b1),
.RE_POLARITY(1'b1),
.WCLK_POLARITY(1'b1),
.WE_POLARITY(1'b1),
.WCLKE_POLARITY(1'b1),
.WRITE_MODE(WRITEMODE_A),
.INIT_0(INIT[ 0*256 +: 256]),
.INIT_1(INIT[ 1*256 +: 256]),
.INIT_2(INIT[ 2*256 +: 256]),
.INIT_3(INIT[ 3*256 +: 256]),
.INIT_4(INIT[ 4*256 +: 256]),
.INIT_5(INIT[ 5*256 +: 256]),
.INIT_6(INIT[ 6*256 +: 256]),
.INIT_7(INIT[ 7*256 +: 256]),
.INIT_8(INIT[ 8*256 +: 256]),
.INIT_9(INIT[ 9*256 +: 256]),
.INIT_A(INIT[10*256 +: 256]),
.INIT_B(INIT[11*256 +: 256]),
.INIT_C(INIT[12*256 +: 256]),
.INIT_D(INIT[13*256 +: 256]),
.INIT_E(INIT[14*256 +: 256]),
.INIT_F(INIT[15*256 +: 256]),
.INIT_10(INIT[16*256 +: 256]),
.INIT_11(INIT[17*256 +: 256]),
.INIT_12(INIT[18*256 +: 256]),
.INIT_13(INIT[19*256 +: 256])
) _TECHMAP_REPLACE_ (
.WDATA(A1DATA),
.WADDR(A1ADDR),
.WE(A1EN),
.WCLK(CLK2),
.WCLKE(1'b1),
.RDATA(B1DATA),
.RADDR(B1ADDR),
.RE(B1EN),
.RCLK(CLK3)
);
endmodule

View File

@ -0,0 +1,45 @@
module \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
input [WIDTH-1:0] A;
output Y;
generate
if (WIDTH == 1) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
end else
if (WIDTH == 2) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
end else
if (WIDTH == 3) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
end else
if (WIDTH == 4) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif

107
techlibs/efinix/cells_sim.v Normal file
View File

@ -0,0 +1,107 @@
module EFX_LUT4(
output O,
input I0,
input I1,
input I2,
input I3
);
parameter LUTMASK = 16'h0000;
endmodule
module EFX_ADD(
output O,
output CO,
input I0,
input I1,
input CI
);
parameter I0_POLARITY = 1;
parameter I1_POLARITY = 1;
endmodule
module EFX_FF(
output Q,
input D,
input CE,
input CLK,
input SR
);
parameter CLK_POLARITY = 1;
parameter CE_POLARITY = 1;
parameter SR_POLARITY = 1;
parameter SR_SYNC = 0;
parameter SR_VALUE = 0;
parameter SR_SYNC_PRIORITY = 0;
parameter D_POLARITY = 1;
endmodule
module EFX_GBUFCE(
input CE,
input I,
output O
);
parameter CE_POLARITY = 1'b1;
endmodule
module EFX_RAM_5K(
input [WRITE_WIDTH-1:0] WDATA,
input [WRITE_ADDR_WIDTH-1:0] WADDR,
input WE,
input WCLK,
input WCLKE,
output [READ_WIDTH-1:0] RDATA,
input [READ_ADDR_WIDTH-1:0] RADDR,
input RE,
input RCLK
);
parameter READ_WIDTH = 20;
parameter WRITE_WIDTH = 20;
parameter OUTPUT_REG = 1'b0;
parameter RCLK_POLARITY = 1'b1;
parameter RE_POLARITY = 1'b1;
parameter WCLK_POLARITY = 1'b1;
parameter WE_POLARITY = 1'b1;
parameter WCLKE_POLARITY = 1'b1;
parameter WRITE_MODE = "READ_FIRST";
parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
localparam READ_ADDR_WIDTH =
(READ_WIDTH == 16) ? 8 : // 256x16
(READ_WIDTH == 8) ? 9 : // 512x8
(READ_WIDTH == 4) ? 10 : // 1024x4
(READ_WIDTH == 2) ? 11 : // 2048x2
(READ_WIDTH == 1) ? 12 : // 4096x1
(READ_WIDTH == 20) ? 8 : // 256x20
(READ_WIDTH == 10) ? 9 : // 512x10
(READ_WIDTH == 5) ? 10 : -1; // 1024x5
localparam WRITE_ADDR_WIDTH =
(WRITE_WIDTH == 16) ? 8 : // 256x16
(WRITE_WIDTH == 8) ? 9 : // 512x8
(WRITE_WIDTH == 4) ? 10 : // 1024x4
(WRITE_WIDTH == 2) ? 11 : // 2048x2
(WRITE_WIDTH == 1) ? 12 : // 4096x1
(WRITE_WIDTH == 20) ? 8 : // 256x20
(WRITE_WIDTH == 10) ? 9 : // 512x10
(WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
endmodule

View File

@ -0,0 +1,122 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.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/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static SigBit get_bit_or_zero(const SigSpec &sig)
{
if (GetSize(sig) == 0)
return State::S0;
return sig[0];
}
static void fix_carry_chain(Module *module)
{
SigMap sigmap(module);
pool<SigBit> ci_bits;
dict<SigBit, SigBit> mapping_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_ADD") {
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
if (bit_i0 == State::S0 && bit_i1== State::S0) {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit bit_o = sigmap(cell->getPort("\\O"));
ci_bits.insert(bit_ci);
mapping_bits[bit_ci] = bit_o;
}
}
}
vector<Cell*> adders_to_fix_cells;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_ADD") {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
SigBit canonical_bit = sigmap(bit_ci);
if (!ci_bits.count(canonical_bit))
continue;
if (bit_i0 == State::S0 && bit_i1== State::S0)
continue;
adders_to_fix_cells.push_back(cell);
log("Found %s cell named %s with invalid CI signal.\n", log_id(cell->type), log_id(cell));
}
}
for (auto cell : adders_to_fix_cells)
{
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit canonical_bit = sigmap(bit_ci);
auto bit = mapping_bits.at(canonical_bit);
log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
Cell *c = module->addCell(NEW_ID, "\\EFX_ADD");
SigBit new_bit = module->addWire(NEW_ID);
c->setParam("\\I0_POLARITY", State::S1);
c->setParam("\\I1_POLARITY", State::S1);
c->setPort("\\I0", bit);
c->setPort("\\I1", State::S1);
c->setPort("\\CI", State::S0);
c->setPort("\\CO", new_bit);
cell->setPort("\\CI", new_bit);
}
}
struct EfinixCarryFixPass : public Pass {
EfinixCarryFixPass() : Pass("efinix_fixcarry", "Efinix: fix carry chain") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" efinix_fixcarry [options] [selection]\n");
log("\n");
log("Add Efinix adders to fix carry chain if needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
fix_carry_chain(module);
}
} EfinixCarryFixPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,119 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* 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/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void handle_gbufs(Module *module)
{
SigMap sigmap(module);
pool<SigBit> clk_bits;
dict<SigBit, SigBit> rewrite_bits;
vector<pair<Cell*, SigBit>> pad_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_FF") {
for (auto bit : sigmap(cell->getPort("\\CLK")))
clk_bits.insert(bit);
}
if (cell->type == "\\EFX_RAM_5K") {
for (auto bit : sigmap(cell->getPort("\\RCLK")))
clk_bits.insert(bit);
for (auto bit : sigmap(cell->getPort("\\WCLK")))
clk_bits.insert(bit);
}
}
for (auto wire : vector<Wire*>(module->wires()))
{
if (!wire->port_input)
continue;
for (int index = 0; index < GetSize(wire); index++)
{
SigBit bit(wire, index);
SigBit canonical_bit = sigmap(bit);
if (!clk_bits.count(canonical_bit))
continue;
Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE");
SigBit new_bit = module->addWire(NEW_ID);
c->setParam("\\CE_POLARITY", State::S1);
c->setPort("\\O", new_bit);
c->setPort("\\CE", State::S1);
pad_bits.push_back(make_pair(c, bit));
rewrite_bits[canonical_bit] = new_bit;
log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
}
}
auto rewrite_function = [&](SigSpec &s) {
for (auto &bit : s) {
SigBit canonical_bit = sigmap(bit);
if (rewrite_bits.count(canonical_bit))
bit = rewrite_bits.at(canonical_bit);
}
};
module->rewrite_sigspecs(rewrite_function);
for (auto &it : pad_bits)
it.first->setPort("\\I", it.second);
}
struct EfinixGbufPass : public Pass {
EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" efinix_gbuf [options] [selection]\n");
log("\n");
log("Add Efinix global clock buffers to top module as needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
handle_gbufs(module);
}
} EfinixGbufPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,219 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2019 Clifford Wolf <clifford@clifford.at>
*
* 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/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SynthEfinixPass : public ScriptPass
{
SynthEfinixPass() : ScriptPass("synth_efinix", "synthesis for Efinix FPGAs") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" synth_efinix [options]\n");
log("\n");
log("This command runs synthesis for Efinix FPGAs.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module\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(" -json <file>\n");
log(" write the design to the specified JSON file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\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(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
string top_opt, edif_file, json_file;
bool flatten, retime;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
edif_file = "";
json_file = "";
flatten = true;
retime = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
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] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx];
continue;
}
if (args[argidx] == "-json" && argidx+1 < args.size()) {
json_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") {
retime = true;
continue;
}
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_EFINIX pass.\n");
log_push();
run_script(design, run_from, run_to);
log_pop();
}
void script() YS_OVERRIDE
{
if (check_label("begin"))
{
run("read_verilog -lib +/efinix/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
run("tribuf -logic");
run("deminout");
}
if (check_label("coarse"))
{
run("synth -run coarse");
}
if (check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/efinix/bram.txt");
run("techmap -map +/efinix/brams_map.v");
run("setundef -zero -params t:EFX_RAM_5K");
}
if (check_label("fine"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
}
if (check_label("map_ffs"))
{
run("dffsr2dff");
run("techmap -D NO_LUT -map +/efinix/cells_map.v");
run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit");
run("opt_expr -mux_undef");
run("simplemap");
}
if (check_label("map_luts"))
{
run("abc -lut 4");
run("clean");
}
if (check_label("map_cells"))
{
run("techmap -map +/efinix/cells_map.v");
run("clean");
}
if (check_label("map_gbuf"))
{
run("efinix_gbuf");
run("efinix_fixcarry");
run("clean");
}
if (check_label("check"))
{
run("hierarchy -check");
run("stat");
run("check -noinit");
}
if (check_label("edif"))
{
if (!edif_file.empty() || help_mode)
run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
}
if (check_label("json"))
{
if (!json_file.empty() || help_mode)
run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
}
}
} SynthEfinixPass;
PRIVATE_NAMESPACE_END

View File

@ -143,11 +143,13 @@ endmodule
(* abc_box_id = 1, lib_whitebox *) (* abc_box_id = 1, lib_whitebox *)
module \$__ICE40_FULL_ADDER ( module \$__ICE40_FULL_ADDER (
(* abc_carry *) output CO, (* abc_carry *)
output CO,
output O, output O,
input A, input A,
input B, input B,
(* abc_carry *) input CI (* abc_carry *)
input CI
); );
SB_CARRY carry ( SB_CARRY carry (
.I0(A), .I0(A),

View File

@ -175,9 +175,11 @@ endmodule
(* abc_box_id = 4, lib_whitebox *) (* abc_box_id = 4, lib_whitebox *)
module CARRY4( module CARRY4(
(* abc_carry *) output [3:0] CO, (* abc_carry *)
output [3:0] CO,
output [3:0] O, output [3:0] O,
(* abc_carry *) input CI, (* abc_carry *)
input CI,
input CYINIT, input CYINIT,
input [3:0] DI, S input [3:0] DI, S
); );
@ -299,7 +301,8 @@ endmodule
module RAM32X1D ( module RAM32X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO, (* abc_arrival=1153 *)
output DPO, SPO,
input D, input D,
input WCLK, input WCLK,
input WE, input WE,
@ -319,7 +322,8 @@ endmodule
module RAM64X1D ( module RAM64X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO, (* abc_arrival=1153 *)
output DPO, SPO,
input D, input D,
input WCLK, input WCLK,
input WE, input WE,
@ -339,7 +343,8 @@ endmodule
module RAM128X1D ( module RAM128X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO, (* abc_arrival=1153 *)
output DPO, SPO,
input D, input D,
input WCLK, input WCLK,
input WE, input WE,

View File

@ -221,3 +221,73 @@ check
equiv_opt opt_expr -fine equiv_opt opt_expr -fine
design -load postopt design -load postopt
select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shiftx_1bit(input [2:0] a, input [1:0] b, output y);
\$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shiftx (.A({1'bx,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shiftx r:A_WIDTH=3 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shiftx_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
\$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shiftx (.A({4'bxx00,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shiftx r:A_WIDTH=12 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_1bit(input [2:0] a, input [1:0] b, output y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shift (.A({1'b0,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=3 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=10 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_3bit_keepdc(input [9:0] a, input [3:0] b, output [2:0] y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr -keepdc
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=13 %i

14
tests/various/mem2reg.ys Normal file
View File

@ -0,0 +1,14 @@
read_verilog <<EOT
module top;
parameter DATADEPTH=2;
parameter DATAWIDTH=1;
(* keep, nomem2reg *) reg [DATAWIDTH-1:0] data1 [DATADEPTH-1:0];
(* keep, mem2reg *) reg [DATAWIDTH-1:0] data2 [DATADEPTH-1:0];
endmodule
EOT
proc
cd top
select -assert-count 1 m:data1 a:src=<<EOT:4 %i
select -assert-count 2 w:data2[*] a:src=<<EOT:5 %i
select -assert-none a:mem2reg