mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Merge remote-tracking branch 'origin/master' into xaig_dff
This commit is contained in:
commit
699d8e3939
31
CHANGELOG
31
CHANGELOG
|
@ -3,6 +3,17 @@ List of major changes and improvements between releases
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
|
|
||||||
|
Yosys 0.9 .. Yosys 0.9-dev
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
* Various
|
||||||
|
- Added "write_xaiger" backend
|
||||||
|
- Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs)
|
||||||
|
- Added "synth_xilinx -abc9" (experimental)
|
||||||
|
- Added "synth_ice40 -abc9" (experimental)
|
||||||
|
- Added "synth -abc9" (experimental)
|
||||||
|
|
||||||
|
|
||||||
Yosys 0.8 .. Yosys 0.8-dev
|
Yosys 0.8 .. Yosys 0.8-dev
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
@ -16,12 +27,18 @@ Yosys 0.8 .. Yosys 0.8-dev
|
||||||
- Added "gate2lut.v" techmap rule
|
- Added "gate2lut.v" techmap rule
|
||||||
- Added "rename -src"
|
- Added "rename -src"
|
||||||
- Added "equiv_opt" pass
|
- Added "equiv_opt" pass
|
||||||
|
- Added "shregmap -tech xilinx"
|
||||||
- Added "read_aiger" frontend
|
- Added "read_aiger" frontend
|
||||||
- Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs)
|
- Added "muxcover -mux{4,8,16}=<cost>"
|
||||||
- Added "synth_xilinx -abc9" (experimental)
|
- Added "muxcover -dmux=<cost>"
|
||||||
- Added "synth_ice40 -abc9" (experimental)
|
- Added "muxcover -nopartial"
|
||||||
- Added "synth -abc9" (experimental)
|
- Added "muxpack" pass
|
||||||
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
|
- Added "pmux2shiftx -norange"
|
||||||
|
- Added "synth_xilinx -nocarry"
|
||||||
|
- Added "synth_xilinx -nowidelut"
|
||||||
|
- Added "synth_ecp5 -nowidelut"
|
||||||
|
- "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
|
||||||
|
- Fixed sign extension of unsized constants with 'bx and 'bz MSB
|
||||||
|
|
||||||
|
|
||||||
Yosys 0.7 .. Yosys 0.8
|
Yosys 0.7 .. Yosys 0.8
|
||||||
|
@ -35,7 +52,7 @@ Yosys 0.7 .. Yosys 0.8
|
||||||
- Added "write_verilog -decimal"
|
- Added "write_verilog -decimal"
|
||||||
- Added "scc -set_attr"
|
- Added "scc -set_attr"
|
||||||
- Added "verilog_defines" command
|
- Added "verilog_defines" command
|
||||||
- Remeber defines from one read_verilog to next
|
- Remember defines from one read_verilog to next
|
||||||
- Added support for hierarchical defparam
|
- Added support for hierarchical defparam
|
||||||
- Added FIRRTL back-end
|
- Added FIRRTL back-end
|
||||||
- Improved ABC default scripts
|
- Improved ABC default scripts
|
||||||
|
@ -44,7 +61,7 @@ Yosys 0.7 .. Yosys 0.8
|
||||||
- Added Verilog $rtoi and $itor support
|
- Added Verilog $rtoi and $itor support
|
||||||
- Added "check -initdrv"
|
- Added "check -initdrv"
|
||||||
- Added "read_blif -wideports"
|
- Added "read_blif -wideports"
|
||||||
- Added support for systemVerilog "++" and "--" operators
|
- Added support for SystemVerilog "++" and "--" operators
|
||||||
- Added support for SystemVerilog unique, unique0, and priority case
|
- Added support for SystemVerilog unique, unique0, and priority case
|
||||||
- Added "write_edif" options for edif "flavors"
|
- Added "write_edif" options for edif "flavors"
|
||||||
- Added support for resetall compiler directive
|
- Added support for resetall compiler directive
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -666,6 +666,12 @@ else
|
||||||
SEEDOPT=""
|
SEEDOPT=""
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ABCEXTERNAL),)
|
||||||
|
ABCOPT="-A $(ABCEXTERNAL)"
|
||||||
|
else
|
||||||
|
ABCOPT=""
|
||||||
|
endif
|
||||||
|
|
||||||
test: $(TARGETS) $(EXTRA_TARGETS)
|
test: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
||||||
|
@ -674,13 +680,15 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/techmap && bash run-test.sh
|
+cd tests/techmap && bash run-test.sh
|
||||||
+cd tests/memories && bash run-test.sh $(SEEDOPT)
|
+cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||||
+cd tests/bram && bash run-test.sh $(SEEDOPT)
|
+cd tests/bram && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/various && bash run-test.sh
|
+cd tests/various && bash run-test.sh
|
||||||
+cd tests/sat && bash run-test.sh
|
+cd tests/sat && bash run-test.sh
|
||||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/opt && bash run-test.sh
|
+cd tests/opt && bash run-test.sh
|
||||||
+cd tests/aiger && bash run-test.sh
|
+cd tests/aiger && bash run-test.sh $(ABCOPT)
|
||||||
|
+cd tests/arch && bash run-test.sh
|
||||||
|
+cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Passed \"make test\"."
|
@echo " Passed \"make test\"."
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
|
@ -350,6 +350,14 @@ Verilog Attributes and non-standard features
|
||||||
through the synthesis. When entities are combined, a new |-separated
|
through the synthesis. When entities are combined, a new |-separated
|
||||||
string is created that contains all the string from the original entities.
|
string is created that contains all the string from the original entities.
|
||||||
|
|
||||||
|
- The ``defaultvalue`` attribute is used to store default values for
|
||||||
|
module inputs. The attribute is attached to the input wire by the HDL
|
||||||
|
front-end when the input is declared with a default value.
|
||||||
|
|
||||||
|
- The ``parameter`` and ``localparam`` attributes are used to mark wires
|
||||||
|
that represent module parameters or localparams (when the HDL front-end
|
||||||
|
is run in -pwires mode).
|
||||||
|
|
||||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
||||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||||
|
|
|
@ -70,34 +70,35 @@ struct AigerWriter
|
||||||
|
|
||||||
int bit2aig(SigBit bit)
|
int bit2aig(SigBit bit)
|
||||||
{
|
{
|
||||||
if (aig_map.count(bit) == 0)
|
auto it = aig_map.find(bit);
|
||||||
{
|
if (it != aig_map.end()) {
|
||||||
aig_map[bit] = -1;
|
log_assert(it->second >= 0);
|
||||||
|
return it->second;
|
||||||
if (initstate_bits.count(bit)) {
|
|
||||||
log_assert(initstate_ff > 0);
|
|
||||||
aig_map[bit] = initstate_ff;
|
|
||||||
} else
|
|
||||||
if (not_map.count(bit)) {
|
|
||||||
int a = bit2aig(not_map.at(bit)) ^ 1;
|
|
||||||
aig_map[bit] = a;
|
|
||||||
} else
|
|
||||||
if (and_map.count(bit)) {
|
|
||||||
auto args = and_map.at(bit);
|
|
||||||
int a0 = bit2aig(args.first);
|
|
||||||
int a1 = bit2aig(args.second);
|
|
||||||
aig_map[bit] = mkgate(a0, a1);
|
|
||||||
} else
|
|
||||||
if (alias_map.count(bit)) {
|
|
||||||
aig_map[bit] = bit2aig(alias_map.at(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bit == State::Sx || bit == State::Sz)
|
|
||||||
log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert(aig_map.at(bit) >= 0);
|
// NB: Cannot use iterator returned from aig_map.insert()
|
||||||
return aig_map.at(bit);
|
// since this function is called recursively
|
||||||
|
|
||||||
|
int a = -1;
|
||||||
|
if (not_map.count(bit)) {
|
||||||
|
a = bit2aig(not_map.at(bit)) ^ 1;
|
||||||
|
} else
|
||||||
|
if (and_map.count(bit)) {
|
||||||
|
auto args = and_map.at(bit);
|
||||||
|
int a0 = bit2aig(args.first);
|
||||||
|
int a1 = bit2aig(args.second);
|
||||||
|
a = mkgate(a0, a1);
|
||||||
|
} else
|
||||||
|
if (alias_map.count(bit)) {
|
||||||
|
a = bit2aig(alias_map.at(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit == State::Sx || bit == State::Sz)
|
||||||
|
log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
|
||||||
|
|
||||||
|
log_assert(a >= 0);
|
||||||
|
aig_map[bit] = a;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||||
|
@ -776,6 +777,7 @@ struct AigerBackend : public Backend {
|
||||||
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||||
|
|
||||||
if (!map_filename.empty()) {
|
if (!map_filename.empty()) {
|
||||||
|
rewrite_filename(filename);
|
||||||
std::ofstream mapf;
|
std::ofstream mapf;
|
||||||
mapf.open(map_filename.c_str(), std::ofstream::trunc);
|
mapf.open(map_filename.c_str(), std::ofstream::trunc);
|
||||||
if (mapf.fail())
|
if (mapf.fail())
|
||||||
|
|
|
@ -25,6 +25,21 @@
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#include <libkern/OSByteOrder.h>
|
#include <libkern/OSByteOrder.h>
|
||||||
#define __builtin_bswap32 OSSwapInt32
|
#define __builtin_bswap32 OSSwapInt32
|
||||||
|
#elif !defined(__GNUC__)
|
||||||
|
#include <cstdint>
|
||||||
|
inline uint32_t __builtin_bswap32(uint32_t x)
|
||||||
|
{
|
||||||
|
// https://stackoverflow.com/a/27796212
|
||||||
|
register uint32_t value = number_to_be_reversed;
|
||||||
|
uint8_t lolo = (value >> 0) & 0xFF;
|
||||||
|
uint8_t lohi = (value >> 8) & 0xFF;
|
||||||
|
uint8_t hilo = (value >> 16) & 0xFF;
|
||||||
|
uint8_t hihi = (value >> 24) & 0xFF;
|
||||||
|
return (hihi << 24)
|
||||||
|
| (hilo << 16)
|
||||||
|
| (lohi << 8)
|
||||||
|
| (lolo << 0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "kernel/yosys.h"
|
#include "kernel/yosys.h"
|
||||||
|
@ -79,6 +94,7 @@ struct XAigerWriter
|
||||||
dict<SigBit, int> ordered_latches;
|
dict<SigBit, int> ordered_latches;
|
||||||
|
|
||||||
vector<Cell*> box_list;
|
vector<Cell*> box_list;
|
||||||
|
bool omode = false;
|
||||||
|
|
||||||
//dict<SigBit, int> init_inputs;
|
//dict<SigBit, int> init_inputs;
|
||||||
//int initstate_ff = 0;
|
//int initstate_ff = 0;
|
||||||
|
@ -92,30 +108,37 @@ struct XAigerWriter
|
||||||
|
|
||||||
int bit2aig(SigBit bit)
|
int bit2aig(SigBit bit)
|
||||||
{
|
{
|
||||||
if (aig_map.count(bit) == 0)
|
auto it = aig_map.find(bit);
|
||||||
{
|
if (it != aig_map.end()) {
|
||||||
aig_map[bit] = -1;
|
log_assert(it->second >= 0);
|
||||||
|
return it->second;
|
||||||
if (not_map.count(bit)) {
|
|
||||||
int a = bit2aig(not_map.at(bit)) ^ 1;
|
|
||||||
aig_map[bit] = a;
|
|
||||||
} else
|
|
||||||
if (and_map.count(bit)) {
|
|
||||||
auto args = and_map.at(bit);
|
|
||||||
int a0 = bit2aig(args.first);
|
|
||||||
int a1 = bit2aig(args.second);
|
|
||||||
aig_map[bit] = mkgate(a0, a1);
|
|
||||||
} else
|
|
||||||
if (alias_map.count(bit)) {
|
|
||||||
aig_map[bit] = bit2aig(alias_map.at(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bit == State::Sx || bit == State::Sz)
|
|
||||||
log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert(aig_map.at(bit) >= 0);
|
// NB: Cannot use iterator returned from aig_map.insert()
|
||||||
return aig_map.at(bit);
|
// since this function is called recursively
|
||||||
|
|
||||||
|
int a = -1;
|
||||||
|
if (not_map.count(bit)) {
|
||||||
|
a = bit2aig(not_map.at(bit)) ^ 1;
|
||||||
|
} else
|
||||||
|
if (and_map.count(bit)) {
|
||||||
|
auto args = and_map.at(bit);
|
||||||
|
int a0 = bit2aig(args.first);
|
||||||
|
int a1 = bit2aig(args.second);
|
||||||
|
a = mkgate(a0, a1);
|
||||||
|
} else
|
||||||
|
if (alias_map.count(bit)) {
|
||||||
|
a = bit2aig(alias_map.at(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit == State::Sx || bit == State::Sz) {
|
||||||
|
log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n");
|
||||||
|
a = aig_map.at(State::S0);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(a >= 0);
|
||||||
|
aig_map[bit] = a;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
XAigerWriter(Module *module, bool zinit_mode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
XAigerWriter(Module *module, bool zinit_mode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||||
|
@ -167,9 +190,13 @@ struct XAigerWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire->port_output || keep) {
|
if (wire->port_output || keep) {
|
||||||
if (bit != wirebit)
|
if (bit != RTLIL::Sx) {
|
||||||
alias_map[wirebit] = bit;
|
if (bit != wirebit)
|
||||||
output_bits.insert(wirebit);
|
alias_map[wirebit] = bit;
|
||||||
|
output_bits.insert(wirebit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +301,8 @@ struct XAigerWriter
|
||||||
if (c.second.is_fully_const()) continue;
|
if (c.second.is_fully_const()) continue;
|
||||||
auto is_input = cell->input(c.first);
|
auto is_input = cell->input(c.first);
|
||||||
auto is_output = cell->output(c.first);
|
auto is_output = cell->output(c.first);
|
||||||
log_assert(is_input || is_output);
|
if (!is_input && !is_output)
|
||||||
|
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
|
||||||
|
|
||||||
if (is_input) {
|
if (is_input) {
|
||||||
for (auto b : c.second.bits()) {
|
for (auto b : c.second.bits()) {
|
||||||
|
@ -313,8 +341,6 @@ struct XAigerWriter
|
||||||
for (auto user_cell : it.second)
|
for (auto user_cell : it.second)
|
||||||
toposort.edge(driver_cell, user_cell);
|
toposort.edge(driver_cell, user_cell);
|
||||||
|
|
||||||
pool<RTLIL::Module*> abc_carry_modules;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
toposort.analyze_loops = true;
|
toposort.analyze_loops = true;
|
||||||
#endif
|
#endif
|
||||||
|
@ -322,53 +348,63 @@ struct XAigerWriter
|
||||||
#if 0
|
#if 0
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (auto &it : toposort.loops) {
|
for (auto &it : toposort.loops) {
|
||||||
log(" loop %d", i++);
|
log(" loop %d\n", i++);
|
||||||
for (auto cell : it)
|
for (auto cell_name : it) {
|
||||||
log(" %s", log_id(cell));
|
auto cell = module->cell(cell_name);
|
||||||
log("\n");
|
log_assert(cell);
|
||||||
|
log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
log_assert(no_loops);
|
log_assert(no_loops);
|
||||||
|
|
||||||
|
pool<IdString> seen_boxes;
|
||||||
for (auto cell_name : toposort.sorted) {
|
for (auto cell_name : toposort.sorted) {
|
||||||
RTLIL::Cell *cell = module->cell(cell_name);
|
RTLIL::Cell *cell = module->cell(cell_name);
|
||||||
|
log_assert(cell);
|
||||||
|
|
||||||
RTLIL::Module* box_module = module->design->module(cell->type);
|
RTLIL::Module* box_module = module->design->module(cell->type);
|
||||||
if (!box_module || !box_module->attributes.count("\\abc_box_id"))
|
if (!box_module || !box_module->attributes.count("\\abc_box_id"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
|
if (seen_boxes.insert(cell->type).second) {
|
||||||
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
|
auto it = box_module->attributes.find("\\abc_carry");
|
||||||
RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
|
if (it != box_module->attributes.end()) {
|
||||||
for (const auto &port_name : box_module->ports) {
|
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
|
||||||
RTLIL::Wire* w = box_module->wire(port_name);
|
auto carry_in_out = it->second.decode_string();
|
||||||
log_assert(w);
|
auto pos = carry_in_out.find(',');
|
||||||
if (w->port_input) {
|
if (pos == std::string::npos)
|
||||||
if (w->attributes.count("\\abc_carry_in")) {
|
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
|
||||||
log_assert(!carry_in);
|
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
|
||||||
carry_in = w;
|
carry_in = box_module->wire(carry_in_name);
|
||||||
}
|
if (!carry_in || !carry_in->port_input)
|
||||||
log_assert(!last_in || last_in->port_id < w->port_id);
|
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
|
||||||
last_in = w;
|
|
||||||
}
|
|
||||||
if (w->port_output) {
|
|
||||||
if (w->attributes.count("\\abc_carry_out")) {
|
|
||||||
log_assert(!carry_out);
|
|
||||||
carry_out = w;
|
|
||||||
}
|
|
||||||
log_assert(!last_out || last_out->port_id < w->port_id);
|
|
||||||
last_out = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carry_in) {
|
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
|
||||||
log_assert(last_in);
|
carry_out = box_module->wire(carry_out_name);
|
||||||
std::swap(box_module->ports[carry_in->port_id-1], box_module->ports[last_in->port_id-1]);
|
if (!carry_out || !carry_out->port_output)
|
||||||
std::swap(carry_in->port_id, last_in->port_id);
|
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
|
||||||
}
|
|
||||||
if (carry_out) {
|
auto &ports = box_module->ports;
|
||||||
log_assert(last_out);
|
for (auto jt = ports.begin(); jt != ports.end(); ) {
|
||||||
std::swap(box_module->ports[carry_out->port_id-1], box_module->ports[last_out->port_id-1]);
|
RTLIL::Wire* w = box_module->wire(*jt);
|
||||||
std::swap(carry_out->port_id, last_out->port_id);
|
log_assert(w);
|
||||||
|
if (w == carry_in || w == carry_out) {
|
||||||
|
jt = ports.erase(jt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (w->port_id > carry_in->port_id)
|
||||||
|
--w->port_id;
|
||||||
|
if (w->port_id > carry_out->port_id)
|
||||||
|
--w->port_id;
|
||||||
|
log_assert(w->port_input || w->port_output);
|
||||||
|
log_assert(ports[w->port_id-1] == w->name);
|
||||||
|
++jt;
|
||||||
|
}
|
||||||
|
ports.push_back(carry_in->name);
|
||||||
|
carry_in->port_id = ports.size();
|
||||||
|
ports.push_back(carry_out->name);
|
||||||
|
carry_out->port_id = ports.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,10 +429,16 @@ struct XAigerWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (const auto &b : rhs.bits()) {
|
for (auto b : rhs.bits()) {
|
||||||
SigBit I = sigmap(b);
|
SigBit I = sigmap(b);
|
||||||
if (I != b)
|
if (b == RTLIL::Sx)
|
||||||
alias_map[b] = I;
|
b = RTLIL::S0;
|
||||||
|
else if (I != b) {
|
||||||
|
if (I == RTLIL::Sx)
|
||||||
|
alias_map[b] = RTLIL::S0;
|
||||||
|
else
|
||||||
|
alias_map[b] = I;
|
||||||
|
}
|
||||||
co_bits.emplace_back(b, cell, port_name, offset++, 0);
|
co_bits.emplace_back(b, cell, port_name, offset++, 0);
|
||||||
unused_bits.erase(b);
|
unused_bits.erase(b);
|
||||||
}
|
}
|
||||||
|
@ -437,27 +479,33 @@ struct XAigerWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto bit : input_bits) {
|
for (auto bit : input_bits) {
|
||||||
|
if (!output_bits.count(bit))
|
||||||
|
continue;
|
||||||
RTLIL::Wire *wire = bit.wire;
|
RTLIL::Wire *wire = bit.wire;
|
||||||
// If encountering an inout port, or a keep-ed wire, then create a new wire
|
// If encountering an inout port, or a keep-ed wire, then create a new wire
|
||||||
// with $inout.out suffix, make it a PO driven by the existing inout, and
|
// with $inout.out suffix, make it a PO driven by the existing inout, and
|
||||||
// inherit existing inout's drivers
|
// inherit existing inout's drivers
|
||||||
if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
|
if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
|
||||||
|| wire->attributes.count("\\keep")) {
|
|| wire->attributes.count("\\keep")) {
|
||||||
log_assert(input_bits.count(bit) && output_bits.count(bit));
|
|
||||||
RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
|
RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
|
||||||
RTLIL::Wire *new_wire = module->wire(wire_name);
|
RTLIL::Wire *new_wire = module->wire(wire_name);
|
||||||
if (!new_wire)
|
if (!new_wire)
|
||||||
new_wire = module->addWire(wire_name, GetSize(wire));
|
new_wire = module->addWire(wire_name, GetSize(wire));
|
||||||
SigBit new_bit(new_wire, bit.offset);
|
SigBit new_bit(new_wire, bit.offset);
|
||||||
module->connect(new_bit, bit);
|
module->connect(new_bit, bit);
|
||||||
if (not_map.count(bit))
|
if (not_map.count(bit)) {
|
||||||
not_map[new_bit] = not_map.at(bit);
|
auto a = not_map.at(bit);
|
||||||
else if (and_map.count(bit))
|
not_map[new_bit] = a;
|
||||||
and_map[new_bit] = and_map.at(bit);
|
}
|
||||||
else if (alias_map.count(bit))
|
else if (and_map.count(bit)) {
|
||||||
alias_map[new_bit] = alias_map.at(bit);
|
auto a = and_map.at(bit);
|
||||||
|
and_map[new_bit] = a;
|
||||||
|
}
|
||||||
|
else if (alias_map.count(bit)) {
|
||||||
|
auto a = alias_map.at(bit);
|
||||||
|
alias_map[new_bit] = a;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
//log_abort();
|
|
||||||
alias_map[new_bit] = bit;
|
alias_map[new_bit] = bit;
|
||||||
output_bits.erase(bit);
|
output_bits.erase(bit);
|
||||||
output_bits.insert(new_bit);
|
output_bits.insert(new_bit);
|
||||||
|
@ -590,6 +638,12 @@ struct XAigerWriter
|
||||||
aig_o++;
|
aig_o++;
|
||||||
aig_outputs.push_back(ff_aig_map.at(bit));
|
aig_outputs.push_back(ff_aig_map.at(bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output_bits.empty()) {
|
||||||
|
aig_o++;
|
||||||
|
aig_outputs.push_back(0);
|
||||||
|
omode = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_aiger(std::ostream &f, bool ascii_mode)
|
void write_aiger(std::ostream &f, bool ascii_mode)
|
||||||
|
@ -796,6 +850,8 @@ struct XAigerWriter
|
||||||
f.write(buffer_str.data(), buffer_str.size());
|
f.write(buffer_str.data(), buffer_str.size());
|
||||||
|
|
||||||
if (holes_module) {
|
if (holes_module) {
|
||||||
|
log_push();
|
||||||
|
|
||||||
// NB: fixup_ports() will sort ports by name
|
// NB: fixup_ports() will sort ports by name
|
||||||
//holes_module->fixup_ports();
|
//holes_module->fixup_ports();
|
||||||
holes_module->check();
|
holes_module->check();
|
||||||
|
@ -832,6 +888,8 @@ struct XAigerWriter
|
||||||
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
||||||
f.write(buffer_str.data(), buffer_str.size());
|
f.write(buffer_str.data(), buffer_str.size());
|
||||||
holes_module->design->remove(holes_module);
|
holes_module->design->remove(holes_module);
|
||||||
|
|
||||||
|
log_pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,6 +973,8 @@ struct XAigerWriter
|
||||||
for (auto &it : output_lines)
|
for (auto &it : output_lines)
|
||||||
f << it.second;
|
f << it.second;
|
||||||
log_assert(output_lines.size() == output_bits.size());
|
log_assert(output_lines.size() == output_bits.size());
|
||||||
|
if (omode && output_bits.empty())
|
||||||
|
f << "output " << output_lines.size() << " 0 $__dummy__\n";
|
||||||
|
|
||||||
latch_lines.sort();
|
latch_lines.sort();
|
||||||
for (auto &it : latch_lines)
|
for (auto &it : latch_lines)
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// [[CITE]] Btor2 , BtorMC and Boolector 3.0
|
||||||
|
// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere
|
||||||
|
// Computer Aided Verification - 30th International Conference, CAV 2018
|
||||||
|
// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/
|
||||||
|
|
||||||
#include "kernel/rtlil.h"
|
#include "kernel/rtlil.h"
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
|
@ -875,9 +880,28 @@ struct BtorWorker
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (bit_cell.count(bit) == 0)
|
if (bit_cell.count(bit) == 0)
|
||||||
log_error("No driver for signal bit %s.\n", log_signal(bit));
|
{
|
||||||
export_cell(bit_cell.at(bit));
|
SigSpec s = bit;
|
||||||
log_assert(bit_nid.count(bit));
|
|
||||||
|
while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr &&
|
||||||
|
bit_cell.count(sig[i+GetSize(s)]) == 0)
|
||||||
|
s.append(sig[i+GetSize(s)]);
|
||||||
|
|
||||||
|
log_warning("No driver for signal %s.\n", log_signal(s));
|
||||||
|
|
||||||
|
int sid = get_bv_sid(GetSize(s));
|
||||||
|
int nid = next_nid++;
|
||||||
|
btorf("%d input %d %s\n", nid, sid);
|
||||||
|
nid_width[nid] = GetSize(s);
|
||||||
|
|
||||||
|
i += GetSize(s)-1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
export_cell(bit_cell.at(bit));
|
||||||
|
log_assert(bit_nid.count(bit));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -483,6 +483,7 @@ struct DumpPass : public Pass {
|
||||||
std::stringstream buf;
|
std::stringstream buf;
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
|
rewrite_filename(filename);
|
||||||
std::ofstream *ff = new std::ofstream;
|
std::ofstream *ff = new std::ofstream;
|
||||||
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
|
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
|
||||||
if (ff->fail()) {
|
if (ff->fail()) {
|
||||||
|
|
|
@ -126,6 +126,10 @@ struct JsonWriter
|
||||||
f << stringf("%s\n", first ? "" : ",");
|
f << stringf("%s\n", first ? "" : ",");
|
||||||
f << stringf(" %s: {\n", get_name(n).c_str());
|
f << stringf(" %s: {\n", get_name(n).c_str());
|
||||||
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
|
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
|
||||||
|
if (w->start_offset)
|
||||||
|
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
||||||
|
if (w->upto)
|
||||||
|
f << stringf(" \"upto\": 1,\n");
|
||||||
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
|
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
|
||||||
f << stringf(" }");
|
f << stringf(" }");
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -189,6 +193,10 @@ struct JsonWriter
|
||||||
f << stringf(" %s: {\n", get_name(w->name).c_str());
|
f << stringf(" %s: {\n", get_name(w->name).c_str());
|
||||||
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
|
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
|
||||||
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
|
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
|
||||||
|
if (w->start_offset)
|
||||||
|
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
||||||
|
if (w->upto)
|
||||||
|
f << stringf(" \"upto\": 1,\n");
|
||||||
f << stringf(" \"attributes\": {");
|
f << stringf(" \"attributes\": {");
|
||||||
write_parameters(w->attributes);
|
write_parameters(w->attributes);
|
||||||
f << stringf("\n }\n");
|
f << stringf("\n }\n");
|
||||||
|
@ -525,6 +533,7 @@ struct JsonPass : public Pass {
|
||||||
std::stringstream buf;
|
std::stringstream buf;
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
|
rewrite_filename(filename);
|
||||||
std::ofstream *ff = new std::ofstream;
|
std::ofstream *ff = new std::ofstream;
|
||||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||||
if (ff->fail()) {
|
if (ff->fail()) {
|
||||||
|
|
|
@ -336,6 +336,7 @@ struct ProtobufPass : public Pass {
|
||||||
std::stringstream buf;
|
std::stringstream buf;
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
|
rewrite_filename(filename);
|
||||||
std::ofstream *ff = new std::ofstream;
|
std::ofstream *ff = new std::ofstream;
|
||||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||||
if (ff->fail()) {
|
if (ff->fail()) {
|
||||||
|
|
|
@ -1023,6 +1023,8 @@ class MkVcd:
|
||||||
assert t >= self.t
|
assert t >= self.t
|
||||||
if t != self.t:
|
if t != self.t:
|
||||||
if self.t == -1:
|
if self.t == -1:
|
||||||
|
print("$version Generated by Yosys-SMTBMC $end", file=self.f)
|
||||||
|
print("$timescale 1ns $end", file=self.f)
|
||||||
print("$var integer 32 t smt_step $end", file=self.f)
|
print("$var integer 32 t smt_step $end", file=self.f)
|
||||||
print("$var event 1 ! smt_clock $end", file=self.f)
|
print("$var event 1 ! smt_clock $end", file=self.f)
|
||||||
|
|
||||||
|
@ -1041,7 +1043,10 @@ class MkVcd:
|
||||||
scope = scope[:-1]
|
scope = scope[:-1]
|
||||||
|
|
||||||
while uipath[:-1] != scope:
|
while uipath[:-1] != scope:
|
||||||
print("$scope module %s $end" % uipath[len(scope)], file=self.f)
|
scopename = uipath[len(scope)]
|
||||||
|
if scopename.startswith("$"):
|
||||||
|
scopename = "\\" + scopename
|
||||||
|
print("$scope module %s $end" % scopename, file=self.f)
|
||||||
scope.append(uipath[len(scope)])
|
scope.append(uipath[len(scope)])
|
||||||
|
|
||||||
if path in self.clocks and self.clocks[path][1] == "event":
|
if path in self.clocks and self.clocks[path][1] == "event":
|
||||||
|
|
|
@ -22,9 +22,6 @@
|
||||||
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
|
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
|
||||||
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
|
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <libgen.h>
|
|
||||||
#endif
|
|
||||||
// https://stackoverflow.com/a/46137633
|
// https://stackoverflow.com/a/46137633
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -52,6 +49,9 @@ inline int32_t from_big_endian(int32_t i32) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define log_debug2(...) ;
|
||||||
|
//#define log_debug2(...) log_debug(__VA_ARGS__)
|
||||||
|
|
||||||
struct ConstEvalAig
|
struct ConstEvalAig
|
||||||
{
|
{
|
||||||
RTLIL::Module *module;
|
RTLIL::Module *module;
|
||||||
|
@ -117,13 +117,20 @@ struct ConstEvalAig
|
||||||
|
|
||||||
RTLIL::Cell *cell = sig2driver.at(output);
|
RTLIL::Cell *cell = sig2driver.at(output);
|
||||||
RTLIL::SigBit sig_a = cell->getPort("\\A");
|
RTLIL::SigBit sig_a = cell->getPort("\\A");
|
||||||
|
sig2deps[sig_a].reserve(sig2deps[sig_a].size() + sig2deps[output].size()); // Reserve so that any invalidation
|
||||||
|
// that may occur does so here, and
|
||||||
|
// not mid insertion (below)
|
||||||
sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end());
|
sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end());
|
||||||
if (!inputs.count(sig_a))
|
if (!inputs.count(sig_a))
|
||||||
compute_deps(sig_a, inputs);
|
compute_deps(sig_a, inputs);
|
||||||
|
|
||||||
if (cell->type == "$_AND_") {
|
if (cell->type == "$_AND_") {
|
||||||
RTLIL::SigSpec sig_b = cell->getPort("\\B");
|
RTLIL::SigSpec sig_b = cell->getPort("\\B");
|
||||||
|
sig2deps[sig_b].reserve(sig2deps[sig_b].size() + sig2deps[output].size()); // Reserve so that any invalidation
|
||||||
|
// that may occur does so here, and
|
||||||
|
// not mid insertion (below)
|
||||||
sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end());
|
sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end());
|
||||||
|
|
||||||
if (!inputs.count(sig_b))
|
if (!inputs.count(sig_b))
|
||||||
compute_deps(sig_b, inputs);
|
compute_deps(sig_b, inputs);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +312,7 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
|
||||||
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : ""));
|
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : ""));
|
||||||
RTLIL::Wire *wire = module->wire(wire_name);
|
RTLIL::Wire *wire = module->wire(wire_name);
|
||||||
if (wire) return wire;
|
if (wire) return wire;
|
||||||
log_debug("Creating %s\n", wire_name.c_str());
|
log_debug2("Creating %s\n", wire_name.c_str());
|
||||||
wire = module->addWire(wire_name);
|
wire = module->addWire(wire_name);
|
||||||
wire->port_input = wire->port_output = false;
|
wire->port_input = wire->port_output = false;
|
||||||
if (!invert) return wire;
|
if (!invert) return wire;
|
||||||
|
@ -315,12 +322,12 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
|
||||||
if (module->cell(wire_inv_name)) return wire;
|
if (module->cell(wire_inv_name)) return wire;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log_debug("Creating %s\n", wire_inv_name.c_str());
|
log_debug2("Creating %s\n", wire_inv_name.c_str());
|
||||||
wire_inv = module->addWire(wire_inv_name);
|
wire_inv = module->addWire(wire_inv_name);
|
||||||
wire_inv->port_input = wire_inv->port_output = false;
|
wire_inv->port_input = wire_inv->port_output = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||||
module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire);
|
module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire);
|
||||||
|
|
||||||
return wire;
|
return wire;
|
||||||
|
@ -369,7 +376,11 @@ void AigerReader::parse_xaiger()
|
||||||
continue;
|
continue;
|
||||||
if (m->name.begins_with("$paramod"))
|
if (m->name.begins_with("$paramod"))
|
||||||
continue;
|
continue;
|
||||||
auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name));
|
auto id = it->second.as_int();
|
||||||
|
auto r = box_lookup.insert(std::make_pair(id, m->name));
|
||||||
|
if (!r.second)
|
||||||
|
log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n",
|
||||||
|
log_id(m), id, log_id(r.first->second));
|
||||||
log_assert(r.second);
|
log_assert(r.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,13 +407,13 @@ void AigerReader::parse_xaiger()
|
||||||
for (unsigned i = 0; i < lutNum; ++i) {
|
for (unsigned i = 0; i < lutNum; ++i) {
|
||||||
uint32_t rootNodeID = parse_xaiger_literal(f);
|
uint32_t rootNodeID = parse_xaiger_literal(f);
|
||||||
uint32_t cutLeavesM = parse_xaiger_literal(f);
|
uint32_t cutLeavesM = parse_xaiger_literal(f);
|
||||||
log_debug("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
|
log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
|
||||||
RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID));
|
RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID));
|
||||||
uint32_t nodeID;
|
uint32_t nodeID;
|
||||||
RTLIL::SigSpec input_sig;
|
RTLIL::SigSpec input_sig;
|
||||||
for (unsigned j = 0; j < cutLeavesM; ++j) {
|
for (unsigned j = 0; j < cutLeavesM; ++j) {
|
||||||
nodeID = parse_xaiger_literal(f);
|
nodeID = parse_xaiger_literal(f);
|
||||||
log_debug("\t%u\n", nodeID);
|
log_debug2("\t%u\n", nodeID);
|
||||||
RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID));
|
RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID));
|
||||||
log_assert(wire);
|
log_assert(wire);
|
||||||
input_sig.append(wire);
|
input_sig.append(wire);
|
||||||
|
@ -487,7 +498,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
for (unsigned i = 1; i <= I; ++i, ++line_count) {
|
for (unsigned i = 1; i <= I; ++i, ++line_count) {
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
||||||
log_debug("%d is an input\n", l1);
|
log_debug2("%d is an input\n", l1);
|
||||||
log_assert(!(l1 & 1)); // Inputs can't be inverted
|
log_assert(!(l1 & 1)); // Inputs can't be inverted
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
wire->port_input = true;
|
wire->port_input = true;
|
||||||
|
@ -499,7 +510,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
if (L > 0 && !clk_name.empty()) {
|
if (L > 0 && !clk_name.empty()) {
|
||||||
clk_wire = module->wire(clk_name);
|
clk_wire = module->wire(clk_name);
|
||||||
log_assert(!clk_wire);
|
log_assert(!clk_wire);
|
||||||
log_debug("Creating %s\n", clk_name.c_str());
|
log_debug2("Creating %s\n", clk_name.c_str());
|
||||||
clk_wire = module->addWire(clk_name);
|
clk_wire = module->addWire(clk_name);
|
||||||
clk_wire->port_input = true;
|
clk_wire->port_input = true;
|
||||||
clk_wire->port_output = false;
|
clk_wire->port_output = false;
|
||||||
|
@ -507,7 +518,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||||
if (!(f >> l1 >> l2))
|
if (!(f >> l1 >> l2))
|
||||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||||
log_debug("%d %d is a latch\n", l1, l2);
|
log_debug2("%d %d is a latch\n", l1, l2);
|
||||||
log_assert(!(l1 & 1));
|
log_assert(!(l1 & 1));
|
||||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||||
|
@ -544,7 +555,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||||
|
|
||||||
log_debug("%d is an output\n", l1);
|
log_debug2("%d is an output\n", l1);
|
||||||
const unsigned variable = l1 >> 1;
|
const unsigned variable = l1 >> 1;
|
||||||
const bool invert = l1 & 1;
|
const bool invert = l1 & 1;
|
||||||
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
|
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
|
||||||
|
@ -565,7 +576,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
||||||
|
|
||||||
log_debug("%d is a bad state property\n", l1);
|
log_debug2("%d is a bad state property\n", l1);
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
bad_properties.push_back(wire);
|
bad_properties.push_back(wire);
|
||||||
|
@ -588,7 +599,7 @@ void AigerReader::parse_aiger_ascii()
|
||||||
if (!(f >> l1 >> l2 >> l3))
|
if (!(f >> l1 >> l2 >> l3))
|
||||||
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
||||||
|
|
||||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
log_debug2("%d %d %d is an AND\n", l1, l2, l3);
|
||||||
log_assert(!(l1 & 1));
|
log_assert(!(l1 & 1));
|
||||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||||
|
@ -614,7 +625,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
|
|
||||||
// Parse inputs
|
// Parse inputs
|
||||||
for (unsigned i = 1; i <= I; ++i) {
|
for (unsigned i = 1; i <= I; ++i) {
|
||||||
log_debug("%d is an input\n", i);
|
log_debug2("%d is an input\n", i);
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
||||||
wire->port_input = true;
|
wire->port_input = true;
|
||||||
log_assert(!wire->port_output);
|
log_assert(!wire->port_output);
|
||||||
|
@ -626,7 +637,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
if (L > 0 && !clk_name.empty()) {
|
if (L > 0 && !clk_name.empty()) {
|
||||||
clk_wire = module->wire(clk_name);
|
clk_wire = module->wire(clk_name);
|
||||||
log_assert(!clk_wire);
|
log_assert(!clk_wire);
|
||||||
log_debug("Creating %s\n", clk_name.c_str());
|
log_debug2("Creating %s\n", clk_name.c_str());
|
||||||
clk_wire = module->addWire(clk_name);
|
clk_wire = module->addWire(clk_name);
|
||||||
clk_wire->port_input = true;
|
clk_wire->port_input = true;
|
||||||
clk_wire->port_output = false;
|
clk_wire->port_output = false;
|
||||||
|
@ -671,7 +682,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||||
|
|
||||||
log_debug("%d is an output\n", l1);
|
log_debug2("%d is an output\n", l1);
|
||||||
const unsigned variable = l1 >> 1;
|
const unsigned variable = l1 >> 1;
|
||||||
const bool invert = l1 & 1;
|
const bool invert = l1 & 1;
|
||||||
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
|
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
|
||||||
|
@ -693,7 +704,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
||||||
|
|
||||||
log_debug("%d is a bad state property\n", l1);
|
log_debug2("%d is a bad state property\n", l1);
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
bad_properties.push_back(wire);
|
bad_properties.push_back(wire);
|
||||||
|
@ -719,7 +730,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
l2 = parse_next_delta_literal(f, l1);
|
l2 = parse_next_delta_literal(f, l1);
|
||||||
l3 = parse_next_delta_literal(f, l2);
|
l3 = parse_next_delta_literal(f, l2);
|
||||||
|
|
||||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
log_debug2("%d %d %d is an AND\n", l1, l2, l3);
|
||||||
log_assert(!(l1 & 1));
|
log_assert(!(l1 & 1));
|
||||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||||
|
@ -730,7 +741,7 @@ void AigerReader::parse_aiger_binary()
|
||||||
|
|
||||||
void AigerReader::post_process()
|
void AigerReader::post_process()
|
||||||
{
|
{
|
||||||
pool<RTLIL::Module*> abc_carry_modules;
|
pool<IdString> seen_boxes;
|
||||||
unsigned ci_count = 0, co_count = 0, flop_count = 0;
|
unsigned ci_count = 0, co_count = 0, flop_count = 0;
|
||||||
for (auto cell : boxes) {
|
for (auto cell : boxes) {
|
||||||
RTLIL::Module* box_module = design->module(cell->type);
|
RTLIL::Module* box_module = design->module(cell->type);
|
||||||
|
@ -745,38 +756,44 @@ void AigerReader::post_process()
|
||||||
log_assert(flop_module);
|
log_assert(flop_module);
|
||||||
flop_past_q = box_module->attributes.at("\\abc_flop_past_q").decode_string();
|
flop_past_q = box_module->attributes.at("\\abc_flop_past_q").decode_string();
|
||||||
}
|
}
|
||||||
else if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
|
else if (seen_boxes.insert(cell->type).second) {
|
||||||
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
|
auto it = box_module->attributes.find("\\abc_carry");
|
||||||
RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
|
if (it != box_module->attributes.end()) {
|
||||||
for (const auto &port_name : box_module->ports) {
|
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
|
||||||
RTLIL::Wire* w = box_module->wire(port_name);
|
auto carry_in_out = it->second.decode_string();
|
||||||
log_assert(w);
|
auto pos = carry_in_out.find(',');
|
||||||
if (w->port_input) {
|
if (pos == std::string::npos)
|
||||||
if (w->attributes.count("\\abc_carry_in")) {
|
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
|
||||||
log_assert(!carry_in);
|
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
|
||||||
carry_in = w;
|
carry_in = box_module->wire(carry_in_name);
|
||||||
}
|
if (!carry_in || !carry_in->port_input)
|
||||||
log_assert(!last_in || last_in->port_id < w->port_id);
|
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
|
||||||
last_in = w;
|
|
||||||
}
|
|
||||||
if (w->port_output) {
|
|
||||||
if (w->attributes.count("\\abc_carry_out")) {
|
|
||||||
log_assert(!carry_out);
|
|
||||||
carry_out = w;
|
|
||||||
}
|
|
||||||
log_assert(!last_out || last_out->port_id < w->port_id);
|
|
||||||
last_out = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carry_in != last_in) {
|
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
|
||||||
std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]);
|
carry_out = box_module->wire(carry_out_name);
|
||||||
std::swap(carry_in->port_id, last_in->port_id);
|
if (!carry_out || !carry_out->port_output)
|
||||||
}
|
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
|
||||||
if (carry_out != last_out) {
|
|
||||||
log_assert(last_out);
|
auto &ports = box_module->ports;
|
||||||
std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]);
|
for (auto jt = ports.begin(); jt != ports.end(); ) {
|
||||||
std::swap(carry_out->port_id, last_out->port_id);
|
RTLIL::Wire* w = box_module->wire(*jt);
|
||||||
|
log_assert(w);
|
||||||
|
if (w == carry_in || w == carry_out) {
|
||||||
|
jt = ports.erase(jt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (w->port_id > carry_in->port_id)
|
||||||
|
--w->port_id;
|
||||||
|
if (w->port_id > carry_out->port_id)
|
||||||
|
--w->port_id;
|
||||||
|
log_assert(w->port_input || w->port_output);
|
||||||
|
log_assert(ports[w->port_id-1] == w->name);
|
||||||
|
++jt;
|
||||||
|
}
|
||||||
|
ports.push_back(carry_in->name);
|
||||||
|
carry_in->port_id = ports.size();
|
||||||
|
ports.push_back(carry_out->name);
|
||||||
|
carry_out->port_id = ports.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,7 +890,10 @@ void AigerReader::post_process()
|
||||||
RTLIL::Wire* wire = outputs[variable + co_count];
|
RTLIL::Wire* wire = outputs[variable + co_count];
|
||||||
log_assert(wire);
|
log_assert(wire);
|
||||||
log_assert(wire->port_output);
|
log_assert(wire->port_output);
|
||||||
log_debug("Renaming output %s", log_id(wire));
|
if (escaped_s == "$__dummy__") {
|
||||||
|
wire->port_output = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// Cope with the fact that a CO might be identical
|
// Cope with the fact that a CO might be identical
|
||||||
|
@ -988,10 +1008,15 @@ void AigerReader::post_process()
|
||||||
if (other_wire) {
|
if (other_wire) {
|
||||||
other_wire->port_input = false;
|
other_wire->port_input = false;
|
||||||
other_wire->port_output = false;
|
other_wire->port_output = false;
|
||||||
if (wire->port_input)
|
}
|
||||||
|
if (wire->port_input) {
|
||||||
|
if (other_wire)
|
||||||
module->connect(other_wire, SigSpec(wire, i));
|
module->connect(other_wire, SigSpec(wire, i));
|
||||||
else
|
}
|
||||||
module->connect(SigSpec(wire, i), other_wire);
|
else {
|
||||||
|
// Since we skip POs that are connected to Sx,
|
||||||
|
// re-connect them here
|
||||||
|
module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace AST {
|
||||||
// instantiate global variables (private API)
|
// instantiate global variables (private API)
|
||||||
namespace AST_INTERNAL {
|
namespace AST_INTERNAL {
|
||||||
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||||
bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire;
|
bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_autowire;
|
||||||
AstNode *current_ast, *current_ast_mod;
|
AstNode *current_ast, *current_ast_mod;
|
||||||
std::map<std::string, AstNode*> current_scope;
|
std::map<std::string, AstNode*> current_scope;
|
||||||
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
|
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
|
||||||
|
@ -1112,6 +1112,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
||||||
current_module->nowb = flag_nowb;
|
current_module->nowb = flag_nowb;
|
||||||
current_module->noopt = flag_noopt;
|
current_module->noopt = flag_noopt;
|
||||||
current_module->icells = flag_icells;
|
current_module->icells = flag_icells;
|
||||||
|
current_module->pwires = flag_pwires;
|
||||||
current_module->autowire = flag_autowire;
|
current_module->autowire = flag_autowire;
|
||||||
current_module->fixup_ports();
|
current_module->fixup_ports();
|
||||||
|
|
||||||
|
@ -1126,7 +1127,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
||||||
|
|
||||||
// create AstModule instances for all modules in the AST tree and add them to 'design'
|
// create AstModule instances for all modules in the AST tree and add them to 'design'
|
||||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
|
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
|
||||||
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
|
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire)
|
||||||
{
|
{
|
||||||
current_ast = ast;
|
current_ast = ast;
|
||||||
flag_dump_ast1 = dump_ast1;
|
flag_dump_ast1 = dump_ast1;
|
||||||
|
@ -1144,6 +1145,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
||||||
flag_nowb = nowb;
|
flag_nowb = nowb;
|
||||||
flag_noopt = noopt;
|
flag_noopt = noopt;
|
||||||
flag_icells = icells;
|
flag_icells = icells;
|
||||||
|
flag_pwires = pwires;
|
||||||
flag_autowire = autowire;
|
flag_autowire = autowire;
|
||||||
|
|
||||||
log_assert(current_ast->type == AST_DESIGN);
|
log_assert(current_ast->type == AST_DESIGN);
|
||||||
|
@ -1480,6 +1482,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
|
||||||
flag_nowb = nowb;
|
flag_nowb = nowb;
|
||||||
flag_noopt = noopt;
|
flag_noopt = noopt;
|
||||||
flag_icells = icells;
|
flag_icells = icells;
|
||||||
|
flag_pwires = pwires;
|
||||||
flag_autowire = autowire;
|
flag_autowire = autowire;
|
||||||
use_internal_line_num();
|
use_internal_line_num();
|
||||||
|
|
||||||
|
@ -1551,6 +1554,7 @@ RTLIL::Module *AstModule::clone() const
|
||||||
new_mod->lib = lib;
|
new_mod->lib = lib;
|
||||||
new_mod->noopt = noopt;
|
new_mod->noopt = noopt;
|
||||||
new_mod->icells = icells;
|
new_mod->icells = icells;
|
||||||
|
new_mod->pwires = pwires;
|
||||||
new_mod->autowire = autowire;
|
new_mod->autowire = autowire;
|
||||||
|
|
||||||
return new_mod;
|
return new_mod;
|
||||||
|
|
|
@ -286,13 +286,13 @@ namespace AST
|
||||||
|
|
||||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
||||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
|
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
|
||||||
bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
|
bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire);
|
||||||
|
|
||||||
// parametric modules are supported directly by the AST library
|
// parametric modules are supported directly by the AST library
|
||||||
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||||
struct AstModule : RTLIL::Module {
|
struct AstModule : RTLIL::Module {
|
||||||
AstNode *ast;
|
AstNode *ast;
|
||||||
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire;
|
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
|
||||||
~AstModule() YS_OVERRIDE;
|
~AstModule() YS_OVERRIDE;
|
||||||
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
|
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
|
||||||
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
|
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
|
||||||
|
@ -325,7 +325,7 @@ namespace AST_INTERNAL
|
||||||
{
|
{
|
||||||
// internal state variables
|
// internal state variables
|
||||||
extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||||
extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire;
|
||||||
extern AST::AstNode *current_ast, *current_ast_mod;
|
extern AST::AstNode *current_ast, *current_ast_mod;
|
||||||
extern std::map<std::string, AST::AstNode*> current_scope;
|
extern std::map<std::string, AST::AstNode*> current_scope;
|
||||||
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
|
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
|
||||||
|
|
|
@ -853,7 +853,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
case AST_FUNCTION:
|
case AST_FUNCTION:
|
||||||
case AST_DPI_FUNCTION:
|
case AST_DPI_FUNCTION:
|
||||||
case AST_AUTOWIRE:
|
case AST_AUTOWIRE:
|
||||||
case AST_LOCALPARAM:
|
|
||||||
case AST_DEFPARAM:
|
case AST_DEFPARAM:
|
||||||
case AST_GENVAR:
|
case AST_GENVAR:
|
||||||
case AST_GENFOR:
|
case AST_GENFOR:
|
||||||
|
@ -895,6 +894,26 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
// remember the parameter, needed for example in techmap
|
// remember the parameter, needed for example in techmap
|
||||||
case AST_PARAMETER:
|
case AST_PARAMETER:
|
||||||
current_module->avail_parameters.insert(str);
|
current_module->avail_parameters.insert(str);
|
||||||
|
/* fall through */
|
||||||
|
case AST_LOCALPARAM:
|
||||||
|
if (flag_pwires)
|
||||||
|
{
|
||||||
|
if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT)
|
||||||
|
log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str());
|
||||||
|
|
||||||
|
RTLIL::Const val = children[0]->bitsAsConst();
|
||||||
|
RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));
|
||||||
|
current_module->connect(wire, val);
|
||||||
|
|
||||||
|
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||||
|
wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1;
|
||||||
|
|
||||||
|
for (auto &attr : attributes) {
|
||||||
|
if (attr.second->type != AST_CONSTANT)
|
||||||
|
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||||
|
wire->attributes[attr.first] = attr.second->asAttrConst();
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// create an RTLIL::Wire for an AST_WIRE node
|
// create an RTLIL::Wire for an AST_WIRE node
|
||||||
|
|
|
@ -292,6 +292,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
||||||
if (port_wire == nullptr)
|
if (port_wire == nullptr)
|
||||||
port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
|
port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
|
||||||
|
|
||||||
|
if (port_node->data_dict.count("upto") != 0) {
|
||||||
|
JsonNode *val = port_node->data_dict.at("upto");
|
||||||
|
if (val->type == 'N')
|
||||||
|
port_wire->upto = val->data_number != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port_node->data_dict.count("offset") != 0) {
|
||||||
|
JsonNode *val = port_node->data_dict.at("offset");
|
||||||
|
if (val->type == 'N')
|
||||||
|
port_wire->start_offset = val->data_number;
|
||||||
|
}
|
||||||
|
|
||||||
if (port_direction_node->data_string == "input") {
|
if (port_direction_node->data_string == "input") {
|
||||||
port_wire->port_input = true;
|
port_wire->port_input = true;
|
||||||
} else
|
} else
|
||||||
|
@ -372,6 +384,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
||||||
if (wire == nullptr)
|
if (wire == nullptr)
|
||||||
wire = module->addWire(net_name, GetSize(bits_node->data_array));
|
wire = module->addWire(net_name, GetSize(bits_node->data_array));
|
||||||
|
|
||||||
|
if (net_node->data_dict.count("upto") != 0) {
|
||||||
|
JsonNode *val = net_node->data_dict.at("upto");
|
||||||
|
if (val->type == 'N')
|
||||||
|
wire->upto = val->data_number != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_node->data_dict.count("offset") != 0) {
|
||||||
|
JsonNode *val = net_node->data_dict.at("offset");
|
||||||
|
if (val->type == 'N')
|
||||||
|
wire->start_offset = val->data_number;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < GetSize(bits_node->data_array); i++)
|
for (int i = 0; i < GetSize(bits_node->data_array); i++)
|
||||||
{
|
{
|
||||||
JsonNode *bitval_node = bits_node->data_array.at(i);
|
JsonNode *bitval_node = bits_node->data_array.at(i);
|
||||||
|
|
|
@ -153,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
||||||
{
|
{
|
||||||
if (warn_z) {
|
if (warn_z) {
|
||||||
AstNode *ret = const2ast(code, case_type);
|
AstNode *ret = const2ast(code, case_type);
|
||||||
if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
|
if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
|
||||||
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
|
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
|
||||||
current_filename.c_str(), get_line_num());
|
current_filename.c_str(), get_line_num());
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -204,7 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
||||||
{
|
{
|
||||||
std::vector<RTLIL::State> data;
|
std::vector<RTLIL::State> data;
|
||||||
bool is_signed = false;
|
bool is_signed = false;
|
||||||
bool is_unsized = false;
|
bool is_unsized = len_in_bits < 0;
|
||||||
if (*(endptr+1) == 's') {
|
if (*(endptr+1) == 's') {
|
||||||
is_signed = true;
|
is_signed = true;
|
||||||
endptr++;
|
endptr++;
|
||||||
|
@ -213,25 +213,25 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
||||||
{
|
{
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'B':
|
case 'B':
|
||||||
my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false);
|
my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'O':
|
case 'O':
|
||||||
my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false);
|
my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false);
|
my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'H':
|
case 'H':
|
||||||
my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false);
|
my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
char next_char = char(tolower(*(endptr+1)));
|
char next_char = char(tolower(*(endptr+1)));
|
||||||
if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
|
if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
|
||||||
my_strtobin(data, endptr+1, 1, 2, case_type, true);
|
|
||||||
is_unsized = true;
|
is_unsized = true;
|
||||||
|
my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,9 @@ struct VerilogFrontend : public Frontend {
|
||||||
log(" -icells\n");
|
log(" -icells\n");
|
||||||
log(" interpret cell types starting with '$' as internal cell types\n");
|
log(" interpret cell types starting with '$' as internal cell types\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -pwires\n");
|
||||||
|
log(" add a wire for each module parameter\n");
|
||||||
|
log("\n");
|
||||||
log(" -nooverwrite\n");
|
log(" -nooverwrite\n");
|
||||||
log(" ignore re-definitions of modules. (the default behavior is to\n");
|
log(" ignore re-definitions of modules. (the default behavior is to\n");
|
||||||
log(" create an error message if the existing module is not a black box\n");
|
log(" create an error message if the existing module is not a black box\n");
|
||||||
|
@ -228,6 +231,7 @@ struct VerilogFrontend : public Frontend {
|
||||||
bool flag_nodpi = false;
|
bool flag_nodpi = false;
|
||||||
bool flag_noopt = false;
|
bool flag_noopt = false;
|
||||||
bool flag_icells = false;
|
bool flag_icells = false;
|
||||||
|
bool flag_pwires = false;
|
||||||
bool flag_nooverwrite = false;
|
bool flag_nooverwrite = false;
|
||||||
bool flag_overwrite = false;
|
bool flag_overwrite = false;
|
||||||
bool flag_defer = false;
|
bool flag_defer = false;
|
||||||
|
@ -368,6 +372,10 @@ struct VerilogFrontend : public Frontend {
|
||||||
flag_icells = true;
|
flag_icells = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-pwires") {
|
||||||
|
flag_pwires = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
|
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
|
||||||
flag_nooverwrite = true;
|
flag_nooverwrite = true;
|
||||||
flag_overwrite = false;
|
flag_overwrite = false;
|
||||||
|
@ -458,7 +466,7 @@ struct VerilogFrontend : public Frontend {
|
||||||
error_on_dpi_function(current_ast);
|
error_on_dpi_function(current_ast);
|
||||||
|
|
||||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
|
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
|
||||||
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
||||||
|
|
||||||
if (!flag_nopp)
|
if (!flag_nopp)
|
||||||
delete lexin;
|
delete lexin;
|
||||||
|
|
|
@ -313,7 +313,7 @@ supply1 { return TOK_SUPPLY1; }
|
||||||
|
|
||||||
"$"(info|warning|error|fatal) {
|
"$"(info|warning|error|fatal) {
|
||||||
frontend_verilog_yylval.string = new std::string(yytext);
|
frontend_verilog_yylval.string = new std::string(yytext);
|
||||||
return TOK_ELAB_TASK;
|
return TOK_MSG_TASKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
"$signed" { return TOK_TO_SIGNED; }
|
"$signed" { return TOK_TO_SIGNED; }
|
||||||
|
|
|
@ -133,7 +133,7 @@ struct specify_rise_fall {
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||||
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_ELAB_TASK
|
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
|
||||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
|
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
|
||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
|
@ -319,15 +319,17 @@ module_para_list:
|
||||||
|
|
||||||
single_module_para:
|
single_module_para:
|
||||||
/* empty */ |
|
/* empty */ |
|
||||||
TOK_PARAMETER {
|
attr TOK_PARAMETER {
|
||||||
if (astbuf1) delete astbuf1;
|
if (astbuf1) delete astbuf1;
|
||||||
astbuf1 = new AstNode(AST_PARAMETER);
|
astbuf1 = new AstNode(AST_PARAMETER);
|
||||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||||
|
append_attr(astbuf1, $1);
|
||||||
} param_signed param_integer param_range single_param_decl |
|
} param_signed param_integer param_range single_param_decl |
|
||||||
TOK_LOCALPARAM {
|
attr TOK_LOCALPARAM {
|
||||||
if (astbuf1) delete astbuf1;
|
if (astbuf1) delete astbuf1;
|
||||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||||
|
append_attr(astbuf1, $1);
|
||||||
} param_signed param_integer param_range single_param_decl |
|
} param_signed param_integer param_range single_param_decl |
|
||||||
single_param_decl;
|
single_param_decl;
|
||||||
|
|
||||||
|
@ -345,7 +347,13 @@ module_arg_opt_assignment:
|
||||||
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
|
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
|
||||||
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||||
wire->str = ast_stack.back()->children.back()->str;
|
wire->str = ast_stack.back()->children.back()->str;
|
||||||
if (ast_stack.back()->children.back()->is_reg)
|
if (ast_stack.back()->children.back()->is_input) {
|
||||||
|
AstNode *n = ast_stack.back()->children.back();
|
||||||
|
if (n->attributes.count("\\defaultvalue"))
|
||||||
|
delete n->attributes.at("\\defaultvalue");
|
||||||
|
n->attributes["\\defaultvalue"] = $2;
|
||||||
|
} else
|
||||||
|
if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
|
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
|
||||||
else
|
else
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
|
||||||
|
@ -509,6 +517,7 @@ wire_type_token:
|
||||||
TOK_GENVAR {
|
TOK_GENVAR {
|
||||||
astbuf3->type = AST_GENVAR;
|
astbuf3->type = AST_GENVAR;
|
||||||
astbuf3->is_reg = true;
|
astbuf3->is_reg = true;
|
||||||
|
astbuf3->is_signed = true;
|
||||||
astbuf3->range_left = 31;
|
astbuf3->range_left = 31;
|
||||||
astbuf3->range_right = 0;
|
astbuf3->range_right = 0;
|
||||||
} |
|
} |
|
||||||
|
@ -1211,6 +1220,7 @@ param_decl:
|
||||||
attr TOK_PARAMETER {
|
attr TOK_PARAMETER {
|
||||||
astbuf1 = new AstNode(AST_PARAMETER);
|
astbuf1 = new AstNode(AST_PARAMETER);
|
||||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||||
|
append_attr(astbuf1, $1);
|
||||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||||
delete astbuf1;
|
delete astbuf1;
|
||||||
};
|
};
|
||||||
|
@ -1219,6 +1229,7 @@ localparam_decl:
|
||||||
attr TOK_LOCALPARAM {
|
attr TOK_LOCALPARAM {
|
||||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||||
|
append_attr(astbuf1, $1);
|
||||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||||
delete astbuf1;
|
delete astbuf1;
|
||||||
};
|
};
|
||||||
|
@ -1360,7 +1371,12 @@ wire_name_and_opt_assign:
|
||||||
wire_name '=' expr {
|
wire_name '=' expr {
|
||||||
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||||
wire->str = ast_stack.back()->children.back()->str;
|
wire->str = ast_stack.back()->children.back()->str;
|
||||||
if (astbuf1->is_reg)
|
if (astbuf1->is_input) {
|
||||||
|
if (astbuf1->attributes.count("\\defaultvalue"))
|
||||||
|
delete astbuf1->attributes.at("\\defaultvalue");
|
||||||
|
astbuf1->attributes["\\defaultvalue"] = $3;
|
||||||
|
} else
|
||||||
|
if (astbuf1->is_reg || astbuf1->is_logic)
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
|
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3))));
|
||||||
else
|
else
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
|
||||||
|
@ -1385,7 +1401,13 @@ wire_name:
|
||||||
node->children.push_back(rng);
|
node->children.push_back(rng);
|
||||||
}
|
}
|
||||||
node->type = AST_MEMORY;
|
node->type = AST_MEMORY;
|
||||||
node->children.push_back($2);
|
auto *rangeNode = $2;
|
||||||
|
if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
|
||||||
|
// SV array size [n], rewrite as [n-1:0]
|
||||||
|
rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
|
||||||
|
rangeNode->children.push_back(AstNode::mkconst_int(0, false));
|
||||||
|
}
|
||||||
|
node->children.push_back(rangeNode);
|
||||||
}
|
}
|
||||||
if (current_function_or_task == NULL) {
|
if (current_function_or_task == NULL) {
|
||||||
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
|
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
|
||||||
|
@ -1881,6 +1903,16 @@ behavioral_stmt:
|
||||||
} opt_arg_list ';'{
|
} opt_arg_list ';'{
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
|
TOK_MSG_TASKS attr {
|
||||||
|
AstNode *node = new AstNode(AST_TCALL);
|
||||||
|
node->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
ast_stack.push_back(node);
|
||||||
|
append_attr(node, $2);
|
||||||
|
} opt_arg_list ';'{
|
||||||
|
ast_stack.pop_back();
|
||||||
|
} |
|
||||||
attr TOK_BEGIN opt_label {
|
attr TOK_BEGIN opt_label {
|
||||||
AstNode *node = new AstNode(AST_BLOCK);
|
AstNode *node = new AstNode(AST_BLOCK);
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
|
@ -2177,7 +2209,7 @@ gen_stmt:
|
||||||
delete $6;
|
delete $6;
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
TOK_ELAB_TASK {
|
TOK_MSG_TASKS {
|
||||||
AstNode *node = new AstNode(AST_TECALL);
|
AstNode *node = new AstNode(AST_TECALL);
|
||||||
node->str = *$1;
|
node->str = *$1;
|
||||||
delete $1;
|
delete $1;
|
||||||
|
|
|
@ -246,24 +246,24 @@ struct CellTypes
|
||||||
cell_types.clear();
|
cell_types.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_known(RTLIL::IdString type)
|
bool cell_known(RTLIL::IdString type) const
|
||||||
{
|
{
|
||||||
return cell_types.count(type) != 0;
|
return cell_types.count(type) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
|
bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const
|
||||||
{
|
{
|
||||||
auto it = cell_types.find(type);
|
auto it = cell_types.find(type);
|
||||||
return it != cell_types.end() && it->second.outputs.count(port) != 0;
|
return it != cell_types.end() && it->second.outputs.count(port) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
|
bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const
|
||||||
{
|
{
|
||||||
auto it = cell_types.find(type);
|
auto it = cell_types.find(type);
|
||||||
return it != cell_types.end() && it->second.inputs.count(port) != 0;
|
return it != cell_types.end() && it->second.inputs.count(port) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_evaluable(RTLIL::IdString type)
|
bool cell_evaluable(RTLIL::IdString type) const
|
||||||
{
|
{
|
||||||
auto it = cell_types.find(type);
|
auto it = cell_types.find(type);
|
||||||
return it != cell_types.end() && it->second.is_evaluable;
|
return it != cell_types.end() && it->second.is_evaluable;
|
||||||
|
@ -482,4 +482,3 @@ extern CellTypes yosys_celltypes;
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -545,6 +545,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = arg;
|
filename = arg;
|
||||||
|
rewrite_filename(filename);
|
||||||
std::ofstream *ff = new std::ofstream;
|
std::ofstream *ff = new std::ofstream;
|
||||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||||
yosys_output_files.insert(filename);
|
yosys_output_files.insert(filename);
|
||||||
|
|
|
@ -1381,7 +1381,34 @@ void RTLIL::Module::check()
|
||||||
for (auto &it : processes) {
|
for (auto &it : processes) {
|
||||||
log_assert(it.first == it.second->name);
|
log_assert(it.first == it.second->name);
|
||||||
log_assert(!it.first.empty());
|
log_assert(!it.first.empty());
|
||||||
// FIXME: More checks here..
|
log_assert(it.second->root_case.compare.empty());
|
||||||
|
std::vector<CaseRule*> all_cases = {&it.second->root_case};
|
||||||
|
for (size_t i = 0; i < all_cases.size(); i++) {
|
||||||
|
for (auto &switch_it : all_cases[i]->switches) {
|
||||||
|
for (auto &case_it : switch_it->cases) {
|
||||||
|
for (auto &compare_it : case_it->compare) {
|
||||||
|
log_assert(switch_it->signal.size() == compare_it.size());
|
||||||
|
}
|
||||||
|
all_cases.push_back(case_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &sync_it : it.second->syncs) {
|
||||||
|
switch (sync_it->type) {
|
||||||
|
case SyncType::ST0:
|
||||||
|
case SyncType::ST1:
|
||||||
|
case SyncType::STp:
|
||||||
|
case SyncType::STn:
|
||||||
|
case SyncType::STe:
|
||||||
|
log_assert(!sync_it->signal.empty());
|
||||||
|
break;
|
||||||
|
case SyncType::STa:
|
||||||
|
case SyncType::STg:
|
||||||
|
case SyncType::STi:
|
||||||
|
log_assert(sync_it->signal.empty());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &it : connections_) {
|
for (auto &it : connections_) {
|
||||||
|
@ -1565,21 +1592,13 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||||
|
|
||||||
void RTLIL::Module::remove(RTLIL::Cell *cell)
|
void RTLIL::Module::remove(RTLIL::Cell *cell)
|
||||||
{
|
{
|
||||||
auto it = cells_.find(cell->name);
|
|
||||||
log_assert(it != cells_.end());
|
|
||||||
remove(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
dict<RTLIL::IdString, RTLIL::Cell*>::iterator RTLIL::Module::remove(dict<RTLIL::IdString, RTLIL::Cell*>::iterator it)
|
|
||||||
{
|
|
||||||
RTLIL::Cell *cell = it->second;
|
|
||||||
while (!cell->connections_.empty())
|
while (!cell->connections_.empty())
|
||||||
cell->unsetPort(cell->connections_.begin()->first);
|
cell->unsetPort(cell->connections_.begin()->first);
|
||||||
|
|
||||||
|
log_assert(cells_.count(cell->name) != 0);
|
||||||
log_assert(refcount_cells_ == 0);
|
log_assert(refcount_cells_ == 0);
|
||||||
it = cells_.erase(it);
|
cells_.erase(cell->name);
|
||||||
delete cell;
|
delete cell;
|
||||||
return it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
|
void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
|
||||||
|
|
|
@ -1040,7 +1040,6 @@ public:
|
||||||
// Removing wires is expensive. If you have to remove wires, remove them all at once.
|
// Removing wires is expensive. If you have to remove wires, remove them all at once.
|
||||||
void remove(const pool<RTLIL::Wire*> &wires);
|
void remove(const pool<RTLIL::Wire*> &wires);
|
||||||
void remove(RTLIL::Cell *cell);
|
void remove(RTLIL::Cell *cell);
|
||||||
dict<RTLIL::IdString, RTLIL::Cell*>::iterator remove(dict<RTLIL::IdString, RTLIL::Cell*>::iterator it);
|
|
||||||
|
|
||||||
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
|
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
|
||||||
void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
|
void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
|
||||||
|
|
|
@ -651,6 +651,10 @@ void rewrite_filename(std::string &filename)
|
||||||
filename = filename.substr(1, GetSize(filename)-2);
|
filename = filename.substr(1, GetSize(filename)-2);
|
||||||
if (filename.substr(0, 2) == "+/")
|
if (filename.substr(0, 2) == "+/")
|
||||||
filename = proc_share_dirname() + filename.substr(2);
|
filename = proc_share_dirname() + filename.substr(2);
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (filename.substr(0, 2) == "~/")
|
||||||
|
filename = filename.replace(0, 1, getenv("HOME"));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_TCL
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
|
|
@ -350,6 +350,18 @@ and this bit is a one (the second ``1'').} for {\tt \textbackslash{}reset == 1}
|
||||||
sets {\tt \$0\textbackslash{}q[0:0]} to the value of {\tt \textbackslash{}d} if {\tt
|
sets {\tt \$0\textbackslash{}q[0:0]} to the value of {\tt \textbackslash{}d} if {\tt
|
||||||
\textbackslash{}enable} is active (lines $6 \dots 11$).
|
\textbackslash{}enable} is active (lines $6 \dots 11$).
|
||||||
|
|
||||||
|
A case can specify zero or more compare values that will determine whether it matches. Each of the compare values
|
||||||
|
must be the exact same width as the control signal. When more than one compare value is specified, the case matches
|
||||||
|
if any of them matches the control signal; when zero compare values are specified, the case always matches (i.e.
|
||||||
|
it is the default case).
|
||||||
|
|
||||||
|
A switch prioritizes cases from first to last: multiple cases can match, but only the first matched case becomes
|
||||||
|
active. This normally synthesizes to a priority encoder. The {\tt parallel\_case} attribute allows passes to assume
|
||||||
|
that no more than one case will match, and {\tt full\_case} attribute allows passes to assume that exactly one
|
||||||
|
case will match; if these invariants are ever dynamically violated, the behavior is undefined. These attributes
|
||||||
|
are useful when an invariant invisible to the synthesizer causes the control signal to never take certain
|
||||||
|
bit patterns.
|
||||||
|
|
||||||
The lines $13 \dots 16$ then cause {\tt \textbackslash{}q} to be updated whenever there is
|
The lines $13 \dots 16$ then cause {\tt \textbackslash{}q} to be updated whenever there is
|
||||||
a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}.
|
a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}.
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct BlackboxPass : public Pass {
|
struct BlackboxPass : public Pass {
|
||||||
BlackboxPass() : Pass("blackbox", "change type of cells in the design") { }
|
BlackboxPass() : Pass("blackbox", "convert modules into blackbox modules") { }
|
||||||
void help() YS_OVERRIDE
|
void help() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
|
|
@ -285,8 +285,8 @@ struct StatPass : public Pass {
|
||||||
log(" use cell area information from the provided liberty file\n");
|
log(" use cell area information from the provided liberty file\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -tech <technology>\n");
|
log(" -tech <technology>\n");
|
||||||
log(" print area estemate for the specified technology. Corrently supported\n");
|
log(" print area estemate for the specified technology. Currently supported\n");
|
||||||
log(" calues for <technology>: xilinx\n");
|
log(" values for <technology>: xilinx\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -width\n");
|
log(" -width\n");
|
||||||
log(" annotate internal cell types with their word width.\n");
|
log(" annotate internal cell types with their word width.\n");
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct WriteFileFrontend : public Frontend {
|
||||||
if (argidx < args.size() && args[argidx].rfind("-", 0) != 0)
|
if (argidx < args.size() && args[argidx].rfind("-", 0) != 0)
|
||||||
output_filename = args[argidx++];
|
output_filename = args[argidx++];
|
||||||
else
|
else
|
||||||
log_cmd_error("Missing putput filename.\n");
|
log_cmd_error("Missing output filename.\n");
|
||||||
|
|
||||||
extra_args(f, filename, args, argidx);
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
|
|
|
@ -591,6 +591,9 @@ struct HierarchyPass : public Pass {
|
||||||
log(" module instances when the width does not match the module port. This\n");
|
log(" module instances when the width does not match the module port. This\n");
|
||||||
log(" option disables this behavior.\n");
|
log(" option disables this behavior.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -nodefaults\n");
|
||||||
|
log(" do not resolve input port default values\n");
|
||||||
|
log("\n");
|
||||||
log(" -nokeep_asserts\n");
|
log(" -nokeep_asserts\n");
|
||||||
log(" per default this pass sets the \"keep\" attribute on all modules\n");
|
log(" per default this pass sets the \"keep\" attribute on all modules\n");
|
||||||
log(" that directly or indirectly contain one or more formal properties.\n");
|
log(" that directly or indirectly contain one or more formal properties.\n");
|
||||||
|
@ -645,6 +648,7 @@ struct HierarchyPass : public Pass {
|
||||||
bool generate_mode = false;
|
bool generate_mode = false;
|
||||||
bool keep_positionals = false;
|
bool keep_positionals = false;
|
||||||
bool keep_portwidths = false;
|
bool keep_portwidths = false;
|
||||||
|
bool nodefaults = false;
|
||||||
bool nokeep_asserts = false;
|
bool nokeep_asserts = false;
|
||||||
std::vector<std::string> generate_cells;
|
std::vector<std::string> generate_cells;
|
||||||
std::vector<generate_port_decl_t> generate_ports;
|
std::vector<generate_port_decl_t> generate_ports;
|
||||||
|
@ -712,6 +716,10 @@ struct HierarchyPass : public Pass {
|
||||||
keep_portwidths = true;
|
keep_portwidths = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-nodefaults") {
|
||||||
|
nodefaults = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-nokeep_asserts") {
|
if (args[argidx] == "-nokeep_asserts") {
|
||||||
nokeep_asserts = true;
|
nokeep_asserts = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -940,6 +948,36 @@ struct HierarchyPass : public Pass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nodefaults)
|
||||||
|
{
|
||||||
|
dict<IdString, dict<IdString, Const>> defaults_db;
|
||||||
|
|
||||||
|
for (auto module : design->modules())
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_input && wire->attributes.count("\\defaultvalue"))
|
||||||
|
defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue");
|
||||||
|
|
||||||
|
for (auto module : design->modules())
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (defaults_db.count(cell->type) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (keep_positionals) {
|
||||||
|
bool found_positionals = false;
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9')
|
||||||
|
found_positionals = true;
|
||||||
|
if (found_positionals)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &it : defaults_db.at(cell->type))
|
||||||
|
if (!cell->hasPort(it.first))
|
||||||
|
cell->setPort(it.first, it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::set<Module*> blackbox_derivatives;
|
std::set<Module*> blackbox_derivatives;
|
||||||
std::vector<Module*> design_modules = design->modules();
|
std::vector<Module*> design_modules = design->modules();
|
||||||
|
|
||||||
|
|
|
@ -182,11 +182,17 @@ struct MemoryDffWorker
|
||||||
|
|
||||||
if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
|
if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
|
||||||
{
|
{
|
||||||
bool enable_invert = mux_cells_a.count(sig_data) != 0;
|
RTLIL::SigSpec en;
|
||||||
Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
|
RTLIL::SigSpec check_q;
|
||||||
SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
|
|
||||||
|
do {
|
||||||
|
bool enable_invert = mux_cells_a.count(sig_data) != 0;
|
||||||
|
Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
|
||||||
|
check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
|
||||||
|
sig_data = sigmap(mux->getPort("\\Y"));
|
||||||
|
en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
|
||||||
|
} while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data));
|
||||||
|
|
||||||
sig_data = sigmap(mux->getPort("\\Y"));
|
|
||||||
for (auto bit : sig_data)
|
for (auto bit : sig_data)
|
||||||
if (sigbit_users_count[bit] > 1)
|
if (sigbit_users_count[bit] > 1)
|
||||||
goto skip_ff_after_read_merging;
|
goto skip_ff_after_read_merging;
|
||||||
|
@ -195,7 +201,7 @@ struct MemoryDffWorker
|
||||||
{
|
{
|
||||||
disconnect_dff(sig_data);
|
disconnect_dff(sig_data);
|
||||||
cell->setPort("\\CLK", clk_data);
|
cell->setPort("\\CLK", clk_data);
|
||||||
cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
|
cell->setPort("\\EN", en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en);
|
||||||
cell->setPort("\\DATA", sig_data);
|
cell->setPort("\\DATA", sig_data);
|
||||||
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
|
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
|
||||||
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
|
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
|
||||||
|
|
|
@ -14,5 +14,6 @@ OBJS += passes/opt/opt_demorgan.o
|
||||||
OBJS += passes/opt/rmports.o
|
OBJS += passes/opt/rmports.o
|
||||||
OBJS += passes/opt/opt_lut.o
|
OBJS += passes/opt/opt_lut.o
|
||||||
OBJS += passes/opt/pmux2shiftx.o
|
OBJS += passes/opt/pmux2shiftx.o
|
||||||
|
OBJS += passes/opt/muxpack.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
368
passes/opt/muxpack.cc
Normal file
368
passes/opt/muxpack.cc
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* 2019 Eddie Hung <eddie@fpgeh.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
|
||||||
|
|
||||||
|
struct ExclusiveDatabase
|
||||||
|
{
|
||||||
|
Module *module;
|
||||||
|
const SigMap &sigmap;
|
||||||
|
|
||||||
|
dict<SigBit, std::pair<SigSpec,std::vector<Const>>> sig_cmp_prev;
|
||||||
|
|
||||||
|
ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap)
|
||||||
|
{
|
||||||
|
SigSpec const_sig, nonconst_sig;
|
||||||
|
SigBit y_port;
|
||||||
|
pool<Cell*> reduce_or;
|
||||||
|
for (auto cell : module->cells()) {
|
||||||
|
if (cell->type == "$eq") {
|
||||||
|
nonconst_sig = sigmap(cell->getPort("\\A"));
|
||||||
|
const_sig = sigmap(cell->getPort("\\B"));
|
||||||
|
if (!const_sig.is_fully_const()) {
|
||||||
|
if (!nonconst_sig.is_fully_const())
|
||||||
|
continue;
|
||||||
|
std::swap(nonconst_sig, const_sig);
|
||||||
|
}
|
||||||
|
y_port = sigmap(cell->getPort("\\Y"));
|
||||||
|
}
|
||||||
|
else if (cell->type == "$logic_not") {
|
||||||
|
nonconst_sig = sigmap(cell->getPort("\\A"));
|
||||||
|
const_sig = Const(RTLIL::S0, GetSize(nonconst_sig));
|
||||||
|
y_port = sigmap(cell->getPort("\\Y"));
|
||||||
|
}
|
||||||
|
else if (cell->type == "$reduce_or") {
|
||||||
|
reduce_or.insert(cell);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
|
||||||
|
log_assert(!nonconst_sig.empty());
|
||||||
|
log_assert(!const_sig.empty());
|
||||||
|
sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::vector<Const>{const_sig.as_const()});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : reduce_or) {
|
||||||
|
nonconst_sig = SigSpec();
|
||||||
|
std::vector<Const> values;
|
||||||
|
SigSpec a_port = sigmap(cell->getPort("\\A"));
|
||||||
|
for (auto bit : a_port) {
|
||||||
|
auto it = sig_cmp_prev.find(bit);
|
||||||
|
if (it == sig_cmp_prev.end()) {
|
||||||
|
nonconst_sig = SigSpec();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nonconst_sig.empty())
|
||||||
|
nonconst_sig = it->second.first;
|
||||||
|
else if (nonconst_sig != it->second.first) {
|
||||||
|
nonconst_sig = SigSpec();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto value : it->second.second)
|
||||||
|
values.push_back(value);
|
||||||
|
}
|
||||||
|
if (nonconst_sig.empty())
|
||||||
|
continue;
|
||||||
|
y_port = sigmap(cell->getPort("\\Y"));
|
||||||
|
sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::move(values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool query(const SigSpec &sig) const
|
||||||
|
{
|
||||||
|
SigSpec nonconst_sig;
|
||||||
|
pool<Const> const_values;
|
||||||
|
|
||||||
|
for (auto bit : sig.bits()) {
|
||||||
|
auto it = sig_cmp_prev.find(bit);
|
||||||
|
if (it == sig_cmp_prev.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (nonconst_sig.empty())
|
||||||
|
nonconst_sig = it->second.first;
|
||||||
|
else if (nonconst_sig != it->second.first)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto value : it->second.second)
|
||||||
|
if (!const_values.insert(value).second)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct MuxpackWorker
|
||||||
|
{
|
||||||
|
Module *module;
|
||||||
|
SigMap sigmap;
|
||||||
|
|
||||||
|
int mux_count, pmux_count;
|
||||||
|
|
||||||
|
pool<Cell*> remove_cells;
|
||||||
|
|
||||||
|
dict<SigSpec, Cell*> sig_chain_next;
|
||||||
|
dict<SigSpec, Cell*> sig_chain_prev;
|
||||||
|
pool<SigBit> sigbit_with_non_chain_users;
|
||||||
|
pool<Cell*> chain_start_cells;
|
||||||
|
pool<Cell*> candidate_cells;
|
||||||
|
|
||||||
|
ExclusiveDatabase excl_db;
|
||||||
|
|
||||||
|
void make_sig_chain_next_prev()
|
||||||
|
{
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
|
||||||
|
for (auto bit : sigmap(wire))
|
||||||
|
sigbit_with_non_chain_users.insert(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep"))
|
||||||
|
{
|
||||||
|
SigSpec a_sig = sigmap(cell->getPort("\\A"));
|
||||||
|
SigSpec b_sig;
|
||||||
|
if (cell->type == "$mux")
|
||||||
|
b_sig = sigmap(cell->getPort("\\B"));
|
||||||
|
SigSpec y_sig = sigmap(cell->getPort("\\Y"));
|
||||||
|
|
||||||
|
if (sig_chain_next.count(a_sig))
|
||||||
|
for (auto a_bit : a_sig.bits())
|
||||||
|
sigbit_with_non_chain_users.insert(a_bit);
|
||||||
|
else {
|
||||||
|
sig_chain_next[a_sig] = cell;
|
||||||
|
candidate_cells.insert(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!b_sig.empty()) {
|
||||||
|
if (sig_chain_next.count(b_sig))
|
||||||
|
for (auto b_bit : b_sig.bits())
|
||||||
|
sigbit_with_non_chain_users.insert(b_bit);
|
||||||
|
else {
|
||||||
|
sig_chain_next[b_sig] = cell;
|
||||||
|
candidate_cells.insert(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sig_chain_prev[y_sig] = cell;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto conn : cell->connections())
|
||||||
|
if (cell->input(conn.first))
|
||||||
|
for (auto bit : sigmap(conn.second))
|
||||||
|
sigbit_with_non_chain_users.insert(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void find_chain_start_cells()
|
||||||
|
{
|
||||||
|
for (auto cell : candidate_cells)
|
||||||
|
{
|
||||||
|
log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type));
|
||||||
|
|
||||||
|
SigSpec a_sig = sigmap(cell->getPort("\\A"));
|
||||||
|
if (cell->type == "$mux") {
|
||||||
|
SigSpec b_sig = sigmap(cell->getPort("\\B"));
|
||||||
|
if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1)
|
||||||
|
goto start_cell;
|
||||||
|
|
||||||
|
if (!sig_chain_prev.count(a_sig))
|
||||||
|
a_sig = b_sig;
|
||||||
|
}
|
||||||
|
else if (cell->type == "$pmux") {
|
||||||
|
if (!sig_chain_prev.count(a_sig))
|
||||||
|
goto start_cell;
|
||||||
|
}
|
||||||
|
else log_abort();
|
||||||
|
|
||||||
|
for (auto bit : a_sig.bits())
|
||||||
|
if (sigbit_with_non_chain_users.count(bit))
|
||||||
|
goto start_cell;
|
||||||
|
|
||||||
|
{
|
||||||
|
Cell *prev_cell = sig_chain_prev.at(a_sig);
|
||||||
|
log_assert(prev_cell);
|
||||||
|
SigSpec s_sig = sigmap(cell->getPort("\\S"));
|
||||||
|
s_sig.append(sigmap(prev_cell->getPort("\\S")));
|
||||||
|
if (!excl_db.query(s_sig))
|
||||||
|
goto start_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
start_cell:
|
||||||
|
chain_start_cells.insert(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Cell*> create_chain(Cell *start_cell)
|
||||||
|
{
|
||||||
|
vector<Cell*> chain;
|
||||||
|
|
||||||
|
Cell *c = start_cell;
|
||||||
|
while (c != nullptr)
|
||||||
|
{
|
||||||
|
chain.push_back(c);
|
||||||
|
|
||||||
|
SigSpec y_sig = sigmap(c->getPort("\\Y"));
|
||||||
|
|
||||||
|
if (sig_chain_next.count(y_sig) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
c = sig_chain_next.at(y_sig);
|
||||||
|
if (chain_start_cells.count(c) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_chain(vector<Cell*> &chain)
|
||||||
|
{
|
||||||
|
if (GetSize(chain) < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int cursor = 0;
|
||||||
|
while (cursor < GetSize(chain))
|
||||||
|
{
|
||||||
|
int cases = GetSize(chain) - cursor;
|
||||||
|
|
||||||
|
Cell *first_cell = chain[cursor];
|
||||||
|
dict<int, SigBit> taps_dict;
|
||||||
|
|
||||||
|
if (cases < 2) {
|
||||||
|
cursor++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell *last_cell = chain[cursor+cases-1];
|
||||||
|
|
||||||
|
log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n",
|
||||||
|
log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases);
|
||||||
|
|
||||||
|
mux_count += cases;
|
||||||
|
pmux_count += 1;
|
||||||
|
|
||||||
|
first_cell->type = "$pmux";
|
||||||
|
SigSpec b_sig = first_cell->getPort("\\B");
|
||||||
|
SigSpec s_sig = first_cell->getPort("\\S");
|
||||||
|
|
||||||
|
for (int i = 1; i < cases; i++) {
|
||||||
|
Cell* prev_cell = chain[cursor+i-1];
|
||||||
|
Cell* cursor_cell = chain[cursor+i];
|
||||||
|
if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) {
|
||||||
|
b_sig.append(cursor_cell->getPort("\\B"));
|
||||||
|
s_sig.append(cursor_cell->getPort("\\S"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_assert(cursor_cell->type == "$mux");
|
||||||
|
b_sig.append(cursor_cell->getPort("\\A"));
|
||||||
|
s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S")));
|
||||||
|
}
|
||||||
|
remove_cells.insert(cursor_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
first_cell->setPort("\\B", b_sig);
|
||||||
|
first_cell->setPort("\\S", s_sig);
|
||||||
|
first_cell->setParam("\\S_WIDTH", GetSize(s_sig));
|
||||||
|
first_cell->setPort("\\Y", last_cell->getPort("\\Y"));
|
||||||
|
|
||||||
|
cursor += cases;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
for (auto cell : remove_cells)
|
||||||
|
module->remove(cell);
|
||||||
|
|
||||||
|
remove_cells.clear();
|
||||||
|
sig_chain_next.clear();
|
||||||
|
sig_chain_prev.clear();
|
||||||
|
chain_start_cells.clear();
|
||||||
|
candidate_cells.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
MuxpackWorker(Module *module) :
|
||||||
|
module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap)
|
||||||
|
{
|
||||||
|
make_sig_chain_next_prev();
|
||||||
|
find_chain_start_cells();
|
||||||
|
|
||||||
|
for (auto c : chain_start_cells) {
|
||||||
|
vector<Cell*> chain = create_chain(c);
|
||||||
|
process_chain(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MuxpackPass : public Pass {
|
||||||
|
MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" muxpack [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
|
||||||
|
log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n");
|
||||||
|
log("$pmux cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log("This optimisation is conservative --- it will only pack $mux or $pmux cells\n");
|
||||||
|
log("whose select lines are driven by '$eq' cells with other such cells if it can be\n");
|
||||||
|
log("certain that their select inputs are mutually exclusive.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
int mux_count = 0;
|
||||||
|
int pmux_count = 0;
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules()) {
|
||||||
|
MuxpackWorker worker(module);
|
||||||
|
mux_count += worker.mux_count;
|
||||||
|
pmux_count += worker.pmux_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);
|
||||||
|
}
|
||||||
|
} MuxpackPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -44,7 +44,7 @@ struct OptPass : public Pass {
|
||||||
log(" opt_muxtree\n");
|
log(" opt_muxtree\n");
|
||||||
log(" opt_reduce [-fine] [-full]\n");
|
log(" opt_reduce [-fine] [-full]\n");
|
||||||
log(" opt_merge [-share_all]\n");
|
log(" opt_merge [-share_all]\n");
|
||||||
log(" opt_rmdff [-keepdc]\n");
|
log(" opt_rmdff [-keepdc] [-sat]\n");
|
||||||
log(" opt_clean [-purge]\n");
|
log(" opt_clean [-purge]\n");
|
||||||
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
||||||
log(" while <changed design>\n");
|
log(" while <changed design>\n");
|
||||||
|
@ -54,7 +54,7 @@ struct OptPass : public Pass {
|
||||||
log(" do\n");
|
log(" do\n");
|
||||||
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
||||||
log(" opt_merge [-share_all]\n");
|
log(" opt_merge [-share_all]\n");
|
||||||
log(" opt_rmdff [-keepdc]\n");
|
log(" opt_rmdff [-keepdc] [-sat]\n");
|
||||||
log(" opt_clean [-purge]\n");
|
log(" opt_clean [-purge]\n");
|
||||||
log(" while <changed design in opt_rmdff>\n");
|
log(" while <changed design in opt_rmdff>\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -112,6 +112,10 @@ struct OptPass : public Pass {
|
||||||
opt_rmdff_args += " -keepdc";
|
opt_rmdff_args += " -keepdc";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-sat") {
|
||||||
|
opt_rmdff_args += " -sat";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-share_all") {
|
if (args[argidx] == "-share_all") {
|
||||||
opt_merge_args += " -share_all";
|
opt_merge_args += " -share_all";
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -326,8 +326,8 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
|
||||||
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
|
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
|
||||||
// do not delete anything with "keep" or module ports or initialized wires
|
// do not delete anything with "keep" or module ports or initialized wires
|
||||||
} else
|
} else
|
||||||
if (!purge_mode && check_public_name(wire->name)) {
|
if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) {
|
||||||
// do not get rid of public names unless in purge mode
|
// do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased
|
||||||
} else
|
} else
|
||||||
if (!raw_used_signals.check_any(s1)) {
|
if (!raw_used_signals.check_any(s1)) {
|
||||||
// delete wires that aren't used by anything directly
|
// delete wires that aren't used by anything directly
|
||||||
|
@ -480,7 +480,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
|
||||||
|
|
||||||
std::vector<RTLIL::Cell*> delcells;
|
std::vector<RTLIL::Cell*> delcells;
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
if (cell->type.in("$pos", "$_BUF_")) {
|
if (cell->type.in("$pos", "$_BUF_") && !cell->has_keep_attr()) {
|
||||||
bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
|
bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
|
||||||
RTLIL::SigSpec a = cell->getPort("\\A");
|
RTLIL::SigSpec a = cell->getPort("\\A");
|
||||||
RTLIL::SigSpec y = cell->getPort("\\Y");
|
RTLIL::SigSpec y = cell->getPort("\\Y");
|
||||||
|
|
|
@ -17,19 +17,24 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/register.h"
|
|
||||||
#include "kernel/sigtools.h"
|
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
#include <stdlib.h>
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
#include "kernel/satgen.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
SigMap assign_map, dff_init_map;
|
SigMap assign_map, dff_init_map;
|
||||||
SigSet<RTLIL::Cell*> mux_drivers;
|
SigSet<RTLIL::Cell*> mux_drivers;
|
||||||
|
dict<SigBit, RTLIL::Cell*> bit2driver;
|
||||||
dict<SigBit, pool<SigBit>> init_attributes;
|
dict<SigBit, pool<SigBit>> init_attributes;
|
||||||
|
|
||||||
bool keepdc;
|
bool keepdc;
|
||||||
|
bool sat;
|
||||||
|
|
||||||
void remove_init_attr(SigSpec sig)
|
void remove_init_attr(SigSpec sig)
|
||||||
{
|
{
|
||||||
|
@ -452,12 +457,84 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||||
dff->unsetPort("\\E");
|
dff->unsetPort("\\E");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sat && has_init && (!sig_r.size() || val_init == val_rv))
|
||||||
|
{
|
||||||
|
bool removed_sigbits = false;
|
||||||
|
|
||||||
|
ezSatPtr ez;
|
||||||
|
SatGen satgen(ez.get(), &assign_map);
|
||||||
|
pool<Cell*> sat_cells;
|
||||||
|
|
||||||
|
std::function<void(Cell*)> sat_import_cell = [&](Cell *c) {
|
||||||
|
if (!sat_cells.insert(c).second)
|
||||||
|
return;
|
||||||
|
if (!satgen.importCell(c))
|
||||||
|
return;
|
||||||
|
for (auto &conn : c->connections()) {
|
||||||
|
if (!c->input(conn.first))
|
||||||
|
continue;
|
||||||
|
for (auto bit : assign_map(conn.second))
|
||||||
|
if (bit2driver.count(bit))
|
||||||
|
sat_import_cell(bit2driver.at(bit));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
|
||||||
|
for (int position = 0; position < GetSize(sig_d); position += 1) {
|
||||||
|
RTLIL::SigBit q_sigbit = sig_q[position];
|
||||||
|
RTLIL::SigBit d_sigbit = sig_d[position];
|
||||||
|
|
||||||
|
if ((!q_sigbit.wire) || (!d_sigbit.wire))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!bit2driver.count(d_sigbit))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sat_import_cell(bit2driver.at(d_sigbit));
|
||||||
|
|
||||||
|
RTLIL::State sigbit_init_val = val_init[position];
|
||||||
|
if (sigbit_init_val != State::S0 && sigbit_init_val != State::S1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int init_sat_pi = satgen.importSigSpec(sigbit_init_val).front();
|
||||||
|
int q_sat_pi = satgen.importSigBit(q_sigbit);
|
||||||
|
int d_sat_pi = satgen.importSigBit(d_sigbit);
|
||||||
|
|
||||||
|
// Try to find out whether the register bit can change under some circumstances
|
||||||
|
bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi)));
|
||||||
|
|
||||||
|
// If the register bit cannot change, we can replace it with a constant
|
||||||
|
if (!counter_example_found)
|
||||||
|
{
|
||||||
|
log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", sigbit_init_val ? 1 : 0,
|
||||||
|
position, log_id(dff), log_id(dff->type), log_id(mod));
|
||||||
|
|
||||||
|
SigSpec tmp = dff->getPort("\\D");
|
||||||
|
tmp[position] = sigbit_init_val;
|
||||||
|
dff->setPort("\\D", tmp);
|
||||||
|
|
||||||
|
removed_sigbits = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed_sigbits) {
|
||||||
|
handle_dff(mod, dff);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
delete_dff:
|
delete_dff:
|
||||||
log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
|
log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
|
||||||
remove_init_attr(dff->getPort("\\Q"));
|
remove_init_attr(dff->getPort("\\Q"));
|
||||||
mod->remove(dff);
|
mod->remove(dff);
|
||||||
|
|
||||||
|
for (auto &entry : bit2driver)
|
||||||
|
if (entry.second == dff)
|
||||||
|
bit2driver.erase(entry.first);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,11 +544,15 @@ struct OptRmdffPass : public Pass {
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" opt_rmdff [-keepdc] [selection]\n");
|
log(" opt_rmdff [-keepdc] [-sat] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass identifies flip-flops with constant inputs and replaces them with\n");
|
log("This pass identifies flip-flops with constant inputs and replaces them with\n");
|
||||||
log("a constant driver.\n");
|
log("a constant driver.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -sat\n");
|
||||||
|
log(" additionally invoke SAT solver to detect and remove flip-flops (with \n");
|
||||||
|
log(" non-constant inputs) that can also be replaced with a constant driver\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -479,6 +560,7 @@ struct OptRmdffPass : public Pass {
|
||||||
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
|
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
|
||||||
|
|
||||||
keepdc = false;
|
keepdc = false;
|
||||||
|
sat = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
@ -486,18 +568,22 @@ struct OptRmdffPass : public Pass {
|
||||||
keepdc = true;
|
keepdc = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-sat") {
|
||||||
|
sat = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
for (auto module : design->selected_modules())
|
for (auto module : design->selected_modules()) {
|
||||||
{
|
|
||||||
pool<SigBit> driven_bits;
|
pool<SigBit> driven_bits;
|
||||||
dict<SigBit, State> init_bits;
|
dict<SigBit, State> init_bits;
|
||||||
|
|
||||||
assign_map.set(module);
|
assign_map.set(module);
|
||||||
dff_init_map.set(module);
|
dff_init_map.set(module);
|
||||||
mux_drivers.clear();
|
mux_drivers.clear();
|
||||||
|
bit2driver.clear();
|
||||||
init_attributes.clear();
|
init_attributes.clear();
|
||||||
|
|
||||||
for (auto wire : module->wires())
|
for (auto wire : module->wires())
|
||||||
|
@ -522,17 +608,21 @@ struct OptRmdffPass : public Pass {
|
||||||
driven_bits.insert(bit);
|
driven_bits.insert(bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mux_drivers.clear();
|
|
||||||
|
|
||||||
std::vector<RTLIL::IdString> dff_list;
|
std::vector<RTLIL::IdString> dff_list;
|
||||||
std::vector<RTLIL::IdString> dffsr_list;
|
std::vector<RTLIL::IdString> dffsr_list;
|
||||||
std::vector<RTLIL::IdString> dlatch_list;
|
std::vector<RTLIL::IdString> dlatch_list;
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
{
|
{
|
||||||
for (auto &conn : cell->connections())
|
for (auto &conn : cell->connections()) {
|
||||||
if (cell->output(conn.first) || !cell->known())
|
bool is_output = cell->output(conn.first);
|
||||||
for (auto bit : assign_map(conn.second))
|
if (is_output || !cell->known())
|
||||||
|
for (auto bit : assign_map(conn.second)) {
|
||||||
|
if (is_output)
|
||||||
|
bit2driver[bit] = cell;
|
||||||
driven_bits.insert(bit);
|
driven_bits.insert(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->type == "$mux" || cell->type == "$pmux") {
|
if (cell->type == "$mux" || cell->type == "$pmux") {
|
||||||
if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
|
if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
|
||||||
|
@ -604,6 +694,7 @@ struct OptRmdffPass : public Pass {
|
||||||
|
|
||||||
assign_map.clear();
|
assign_map.clear();
|
||||||
mux_drivers.clear();
|
mux_drivers.clear();
|
||||||
|
bit2driver.clear();
|
||||||
init_attributes.clear();
|
init_attributes.clear();
|
||||||
|
|
||||||
if (total_count || total_initdrv)
|
if (total_count || total_initdrv)
|
||||||
|
|
|
@ -221,6 +221,9 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
log(" select strategy for one-hot encoded control signals\n");
|
log(" select strategy for one-hot encoded control signals\n");
|
||||||
log(" default: pmux\n");
|
log(" default: pmux\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -norange\n");
|
||||||
|
log(" disable $sub inference for \"range decoders\"\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -230,6 +233,7 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
bool optimize_onehot = true;
|
bool optimize_onehot = true;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool verbose_onehot = false;
|
bool verbose_onehot = false;
|
||||||
|
bool norange = false;
|
||||||
|
|
||||||
log_header(design, "Executing PMUX2SHIFTX pass.\n");
|
log_header(design, "Executing PMUX2SHIFTX pass.\n");
|
||||||
|
|
||||||
|
@ -270,6 +274,10 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
verbose_onehot = true;
|
verbose_onehot = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-norange") {
|
||||||
|
norange = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -559,7 +567,7 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
int this_inv_delta = this_maxval - this_minval;
|
int this_inv_delta = this_maxval - this_minval;
|
||||||
bool this_inv = false;
|
bool this_inv = false;
|
||||||
|
|
||||||
if (this_delta != this_inv_delta)
|
if (!norange && this_delta != this_inv_delta)
|
||||||
this_inv = this_inv_delta < this_delta;
|
this_inv = this_inv_delta < this_delta;
|
||||||
else if (this_maxval != this_inv_maxval)
|
else if (this_maxval != this_inv_maxval)
|
||||||
this_inv = this_inv_maxval < this_maxval;
|
this_inv = this_inv_maxval < this_maxval;
|
||||||
|
@ -574,7 +582,7 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
|
|
||||||
if (best_src_col < 0)
|
if (best_src_col < 0)
|
||||||
this_is_better = true;
|
this_is_better = true;
|
||||||
else if (this_delta != best_delta)
|
else if (!norange && this_delta != best_delta)
|
||||||
this_is_better = this_delta < best_delta;
|
this_is_better = this_delta < best_delta;
|
||||||
else if (this_maxval != best_maxval)
|
else if (this_maxval != best_maxval)
|
||||||
this_is_better = this_maxval < best_maxval;
|
this_is_better = this_maxval < best_maxval;
|
||||||
|
@ -656,7 +664,7 @@ struct Pmux2ShiftxPass : public Pass {
|
||||||
|
|
||||||
// check density percentages
|
// check density percentages
|
||||||
Const offset(State::S0, GetSize(sig));
|
Const offset(State::S0, GetSize(sig));
|
||||||
if (absolute_density < min_density && range_density >= min_density)
|
if (!norange && absolute_density < min_density && range_density >= min_density)
|
||||||
{
|
{
|
||||||
offset = Const(min_choice, GetSize(sig));
|
offset = Const(min_choice, GetSize(sig));
|
||||||
log(" offset: %s\n", log_signal(offset));
|
log(" offset: %s\n", log_signal(offset));
|
||||||
|
|
|
@ -180,7 +180,7 @@ struct AssertpmuxWorker
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssertpmuxPass : public Pass {
|
struct AssertpmuxPass : public Pass {
|
||||||
AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
|
AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { }
|
||||||
void help() YS_OVERRIDE
|
void help() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
@ -195,8 +195,8 @@ struct AssertpmuxPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -always\n");
|
log(" -always\n");
|
||||||
log(" usually the $pmux condition is only checked when the $pmux output\n");
|
log(" usually the $pmux condition is only checked when the $pmux output\n");
|
||||||
log(" is used be the mux tree it drives. this option will deactivate this\n");
|
log(" is used by the mux tree it drives. this option will deactivate this\n");
|
||||||
log(" additional constrained and check the $pmux condition always.\n");
|
log(" additional constraint and check the $pmux condition always.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
|
|
@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct CutpointPass : public Pass {
|
struct CutpointPass : public Pass {
|
||||||
CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
|
CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { }
|
||||||
void help() YS_OVERRIDE
|
void help() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
|
|
@ -659,6 +659,7 @@ struct SatHelper
|
||||||
|
|
||||||
void dump_model_to_vcd(std::string vcd_file_name)
|
void dump_model_to_vcd(std::string vcd_file_name)
|
||||||
{
|
{
|
||||||
|
rewrite_filename(vcd_file_name);
|
||||||
FILE *f = fopen(vcd_file_name.c_str(), "w");
|
FILE *f = fopen(vcd_file_name.c_str(), "w");
|
||||||
if (!f)
|
if (!f)
|
||||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno));
|
log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno));
|
||||||
|
@ -761,6 +762,7 @@ struct SatHelper
|
||||||
|
|
||||||
void dump_model_to_json(std::string json_file_name)
|
void dump_model_to_json(std::string json_file_name)
|
||||||
{
|
{
|
||||||
|
rewrite_filename(json_file_name);
|
||||||
FILE *f = fopen(json_file_name.c_str(), "w");
|
FILE *f = fopen(json_file_name.c_str(), "w");
|
||||||
if (!f)
|
if (!f)
|
||||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno));
|
log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno));
|
||||||
|
@ -1505,6 +1507,7 @@ struct SatPass : public Pass {
|
||||||
{
|
{
|
||||||
if (!cnf_file_name.empty())
|
if (!cnf_file_name.empty())
|
||||||
{
|
{
|
||||||
|
rewrite_filename(cnf_file_name);
|
||||||
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
||||||
if (!f)
|
if (!f)
|
||||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
|
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
|
||||||
|
@ -1608,6 +1611,7 @@ struct SatPass : public Pass {
|
||||||
|
|
||||||
if (!cnf_file_name.empty())
|
if (!cnf_file_name.empty())
|
||||||
{
|
{
|
||||||
|
rewrite_filename(cnf_file_name);
|
||||||
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
||||||
if (!f)
|
if (!f)
|
||||||
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
|
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
|
||||||
|
|
|
@ -10,6 +10,7 @@ OBJS += passes/techmap/abc.o
|
||||||
OBJS += passes/techmap/abc9.o
|
OBJS += passes/techmap/abc9.o
|
||||||
ifneq ($(ABCEXTERNAL),)
|
ifneq ($(ABCEXTERNAL),)
|
||||||
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||||
|
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define ABC_FAST_COMMAND_LUT "&st; &retime; &if {W}"
|
#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}"
|
||||||
|
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
|
@ -80,8 +80,7 @@ void handle_loops(RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
Pass::call(design, "scc -set_attr abc_scc_id {}");
|
Pass::call(design, "scc -set_attr abc_scc_id {}");
|
||||||
|
|
||||||
design->selection_stack.emplace_back(false);
|
dict<IdString, vector<IdString>> abc_scc_break;
|
||||||
RTLIL::Selection& sel = design->selection_stack.back();
|
|
||||||
|
|
||||||
// For every unique SCC found, (arbitrarily) find the first
|
// For every unique SCC found, (arbitrarily) find the first
|
||||||
// cell in the component, and select (and mark) all its output
|
// cell in the component, and select (and mark) all its output
|
||||||
|
@ -92,24 +91,72 @@ void handle_loops(RTLIL::Design *design)
|
||||||
if (it != cell->attributes.end()) {
|
if (it != cell->attributes.end()) {
|
||||||
auto r = ids_seen.insert(it->second);
|
auto r = ids_seen.insert(it->second);
|
||||||
if (r.second) {
|
if (r.second) {
|
||||||
for (const auto &c : cell->connections()) {
|
for (auto &c : cell->connections_) {
|
||||||
if (c.second.is_fully_const()) continue;
|
if (c.second.is_fully_const()) continue;
|
||||||
if (cell->output(c.first)) {
|
if (cell->output(c.first)) {
|
||||||
SigBit b = c.second.as_bit();
|
SigBit b = c.second.as_bit();
|
||||||
Wire *w = b.wire;
|
Wire *w = b.wire;
|
||||||
|
log_assert(!w->port_input);
|
||||||
|
w->port_input = true;
|
||||||
|
w = module->wire(stringf("%s.abci", w->name.c_str()));
|
||||||
|
if (!w) {
|
||||||
|
w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
|
||||||
|
w->port_output = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_assert(w->port_input);
|
||||||
|
log_assert(b.offset < GetSize(w));
|
||||||
|
}
|
||||||
w->set_bool_attribute("\\abc_scc_break");
|
w->set_bool_attribute("\\abc_scc_break");
|
||||||
sel.select(module, w);
|
module->swap_names(b.wire, w);
|
||||||
|
c.second = RTLIL::SigBit(w, b.offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cell->attributes.erase(it);
|
cell->attributes.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto jt = abc_scc_break.find(cell->type);
|
||||||
|
if (jt == abc_scc_break.end()) {
|
||||||
|
std::vector<IdString> ports;
|
||||||
|
RTLIL::Module* box_module = design->module(cell->type);
|
||||||
|
if (box_module) {
|
||||||
|
auto ports_csv = box_module->attributes.at("\\abc_scc_break", RTLIL::Const::from_string("")).decode_string();
|
||||||
|
for (const auto &port_name : split_tokens(ports_csv, ",")) {
|
||||||
|
auto port_id = RTLIL::escape_id(port_name);
|
||||||
|
auto kt = cell->connections_.find(port_id);
|
||||||
|
if (kt == cell->connections_.end())
|
||||||
|
log_error("abc_scc_break attribute value '%s' does not exist as port on module '%s'\n", port_name.c_str(), log_id(box_module));
|
||||||
|
ports.push_back(port_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jt = abc_scc_break.insert(std::make_pair(cell->type, std::move(ports))).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto port_name : jt->second) {
|
||||||
|
RTLIL::SigSpec sig;
|
||||||
|
auto &rhs = cell->connections_.at(port_name);
|
||||||
|
for (auto b : rhs) {
|
||||||
|
Wire *w = b.wire;
|
||||||
|
if (!w) continue;
|
||||||
|
w->port_output = true;
|
||||||
|
w->set_bool_attribute("\\abc_scc_break");
|
||||||
|
w = module->wire(stringf("%s.abci", w->name.c_str()));
|
||||||
|
if (!w) {
|
||||||
|
w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
|
||||||
|
w->port_input = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_assert(b.offset < GetSize(w));
|
||||||
|
log_assert(w->port_input);
|
||||||
|
}
|
||||||
|
sig.append(RTLIL::SigBit(w, b.offset));
|
||||||
|
}
|
||||||
|
rhs = sig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then cut those selected wires to expose them as new PO/PI
|
module->fixup_ports();
|
||||||
Pass::call(design, "expose -cut -sep .abc");
|
|
||||||
|
|
||||||
design->selection_stack.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string add_echos_to_abc_cmd(std::string str)
|
std::string add_echos_to_abc_cmd(std::string str)
|
||||||
|
@ -380,9 +427,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
RTLIL::Selection& sel = design->selection_stack.back();
|
RTLIL::Selection& sel = design->selection_stack.back();
|
||||||
sel.select(module);
|
sel.select(module);
|
||||||
|
|
||||||
// Behave as for "abc" where BLIF writer implicitly outputs all undef as zero
|
|
||||||
Pass::call(design, "setundef -zero");
|
|
||||||
|
|
||||||
Pass::call(design, "aigmap");
|
Pass::call(design, "aigmap");
|
||||||
|
|
||||||
handle_loops(design);
|
handle_loops(design);
|
||||||
|
@ -409,7 +453,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
reader.parse_xaiger();
|
reader.parse_xaiger();
|
||||||
}
|
}
|
||||||
ifs.close();
|
ifs.close();
|
||||||
Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v"));
|
Pass::call(design, stringf("write_verilog -noexpr -norename"));
|
||||||
design->remove(design->module("$__abc9__"));
|
design->remove(design->module("$__abc9__"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -482,7 +526,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
ifs.close();
|
ifs.close();
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "output.v"));
|
Pass::call(design, stringf("write_verilog -noexpr -norename"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
log_header(design, "Re-integrating ABC9 results.\n");
|
log_header(design, "Re-integrating ABC9 results.\n");
|
||||||
|
@ -498,7 +542,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
if (w->port_output) {
|
if (w->port_output) {
|
||||||
RTLIL::Wire *wire = module->wire(w->name);
|
RTLIL::Wire *wire = module->wire(w->name);
|
||||||
log_assert(wire);
|
log_assert(wire);
|
||||||
for (int i = 0; i < GetSize(wire); i++)
|
for (int i = 0; i < GetSize(w); i++)
|
||||||
output_bits.insert({wire, i});
|
output_bits.insert({wire, i});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,24 +562,28 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
signal = std::move(bits);
|
signal = std::move(bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict<IdString, bool> abc_box;
|
||||||
vector<RTLIL::Cell*> boxes;
|
vector<RTLIL::Cell*> boxes;
|
||||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
|
for (const auto &it : module->cells_) {
|
||||||
RTLIL::Cell* cell = it->second;
|
auto cell = it.second;
|
||||||
if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) {
|
if (cell->type.in("$_AND_", "$_NOT_")) {
|
||||||
it = module->remove(it);
|
module->remove(cell);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
RTLIL::Module* box_module = design->module(cell->type);
|
auto jt = abc_box.find(cell->type);
|
||||||
if (box_module && box_module->attributes.count("\\abc_box_id"))
|
if (jt == abc_box.end()) {
|
||||||
|
RTLIL::Module* box_module = design->module(cell->type);
|
||||||
|
jt = abc_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count("\\abc_box_id"))).first;
|
||||||
|
}
|
||||||
|
if (jt->second)
|
||||||
boxes.emplace_back(cell);
|
boxes.emplace_back(cell);
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, int> cell_stats;
|
std::map<std::string, int> cell_stats;
|
||||||
for (auto c : mapped_mod->cells())
|
for (auto c : mapped_mod->cells())
|
||||||
{
|
{
|
||||||
|
RTLIL::Cell *cell = nullptr;
|
||||||
if (c->type == "$_NOT_") {
|
if (c->type == "$_NOT_") {
|
||||||
RTLIL::Cell *cell;
|
|
||||||
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
|
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
|
||||||
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
|
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
|
||||||
if (!a_bit.wire) {
|
if (!a_bit.wire) {
|
||||||
|
@ -589,11 +637,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
|
cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
|
||||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||||
}
|
}
|
||||||
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||||
|
|
||||||
|
RTLIL::Cell *existing_cell = nullptr;
|
||||||
if (c->type == "$lut") {
|
if (c->type == "$lut") {
|
||||||
if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
|
if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
|
||||||
SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
|
SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
|
||||||
|
@ -602,19 +651,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
|
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
cell = module->addCell(remap_name(c->name), c->type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existing_cell = module->cell(c->name);
|
||||||
|
cell = module->addCell(remap_name(c->name), c->type);
|
||||||
|
module->swap_names(cell, existing_cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
|
|
||||||
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
||||||
RTLIL::Cell *existing_cell = module->cell(c->name);
|
if (existing_cell) {
|
||||||
if (existing_cell) {
|
cell->parameters = existing_cell->parameters;
|
||||||
cell->parameters = existing_cell->parameters;
|
cell->attributes = existing_cell->attributes;
|
||||||
cell->attributes = existing_cell->attributes;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
cell->parameters = c->parameters;
|
||||||
cell->parameters = c->parameters;
|
cell->attributes = c->attributes;
|
||||||
cell->attributes = c->attributes;
|
}
|
||||||
}
|
|
||||||
for (auto &conn : c->connections()) {
|
for (auto &conn : c->connections()) {
|
||||||
RTLIL::SigSpec newsig;
|
RTLIL::SigSpec newsig;
|
||||||
for (auto c : conn.second.chunks()) {
|
for (auto c : conn.second.chunks()) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define COST_DMUX 90
|
||||||
#define COST_MUX2 100
|
#define COST_MUX2 100
|
||||||
#define COST_MUX4 220
|
#define COST_MUX4 220
|
||||||
#define COST_MUX8 460
|
#define COST_MUX8 460
|
||||||
|
@ -57,7 +58,9 @@ struct MuxcoverWorker
|
||||||
bool use_mux8;
|
bool use_mux8;
|
||||||
bool use_mux16;
|
bool use_mux16;
|
||||||
bool nodecode;
|
bool nodecode;
|
||||||
|
bool nopartial;
|
||||||
|
|
||||||
|
int cost_dmux;
|
||||||
int cost_mux2;
|
int cost_mux2;
|
||||||
int cost_mux4;
|
int cost_mux4;
|
||||||
int cost_mux8;
|
int cost_mux8;
|
||||||
|
@ -69,6 +72,8 @@ struct MuxcoverWorker
|
||||||
use_mux8 = false;
|
use_mux8 = false;
|
||||||
use_mux16 = false;
|
use_mux16 = false;
|
||||||
nodecode = false;
|
nodecode = false;
|
||||||
|
nopartial = false;
|
||||||
|
cost_dmux = COST_DMUX;
|
||||||
cost_mux2 = COST_MUX2;
|
cost_mux2 = COST_MUX2;
|
||||||
cost_mux4 = COST_MUX4;
|
cost_mux4 = COST_MUX4;
|
||||||
cost_mux8 = COST_MUX8;
|
cost_mux8 = COST_MUX8;
|
||||||
|
@ -76,6 +81,23 @@ struct MuxcoverWorker
|
||||||
decode_mux_counter = 0;
|
decode_mux_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool xcmp(std::initializer_list<SigBit> list)
|
||||||
|
{
|
||||||
|
auto cursor = list.begin(), end = list.end();
|
||||||
|
log_assert(cursor != end);
|
||||||
|
SigBit tmp = *(cursor++);
|
||||||
|
while (cursor != end) {
|
||||||
|
SigBit bit = *(cursor++);
|
||||||
|
if (bit == State::Sx)
|
||||||
|
continue;
|
||||||
|
if (tmp == State::Sx)
|
||||||
|
tmp = bit;
|
||||||
|
if (bit != tmp)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void treeify()
|
void treeify()
|
||||||
{
|
{
|
||||||
pool<SigBit> roots;
|
pool<SigBit> roots;
|
||||||
|
@ -133,13 +155,22 @@ struct MuxcoverWorker
|
||||||
log(" Finished treeification: Found %d trees.\n", GetSize(tree_list));
|
log(" Finished treeification: Found %d trees.\n", GetSize(tree_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path)
|
bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path, bool first_layer = true)
|
||||||
{
|
{
|
||||||
if (*path) {
|
if (*path) {
|
||||||
if (tree.muxes.count(bit) == 0)
|
if (tree.muxes.count(bit) == 0) {
|
||||||
return false;
|
if (first_layer || nopartial)
|
||||||
|
return false;
|
||||||
|
while (path[0] && path[1])
|
||||||
|
path++;
|
||||||
|
if (path[0] == 'S')
|
||||||
|
ret_bit = State::Sx;
|
||||||
|
else
|
||||||
|
ret_bit = bit;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
char port_name[3] = {'\\', *path, 0};
|
char port_name[3] = {'\\', *path, 0};
|
||||||
return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1);
|
return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1, false);
|
||||||
} else {
|
} else {
|
||||||
ret_bit = bit;
|
ret_bit = bit;
|
||||||
return true;
|
return true;
|
||||||
|
@ -148,7 +179,7 @@ struct MuxcoverWorker
|
||||||
|
|
||||||
int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit)
|
int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit)
|
||||||
{
|
{
|
||||||
if (A == B)
|
if (A == B || sel == State::Sx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tuple<SigBit, SigBit, SigBit> key(A, B, sel);
|
tuple<SigBit, SigBit, SigBit> key(A, B, sel);
|
||||||
|
@ -166,7 +197,10 @@ struct MuxcoverWorker
|
||||||
if (std::get<2>(entry))
|
if (std::get<2>(entry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return cost_mux2 / GetSize(std::get<1>(entry));
|
if (A == State::Sx || B == State::Sx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return cost_dmux / GetSize(std::get<1>(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void implement_decode_mux(SigBit ctrl_bit)
|
void implement_decode_mux(SigBit ctrl_bit)
|
||||||
|
@ -183,9 +217,32 @@ struct MuxcoverWorker
|
||||||
implement_decode_mux(std::get<0>(key));
|
implement_decode_mux(std::get<0>(key));
|
||||||
implement_decode_mux(std::get<1>(key));
|
implement_decode_mux(std::get<1>(key));
|
||||||
|
|
||||||
module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit);
|
if (std::get<0>(key) == State::Sx) {
|
||||||
|
module->addBufGate(NEW_ID, std::get<1>(key), ctrl_bit);
|
||||||
|
} else if (std::get<1>(key) == State::Sx) {
|
||||||
|
module->addBufGate(NEW_ID, std::get<0>(key), ctrl_bit);
|
||||||
|
} else {
|
||||||
|
module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit);
|
||||||
|
decode_mux_counter++;
|
||||||
|
}
|
||||||
std::get<2>(entry) = true;
|
std::get<2>(entry) = true;
|
||||||
decode_mux_counter++;
|
}
|
||||||
|
|
||||||
|
void find_best_covers(tree_t &tree, const vector<SigBit> &bits)
|
||||||
|
{
|
||||||
|
for (auto bit : bits)
|
||||||
|
find_best_cover(tree, bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sum_best_covers(tree_t &tree, const vector<SigBit> &bits)
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
for (auto bit : pool<SigBit>(bits.begin(), bits.end())) {
|
||||||
|
int cost = tree.newmuxes.at(bit).cost;
|
||||||
|
log_debug(" Best cost for %s: %d\n", log_signal(bit), cost);
|
||||||
|
sum += cost;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_best_cover(tree_t &tree, SigBit bit)
|
int find_best_cover(tree_t &tree, SigBit bit)
|
||||||
|
@ -218,9 +275,13 @@ struct MuxcoverWorker
|
||||||
mux.inputs.push_back(B);
|
mux.inputs.push_back(B);
|
||||||
mux.selects.push_back(S1);
|
mux.selects.push_back(S1);
|
||||||
|
|
||||||
|
find_best_covers(tree, mux.inputs);
|
||||||
|
log_debug(" Decode cost for mux2 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
|
|
||||||
mux.cost += cost_mux2;
|
mux.cost += cost_mux2;
|
||||||
mux.cost += find_best_cover(tree, A);
|
mux.cost += sum_best_covers(tree, mux.inputs);
|
||||||
mux.cost += find_best_cover(tree, B);
|
|
||||||
|
log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
|
|
||||||
best_mux = mux;
|
best_mux = mux;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +299,7 @@ struct MuxcoverWorker
|
||||||
ok = ok && follow_muxtree(S2, tree, bit, "BS");
|
ok = ok && follow_muxtree(S2, tree, bit, "BS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && S1 == S2;
|
ok = ok && xcmp({S1, S2});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(T1, tree, bit, "S");
|
ok = ok && follow_muxtree(T1, tree, bit, "S");
|
||||||
|
|
||||||
|
@ -256,13 +317,15 @@ struct MuxcoverWorker
|
||||||
mux.selects.push_back(S1);
|
mux.selects.push_back(S1);
|
||||||
mux.selects.push_back(T1);
|
mux.selects.push_back(T1);
|
||||||
|
|
||||||
mux.cost += cost_mux4;
|
find_best_covers(tree, mux.inputs);
|
||||||
mux.cost += find_best_cover(tree, A);
|
log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
mux.cost += find_best_cover(tree, B);
|
|
||||||
mux.cost += find_best_cover(tree, C);
|
|
||||||
mux.cost += find_best_cover(tree, D);
|
|
||||||
|
|
||||||
if (best_mux.cost > mux.cost)
|
mux.cost += cost_mux4;
|
||||||
|
mux.cost += sum_best_covers(tree, mux.inputs);
|
||||||
|
|
||||||
|
log_debug(" Cost of mux4 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
|
|
||||||
|
if (best_mux.cost >= mux.cost)
|
||||||
best_mux = mux;
|
best_mux = mux;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,13 +349,13 @@ struct MuxcoverWorker
|
||||||
ok = ok && follow_muxtree(S4, tree, bit, "BBS");
|
ok = ok && follow_muxtree(S4, tree, bit, "BBS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && S1 == S2 && S2 == S3 && S3 == S4;
|
ok = ok && xcmp({S1, S2, S3, S4});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(T1, tree, bit, "AS");
|
ok = ok && follow_muxtree(T1, tree, bit, "AS");
|
||||||
ok = ok && follow_muxtree(T2, tree, bit, "BS");
|
ok = ok && follow_muxtree(T2, tree, bit, "BS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && T1 == T2;
|
ok = ok && xcmp({T1, T2});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(U1, tree, bit, "S");
|
ok = ok && follow_muxtree(U1, tree, bit, "S");
|
||||||
|
|
||||||
|
@ -319,17 +382,15 @@ struct MuxcoverWorker
|
||||||
mux.selects.push_back(T1);
|
mux.selects.push_back(T1);
|
||||||
mux.selects.push_back(U1);
|
mux.selects.push_back(U1);
|
||||||
|
|
||||||
mux.cost += cost_mux8;
|
find_best_covers(tree, mux.inputs);
|
||||||
mux.cost += find_best_cover(tree, A);
|
log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
mux.cost += find_best_cover(tree, B);
|
|
||||||
mux.cost += find_best_cover(tree, C);
|
|
||||||
mux.cost += find_best_cover(tree, D);
|
|
||||||
mux.cost += find_best_cover(tree, E);
|
|
||||||
mux.cost += find_best_cover(tree, F);
|
|
||||||
mux.cost += find_best_cover(tree, G);
|
|
||||||
mux.cost += find_best_cover(tree, H);
|
|
||||||
|
|
||||||
if (best_mux.cost > mux.cost)
|
mux.cost += cost_mux8;
|
||||||
|
mux.cost += sum_best_covers(tree, mux.inputs);
|
||||||
|
|
||||||
|
log_debug(" Cost of mux8 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
|
|
||||||
|
if (best_mux.cost >= mux.cost)
|
||||||
best_mux = mux;
|
best_mux = mux;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +426,7 @@ struct MuxcoverWorker
|
||||||
ok = ok && follow_muxtree(S8, tree, bit, "BBBS");
|
ok = ok && follow_muxtree(S8, tree, bit, "BBBS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && S1 == S2 && S2 == S3 && S3 == S4 && S4 == S5 && S5 == S6 && S6 == S7 && S7 == S8;
|
ok = ok && xcmp({S1, S2, S3, S4, S5, S6, S7, S8});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(T1, tree, bit, "AAS");
|
ok = ok && follow_muxtree(T1, tree, bit, "AAS");
|
||||||
ok = ok && follow_muxtree(T2, tree, bit, "ABS");
|
ok = ok && follow_muxtree(T2, tree, bit, "ABS");
|
||||||
|
@ -373,13 +434,13 @@ struct MuxcoverWorker
|
||||||
ok = ok && follow_muxtree(T4, tree, bit, "BBS");
|
ok = ok && follow_muxtree(T4, tree, bit, "BBS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && T1 == T2 && T2 == T3 && T3 == T4;
|
ok = ok && xcmp({T1, T2, T3, T4});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(U1, tree, bit, "AS");
|
ok = ok && follow_muxtree(U1, tree, bit, "AS");
|
||||||
ok = ok && follow_muxtree(U2, tree, bit, "BS");
|
ok = ok && follow_muxtree(U2, tree, bit, "BS");
|
||||||
|
|
||||||
if (nodecode)
|
if (nodecode)
|
||||||
ok = ok && U1 == U2;
|
ok = ok && xcmp({U1, U2});
|
||||||
|
|
||||||
ok = ok && follow_muxtree(V1, tree, bit, "S");
|
ok = ok && follow_muxtree(V1, tree, bit, "S");
|
||||||
|
|
||||||
|
@ -423,25 +484,15 @@ struct MuxcoverWorker
|
||||||
mux.selects.push_back(U1);
|
mux.selects.push_back(U1);
|
||||||
mux.selects.push_back(V1);
|
mux.selects.push_back(V1);
|
||||||
|
|
||||||
mux.cost += cost_mux16;
|
find_best_covers(tree, mux.inputs);
|
||||||
mux.cost += find_best_cover(tree, A);
|
log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
mux.cost += find_best_cover(tree, B);
|
|
||||||
mux.cost += find_best_cover(tree, C);
|
|
||||||
mux.cost += find_best_cover(tree, D);
|
|
||||||
mux.cost += find_best_cover(tree, E);
|
|
||||||
mux.cost += find_best_cover(tree, F);
|
|
||||||
mux.cost += find_best_cover(tree, G);
|
|
||||||
mux.cost += find_best_cover(tree, H);
|
|
||||||
mux.cost += find_best_cover(tree, I);
|
|
||||||
mux.cost += find_best_cover(tree, J);
|
|
||||||
mux.cost += find_best_cover(tree, K);
|
|
||||||
mux.cost += find_best_cover(tree, L);
|
|
||||||
mux.cost += find_best_cover(tree, M);
|
|
||||||
mux.cost += find_best_cover(tree, N);
|
|
||||||
mux.cost += find_best_cover(tree, O);
|
|
||||||
mux.cost += find_best_cover(tree, P);
|
|
||||||
|
|
||||||
if (best_mux.cost > mux.cost)
|
mux.cost += cost_mux16;
|
||||||
|
mux.cost += sum_best_covers(tree, mux.inputs);
|
||||||
|
|
||||||
|
log_debug(" Cost of mux16 at %s: %d\n", log_signal(bit), mux.cost);
|
||||||
|
|
||||||
|
if (best_mux.cost >= mux.cost)
|
||||||
best_mux = mux;
|
best_mux = mux;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,6 +588,7 @@ struct MuxcoverWorker
|
||||||
void treecover(tree_t &tree)
|
void treecover(tree_t &tree)
|
||||||
{
|
{
|
||||||
int count_muxes_by_type[4] = {0, 0, 0, 0};
|
int count_muxes_by_type[4] = {0, 0, 0, 0};
|
||||||
|
log_debug(" Searching for best cover for tree at %s.\n", log_signal(tree.root));
|
||||||
find_best_cover(tree, tree.root);
|
find_best_cover(tree, tree.root);
|
||||||
implement_best_cover(tree, tree.root, count_muxes_by_type);
|
implement_best_cover(tree, tree.root, count_muxes_by_type);
|
||||||
log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root),
|
log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root),
|
||||||
|
@ -553,12 +605,13 @@ struct MuxcoverWorker
|
||||||
|
|
||||||
log(" Covering trees:\n");
|
log(" Covering trees:\n");
|
||||||
|
|
||||||
// pre-fill cache of decoder muxes
|
if (!nodecode) {
|
||||||
if (!nodecode)
|
log_debug(" Populating cache of decoder muxes.\n");
|
||||||
for (auto &tree : tree_list) {
|
for (auto &tree : tree_list) {
|
||||||
find_best_cover(tree, tree.root);
|
find_best_cover(tree, tree.root);
|
||||||
tree.newmuxes.clear();
|
tree.newmuxes.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &tree : tree_list)
|
for (auto &tree : tree_list)
|
||||||
treecover(tree);
|
treecover(tree);
|
||||||
|
@ -584,11 +637,19 @@ struct MuxcoverPass : public Pass {
|
||||||
log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
|
log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
|
||||||
log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
|
log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -dmux=cost\n");
|
||||||
|
log(" Use the specified cost for $_MUX_ cells used in decoders.\n");
|
||||||
|
log(" Default cost: %d\n", COST_DMUX);
|
||||||
|
log("\n");
|
||||||
log(" -nodecode\n");
|
log(" -nodecode\n");
|
||||||
log(" Do not insert decoder logic. This reduces the number of possible\n");
|
log(" Do not insert decoder logic. This reduces the number of possible\n");
|
||||||
log(" substitutions, but guarantees that the resulting circuit is not\n");
|
log(" substitutions, but guarantees that the resulting circuit is not\n");
|
||||||
log(" less efficient than the original circuit.\n");
|
log(" less efficient than the original circuit.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -nopartial\n");
|
||||||
|
log(" Do not consider mappings that use $_MUX<N>_ to select from less\n");
|
||||||
|
log(" than <N> different signals.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -598,6 +659,8 @@ struct MuxcoverPass : public Pass {
|
||||||
bool use_mux8 = false;
|
bool use_mux8 = false;
|
||||||
bool use_mux16 = false;
|
bool use_mux16 = false;
|
||||||
bool nodecode = false;
|
bool nodecode = false;
|
||||||
|
bool nopartial = false;
|
||||||
|
int cost_dmux = COST_DMUX;
|
||||||
int cost_mux4 = COST_MUX4;
|
int cost_mux4 = COST_MUX4;
|
||||||
int cost_mux8 = COST_MUX8;
|
int cost_mux8 = COST_MUX8;
|
||||||
int cost_mux16 = COST_MUX16;
|
int cost_mux16 = COST_MUX16;
|
||||||
|
@ -610,7 +673,7 @@ struct MuxcoverPass : public Pass {
|
||||||
use_mux4 = true;
|
use_mux4 = true;
|
||||||
if (arg.size() > 5) {
|
if (arg.size() > 5) {
|
||||||
if (arg[5] != '=') break;
|
if (arg[5] != '=') break;
|
||||||
cost_mux4 = atoi(arg.substr(5).c_str());
|
cost_mux4 = atoi(arg.substr(6).c_str());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -618,7 +681,7 @@ struct MuxcoverPass : public Pass {
|
||||||
use_mux8 = true;
|
use_mux8 = true;
|
||||||
if (arg.size() > 5) {
|
if (arg.size() > 5) {
|
||||||
if (arg[5] != '=') break;
|
if (arg[5] != '=') break;
|
||||||
cost_mux8 = atoi(arg.substr(5).c_str());
|
cost_mux8 = atoi(arg.substr(6).c_str());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -626,14 +689,22 @@ struct MuxcoverPass : public Pass {
|
||||||
use_mux16 = true;
|
use_mux16 = true;
|
||||||
if (arg.size() > 6) {
|
if (arg.size() > 6) {
|
||||||
if (arg[6] != '=') break;
|
if (arg[6] != '=') break;
|
||||||
cost_mux16 = atoi(arg.substr(6).c_str());
|
cost_mux16 = atoi(arg.substr(7).c_str());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") {
|
||||||
|
cost_dmux = atoi(arg.substr(6).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-nodecode") {
|
if (arg == "-nodecode") {
|
||||||
nodecode = true;
|
nodecode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-nopartial") {
|
||||||
|
nopartial = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -650,10 +721,12 @@ struct MuxcoverPass : public Pass {
|
||||||
worker.use_mux4 = use_mux4;
|
worker.use_mux4 = use_mux4;
|
||||||
worker.use_mux8 = use_mux8;
|
worker.use_mux8 = use_mux8;
|
||||||
worker.use_mux16 = use_mux16;
|
worker.use_mux16 = use_mux16;
|
||||||
|
worker.cost_dmux = cost_dmux;
|
||||||
worker.cost_mux4 = cost_mux4;
|
worker.cost_mux4 = cost_mux4;
|
||||||
worker.cost_mux8 = cost_mux8;
|
worker.cost_mux8 = cost_mux8;
|
||||||
worker.cost_mux16 = cost_mux16;
|
worker.cost_mux16 = cost_mux16;
|
||||||
worker.nodecode = nodecode;
|
worker.nodecode = nodecode;
|
||||||
|
worker.nopartial = nopartial;
|
||||||
worker.run();
|
worker.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,10 +293,22 @@ struct ShregmapWorker
|
||||||
|
|
||||||
if (opts.init || sigbit_init.count(q_bit) == 0)
|
if (opts.init || sigbit_init.count(q_bit) == 0)
|
||||||
{
|
{
|
||||||
if (sigbit_chain_next.count(d_bit)) {
|
auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell));
|
||||||
|
if (!r.second) {
|
||||||
|
// Insertion not successful means that d_bit is already
|
||||||
|
// connected to another register, thus mark it as a
|
||||||
|
// non chain user ...
|
||||||
sigbit_with_non_chain_users.insert(d_bit);
|
sigbit_with_non_chain_users.insert(d_bit);
|
||||||
} else
|
// ... and clone d_bit into another wire, and use that
|
||||||
sigbit_chain_next[d_bit] = cell;
|
// wire as a different key in the d_bit-to-cell dictionary
|
||||||
|
// so that it can be identified as another chain
|
||||||
|
// (omitting this common flop)
|
||||||
|
// Link: https://github.com/YosysHQ/yosys/pull/1085
|
||||||
|
Wire *wire = module->addWire(NEW_ID);
|
||||||
|
module->connect(wire, d_bit);
|
||||||
|
sigmap.add(wire, d_bit);
|
||||||
|
sigbit_chain_next.insert(std::make_pair(wire, cell));
|
||||||
|
}
|
||||||
|
|
||||||
sigbit_chain_prev[q_bit] = cell;
|
sigbit_chain_prev[q_bit] = cell;
|
||||||
continue;
|
continue;
|
||||||
|
@ -605,9 +617,11 @@ struct ShregmapPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -tech greenpak4\n");
|
log(" -tech greenpak4\n");
|
||||||
log(" map to greenpak4 shift registers.\n");
|
log(" map to greenpak4 shift registers.\n");
|
||||||
|
log(" this option also implies -clkpol pos -zinit\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -tech xilinx\n");
|
log(" -tech xilinx\n");
|
||||||
log(" map to xilinx dynamic-length shift registers.\n");
|
log(" map to xilinx dynamic-length shift registers.\n");
|
||||||
|
log(" this option also implies -params -init\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
|
|
@ -13,6 +13,7 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
|
||||||
|
|
||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))
|
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))
|
||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut))
|
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut))
|
||||||
|
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut))
|
||||||
|
|
||||||
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
|
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
|
||||||
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
|
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Box 1 : CCU2C (2xCARRY + 2xLUT4)
|
# Box 1 : CCU2C (2xCARRY + 2xLUT4)
|
||||||
# Outputs: S0, S1, COUT
|
# Outputs: S0, S1, COUT
|
||||||
|
# (NB: carry chain input/output must be last
|
||||||
|
# input/output and bus has been moved
|
||||||
|
# there overriding the otherwise
|
||||||
|
# alphabetical ordering)
|
||||||
# name ID w/b ins outs
|
# name ID w/b ins outs
|
||||||
CCU2C 1 1 9 3
|
CCU2C 1 1 9 3
|
||||||
|
|
||||||
|
@ -9,7 +16,7 @@ CCU2C 1 1 9 3
|
||||||
516 516 516 516 412 412 278 278 43
|
516 516 516 516 412 412 278 278 43
|
||||||
|
|
||||||
# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram)
|
# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram)
|
||||||
# Outputs: DO0, DO1, DO2, DO3, DO4
|
# Outputs: DO0, DO1, DO2, DO3
|
||||||
# name ID w/b ins outs
|
# name ID w/b ins outs
|
||||||
TRELLIS_DPR16X4 2 0 14 4
|
TRELLIS_DPR16X4 2 0 14 4
|
||||||
|
|
||||||
|
|
12
techlibs/ecp5/abc_5g_nowide.lut
Normal file
12
techlibs/ecp5/abc_5g_nowide.lut
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# ECP5-5G LUT library for ABC
|
||||||
|
# Note that ECP5 architecture assigns difference
|
||||||
|
# in LUT input delay to interconnect, so this is
|
||||||
|
# considered too
|
||||||
|
|
||||||
|
|
||||||
|
# Simple LUTs
|
||||||
|
# area D C B A
|
||||||
|
1 1 141
|
||||||
|
2 1 141 275
|
||||||
|
3 1 141 275 379
|
||||||
|
4 1 141 275 379 379
|
|
@ -50,20 +50,21 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
|
||||||
|
|
||||||
wire [Y_WIDTH2-1:0] AA = A_buf;
|
wire [Y_WIDTH2-1:0] AA = A_buf;
|
||||||
wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
|
wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
|
||||||
|
wire [Y_WIDTH2-1:0] BX = B_buf;
|
||||||
wire [Y_WIDTH2-1:0] C = {CO, CI};
|
wire [Y_WIDTH2-1:0] C = {CO, CI};
|
||||||
wire [Y_WIDTH2-1:0] FCO, Y1;
|
wire [Y_WIDTH2-1:0] FCO, Y1;
|
||||||
|
|
||||||
genvar i;
|
genvar i;
|
||||||
generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
|
generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
|
||||||
CCU2C #(
|
CCU2C #(
|
||||||
.INIT0(16'b0110011010101010),
|
.INIT0(16'b1001011010101010),
|
||||||
.INIT1(16'b0110011010101010),
|
.INIT1(16'b1001011010101010),
|
||||||
.INJECT1_0("NO"),
|
.INJECT1_0("NO"),
|
||||||
.INJECT1_1("NO")
|
.INJECT1_1("NO")
|
||||||
) ccu2c_i (
|
) ccu2c_i (
|
||||||
.CIN(C[i]),
|
.CIN(C[i]),
|
||||||
.A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1),
|
.A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1),
|
||||||
.A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1),
|
.A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1),
|
||||||
.S0(Y[i]), .S1(Y1[i]),
|
.S0(Y[i]), .S1(Y1[i]),
|
||||||
.COUT(FCO[i])
|
.COUT(FCO[i])
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,6 +47,28 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
|
||||||
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
||||||
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
// TODO: Diamond flip-flops
|
||||||
|
// module FD1P3AX(); endmodule
|
||||||
|
// module FD1P3AY(); endmodule
|
||||||
|
// module FD1P3BX(); endmodule
|
||||||
|
// module FD1P3DX(); endmodule
|
||||||
|
// module FD1P3IX(); endmodule
|
||||||
|
// module FD1P3JX(); endmodule
|
||||||
|
// module FD1S3AX(); endmodule
|
||||||
|
// module FD1S3AY(); endmodule
|
||||||
|
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
|
// module FL1P3AY(); endmodule
|
||||||
|
// module FL1P3AZ(); endmodule
|
||||||
|
// module FL1P3BX(); endmodule
|
||||||
|
// module FL1P3DX(); endmodule
|
||||||
|
// module FL1P3IY(); endmodule
|
||||||
|
// module FL1P3JY(); endmodule
|
||||||
|
// module FL1S3AX(); endmodule
|
||||||
|
// module FL1S3AY(); endmodule
|
||||||
|
|
||||||
// Diamond I/O buffers
|
// Diamond I/O buffers
|
||||||
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||||
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||||
|
@ -62,14 +84,30 @@ module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(
|
||||||
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
|
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
|
||||||
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
|
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
|
||||||
|
|
||||||
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
|
// Diamond I/O registers
|
||||||
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
// TODO: Diamond I/O latches
|
||||||
|
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
|
||||||
|
|
||||||
`ifndef NO_LUT
|
`ifndef NO_LUT
|
||||||
module \$lut (A, Y);
|
module \$lut (A, Y);
|
||||||
parameter WIDTH = 0;
|
parameter WIDTH = 0;
|
||||||
parameter LUT = 0;
|
parameter LUT = 0;
|
||||||
|
|
||||||
|
input [WIDTH-1:0] A;
|
||||||
|
output Y;
|
||||||
|
|
||||||
// Need to swap input ordering, and fix init accordingly,
|
// Need to swap input ordering, and fix init accordingly,
|
||||||
// to match ABC's expectation of LUT inputs in non-decreasing
|
// to match ABC's expectation of LUT inputs in non-decreasing
|
||||||
|
@ -86,19 +124,15 @@ module \$lut (A, Y);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function [2**P_WIDTH-1:0] permute_init;
|
function [2**P_WIDTH-1:0] permute_init;
|
||||||
input [2**P_WIDTH-1:0] orig;
|
|
||||||
integer i;
|
integer i;
|
||||||
begin
|
begin
|
||||||
permute_init = 0;
|
permute_init = 0;
|
||||||
for (i = 0; i < 2**P_WIDTH; i = i + 1)
|
for (i = 0; i < 2**P_WIDTH; i = i + 1)
|
||||||
permute_init[i] = orig[permute_index(i)];
|
permute_init[i] = LUT[permute_index(i)];
|
||||||
end
|
end
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
parameter [2**P_WIDTH-1:0] P_LUT = permute_init(LUT);
|
parameter [2**P_WIDTH-1:0] P_LUT = permute_init();
|
||||||
|
|
||||||
input [WIDTH-1:0] A;
|
|
||||||
output Y;
|
|
||||||
|
|
||||||
generate
|
generate
|
||||||
if (WIDTH == 1) begin
|
if (WIDTH == 1) begin
|
||||||
|
|
|
@ -15,11 +15,9 @@ module L6MUX21 (input D0, D1, SD, output Z);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
(* abc_box_id=1, abc_carry, lib_whitebox *)
|
(* abc_box_id=1, abc_carry="CIN,COUT", lib_whitebox *)
|
||||||
module CCU2C((* abc_carry_in *) input CIN,
|
module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
|
||||||
input A0, B0, C0, D0, A1, B1, C1, D1,
|
output S0, S1, COUT);
|
||||||
output S0, S1,
|
|
||||||
(* abc_carry_out *) 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;
|
||||||
|
@ -106,7 +104,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
//(* abc_box_id=2 *)
|
//(* abc_box_id=2, abc_scc_break="DI,WAD,WRE" *)
|
||||||
module TRELLIS_DPR16X4 (
|
module TRELLIS_DPR16X4 (
|
||||||
input [3:0] DI,
|
input [3:0] DI,
|
||||||
input [3:0] WAD,
|
input [3:0] WAD,
|
||||||
|
@ -260,18 +258,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
|
||||||
endgenerate
|
endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// ---------------------------------------
|
|
||||||
|
|
||||||
module OBZ(input I, T, output O);
|
|
||||||
assign O = T ? 1'bz : I;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// ---------------------------------------
|
|
||||||
|
|
||||||
module IB(input I, output O);
|
|
||||||
assign O = I;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
(* keep *)
|
(* keep *)
|
||||||
module TRELLIS_IO(
|
module TRELLIS_IO(
|
||||||
|
@ -303,19 +289,6 @@ endmodule
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
module OB(input I, output O);
|
|
||||||
assign O = I;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// ---------------------------------------
|
|
||||||
|
|
||||||
module BB(input I, T, output O, inout B);
|
|
||||||
assign B = T ? 1'bz : I;
|
|
||||||
assign O = B;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// ---------------------------------------
|
|
||||||
|
|
||||||
module INV(input A, output Z);
|
module INV(input A, output Z);
|
||||||
assign Z = !A;
|
assign Z = !A;
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -568,19 +541,56 @@ module DP16KD(
|
||||||
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
|
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
|
// TODO: Diamond flip-flops
|
||||||
module FD1S3BX(input PD, D, CK, output Q);
|
// module FD1P3AX(); endmodule
|
||||||
TRELLIS_FF #(
|
// module FD1P3AY(); endmodule
|
||||||
.GSR("DISABLED"),
|
// module FD1P3BX(); endmodule
|
||||||
.CEMUX("1"),
|
// module FD1P3DX(); endmodule
|
||||||
.CLKMUX("CLK"),
|
// module FD1P3IX(); endmodule
|
||||||
.LSRMUX("LSR"),
|
// module FD1P3JX(); endmodule
|
||||||
.REGSET("SET"),
|
// module FD1S3AX(); endmodule
|
||||||
.SRMODE("ASYNC")
|
// module FD1S3AY(); endmodule
|
||||||
) tff_i (
|
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
.CLK(CK),
|
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
.LSR(PD),
|
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
.DI(D),
|
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
.Q(Q)
|
// module FL1P3AY(); endmodule
|
||||||
);
|
// module FL1P3AZ(); endmodule
|
||||||
endmodule
|
// module FL1P3BX(); endmodule
|
||||||
|
// module FL1P3DX(); endmodule
|
||||||
|
// module FL1P3IY(); endmodule
|
||||||
|
// module FL1P3JY(); endmodule
|
||||||
|
// module FL1S3AX(); endmodule
|
||||||
|
// module FL1S3AY(); endmodule
|
||||||
|
|
||||||
|
// Diamond I/O buffers
|
||||||
|
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
||||||
|
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
||||||
|
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
||||||
|
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
|
||||||
|
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
|
||||||
|
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
|
||||||
|
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
|
||||||
|
|
||||||
|
// Diamond I/O registers
|
||||||
|
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
// TODO: Diamond I/O latches
|
||||||
|
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
|
||||||
|
|
|
@ -76,7 +76,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
log(" -nodram\n");
|
log(" -nodram\n");
|
||||||
log(" do not use distributed RAM cells in output netlist\n");
|
log(" do not use distributed RAM cells in output netlist\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -nomux\n");
|
log(" -nowidelut\n");
|
||||||
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -abc2\n");
|
log(" -abc2\n");
|
||||||
|
@ -96,7 +96,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
string top_opt, blif_file, edif_file, json_file;
|
string top_opt, blif_file, edif_file, json_file;
|
||||||
bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, abc9, vpr;
|
bool noccu2, nodffe, nobram, nodram, nowidelut, flatten, retime, abc2, abc9, vpr;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
nodffe = false;
|
nodffe = false;
|
||||||
nobram = false;
|
nobram = false;
|
||||||
nodram = false;
|
nodram = false;
|
||||||
nomux = false;
|
nowidelut = false;
|
||||||
flatten = true;
|
flatten = true;
|
||||||
retime = false;
|
retime = false;
|
||||||
abc2 = false;
|
abc2 = false;
|
||||||
|
@ -176,8 +176,8 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
nodram = true;
|
nodram = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-nomux") {
|
if (args[argidx] == "-nowidelut" || args[argidx] == "-nomux") {
|
||||||
nomux = true;
|
nowidelut = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-abc2") {
|
if (args[argidx] == "-abc2") {
|
||||||
|
@ -273,14 +273,16 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
}
|
}
|
||||||
run("techmap -map +/ecp5/latches_map.v");
|
run("techmap -map +/ecp5/latches_map.v");
|
||||||
if (abc9) {
|
if (abc9) {
|
||||||
run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200");
|
if (nowidelut)
|
||||||
|
run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200");
|
||||||
|
else
|
||||||
|
run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200");
|
||||||
} else {
|
} else {
|
||||||
if (nomux)
|
if (nowidelut)
|
||||||
run("abc -lut 4 -dress");
|
run("abc -lut 4 -dress");
|
||||||
else
|
else
|
||||||
run("abc -lut 4:7 -dress");
|
run("abc -lut 4:7 -dress");
|
||||||
}
|
}
|
||||||
|
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,113 +1,17 @@
|
||||||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
|
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
|
||||||
|
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Inputs: C D
|
# Inputs: I0 I1 CI
|
||||||
# Outputs: Q
|
|
||||||
SB_DFF 1 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFE 2 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSR 3 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFR 4 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSS 5 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFS 6 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESR 7 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFER 8 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESS 9 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFES 10 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFN 11 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNE 12 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSR 13 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNR 14 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSS 15 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNS 16 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESR 17 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNER 18 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESS 19 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNES 20 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: CI I0 I1
|
|
||||||
# Outputs: CO
|
# Outputs: CO
|
||||||
SB_CARRY 21 1 3 1
|
# (NB: carry chain input/output must be last
|
||||||
126 259 231
|
# input/output and have been moved there
|
||||||
|
# overriding the alphabetical ordering)
|
||||||
|
SB_CARRY 1 1 3 1
|
||||||
|
259 231 126
|
||||||
|
|
||||||
# Inputs: I0 I1 I2 I3
|
# Inputs: I0 I1 I2 I3
|
||||||
# Outputs: O
|
# Outputs: O
|
||||||
SB_LUT4 22 1 4 1
|
SB_LUT4 2 1 4 1
|
||||||
449 400 379 316
|
449 400 379 316
|
||||||
|
|
|
@ -1,113 +1,17 @@
|
||||||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
|
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
|
||||||
|
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
|
# (with exceptions for carry in/out)
|
||||||
# Inputs: C D
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFF 1 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFE 2 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSR 3 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFR 4 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSS 5 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFS 6 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESR 7 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFER 8 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESS 9 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFES 10 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFN 11 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNE 12 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSR 13 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNR 14 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSS 15 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNS 16 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESR 17 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNER 18 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESS 19 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNES 20 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: CI I0 I1
|
# Inputs: CI I0 I1
|
||||||
# Outputs: CO
|
# Outputs: CO
|
||||||
SB_CARRY 21 1 3 1
|
# (NB: carry chain input/output must be last
|
||||||
186 675 609
|
# input/output and have been moved there
|
||||||
|
# overriding the alphabetical ordering)
|
||||||
|
SB_CARRY 1 1 3 1
|
||||||
|
675 609 186
|
||||||
|
|
||||||
# Inputs: I0 I1 I2 I3
|
# Inputs: I0 I1 I2 I3
|
||||||
# Outputs: O
|
# Outputs: O
|
||||||
SB_LUT4 22 1 4 1
|
SB_LUT4 2 1 4 1
|
||||||
661 589 558 465
|
661 589 558 465
|
||||||
|
|
|
@ -1,113 +1,17 @@
|
||||||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
|
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
|
||||||
|
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Inputs: C D
|
# Inputs: I0 I1 CI
|
||||||
# Outputs: Q
|
|
||||||
SB_DFF 1 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFE 2 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSR 3 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFR 4 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFSS 5 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFS 6 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESR 7 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFER 8 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFESS 9 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFES 10 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFN 11 0 2 1
|
|
||||||
- -
|
|
||||||
|
|
||||||
# Inputs: C D E
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNE 12 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSR 13 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNR 14 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNSS 15 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNS 16 0 3 1
|
|
||||||
- - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESR 17 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E R
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNER 18 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNESS 19 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: C D E S
|
|
||||||
# Outputs: Q
|
|
||||||
SB_DFFNES 20 0 4 1
|
|
||||||
- - - -
|
|
||||||
|
|
||||||
# Inputs: CI I0 I1
|
|
||||||
# Outputs: CO
|
# Outputs: CO
|
||||||
SB_CARRY 21 1 3 1
|
# (NB: carry chain input/output must be last
|
||||||
278 675 609
|
# input/output and have been moved there
|
||||||
|
# overriding the alphabetical ordering)
|
||||||
|
SB_CARRY 1 1 3 1
|
||||||
|
675 609 278
|
||||||
|
|
||||||
# Inputs: I0 I1 I2 I3
|
# Inputs: I0 I1 I2 I3
|
||||||
# Outputs: O
|
# Outputs: O
|
||||||
SB_LUT4 22 1 4 1
|
SB_LUT4 2 1 4 1
|
||||||
1285 1231 1205 874
|
1285 1231 1205 874
|
||||||
|
|
|
@ -127,7 +127,7 @@ endmodule
|
||||||
|
|
||||||
// SiliconBlue Logic Cells
|
// SiliconBlue Logic Cells
|
||||||
|
|
||||||
(* abc_box_id = 22, lib_whitebox *)
|
(* abc_box_id = 2, lib_whitebox *)
|
||||||
module SB_LUT4 (output O, input I0, I1, I2, I3);
|
module SB_LUT4 (output O, input I0, I1, I2, I3);
|
||||||
parameter [15:0] LUT_INIT = 0;
|
parameter [15:0] LUT_INIT = 0;
|
||||||
wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
|
wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
|
||||||
|
@ -136,20 +136,16 @@ module SB_LUT4 (output O, input I0, I1, I2, I3);
|
||||||
assign O = I0 ? s1[1] : s1[0];
|
assign O = I0 ? s1[1] : s1[0];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
(* abc_box_id = 21, abc_carry, lib_whitebox *)
|
(* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *)
|
||||||
module SB_CARRY ((* abc_carry_out *) output CO, input I0, I1, (* abc_carry_in *) input CI);
|
module SB_CARRY (output CO, input I0, I1, CI);
|
||||||
assign CO = (I0 && I1) || ((I0 || I1) && CI);
|
assign CO = (I0 && I1) || ((I0 || I1) && CI);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// Positive Edge SiliconBlue FF Cells
|
// Positive Edge SiliconBlue FF Cells
|
||||||
|
|
||||||
module SB_DFF (output `SB_DFF_REG, input C, D);
|
module SB_DFF (output `SB_DFF_REG, input C, D);
|
||||||
`ifndef _ABC
|
|
||||||
always @(posedge C)
|
always @(posedge C)
|
||||||
Q <= D;
|
Q <= D;
|
||||||
`else
|
|
||||||
always @* Q <= D;
|
|
||||||
`endif
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module SB_DFFE (output `SB_DFF_REG, input C, E, D);
|
module SB_DFFE (output `SB_DFF_REG, input C, E, D);
|
||||||
|
@ -896,7 +892,6 @@ module SB_WARMBOOT (
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
(* nomem2reg *)
|
|
||||||
module SB_SPRAM256KA (
|
module SB_SPRAM256KA (
|
||||||
input [13:0] ADDRESS,
|
input [13:0] ADDRESS,
|
||||||
input [15:0] DATAIN,
|
input [15:0] DATAIN,
|
||||||
|
|
|
@ -74,7 +74,7 @@ static void run_ice40_unlut(Module *module)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Ice40UnlutPass : public Pass {
|
struct Ice40UnlutPass : public Pass {
|
||||||
Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: perform simple optimizations") { }
|
Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: transform SB_LUT4 cells to $lut cells") { }
|
||||||
void help() YS_OVERRIDE
|
void help() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
|
|
@ -38,8 +38,8 @@ struct SynthIce40Pass : public ScriptPass
|
||||||
log("This command runs synthesis for iCE40 FPGAs.\n");
|
log("This command runs synthesis for iCE40 FPGAs.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -device < hx | lp | u >\n");
|
log(" -device < hx | lp | u >\n");
|
||||||
log(" optimise the synthesis netlist for the specified device.\n");
|
log(" relevant only for '-abc9' flow, optimise timing for the specified device.\n");
|
||||||
log(" HX is the default target if no device argument specified.\n");
|
log(" default: hx\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -top <module>\n");
|
log(" -top <module>\n");
|
||||||
log(" use the specified module as top module\n");
|
log(" use the specified module as top module\n");
|
||||||
|
@ -105,7 +105,6 @@ struct SynthIce40Pass : public ScriptPass
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string top_opt, blif_file, edif_file, json_file, abc, device_opt;
|
string top_opt, blif_file, edif_file, json_file, abc, device_opt;
|
||||||
bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
|
bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
|
||||||
int min_ce_use;
|
int min_ce_use;
|
||||||
|
@ -331,8 +330,16 @@ struct SynthIce40Pass : public ScriptPass
|
||||||
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
|
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
|
||||||
}
|
}
|
||||||
if (!noabc) {
|
if (!noabc) {
|
||||||
if (abc == "abc9")
|
if (abc == "abc9") {
|
||||||
run(abc + stringf(" -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
|
int wire_delay;
|
||||||
|
if (device_opt == "lp")
|
||||||
|
wire_delay = 400;
|
||||||
|
else if (device_opt == "u")
|
||||||
|
wire_delay = 750;
|
||||||
|
else
|
||||||
|
wire_delay = 250;
|
||||||
|
run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
run(abc + " -dress -lut 4", "(skip if -noabc)");
|
run(abc + " -dress -lut 4", "(skip if -noabc)");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,11 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
|
||||||
|
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_ff.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_ff.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
|
||||||
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7_nowide.lut))
|
||||||
|
|
||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
|
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
|
||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
|
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
|
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
|
||||||
|
|
||||||
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# F7BMUX slower than F7AMUX
|
# F7BMUX slower than F7AMUX
|
||||||
# Inputs: I0 I1 S0
|
# Inputs: I0 I1 S0
|
||||||
# Outputs: O
|
# Outputs: O
|
||||||
|
@ -12,34 +15,42 @@ MUXF8 2 1 3 1
|
||||||
104 94 273
|
104 94 273
|
||||||
|
|
||||||
# CARRY4 + CARRY4_[ABCD]X
|
# CARRY4 + CARRY4_[ABCD]X
|
||||||
# Inputs: S0 S1 S2 S3 CYINIT DI0 DI1 DI2 DI3 CI
|
# Inputs: CYINIT DI0 DI1 DI2 DI3 S0 S1 S2 S3 CI
|
||||||
# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3
|
# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3
|
||||||
# (NB: carry chain input/output must be last input/output,
|
# (NB: carry chain input/output must be last
|
||||||
# swapped with what normally would have been the last
|
# input/output and the entire bus has been
|
||||||
# output, here: CI <-> S, CO <-> O
|
# moved there overriding the otherwise
|
||||||
|
# alphabetical ordering)
|
||||||
CARRY4 3 1 10 8
|
CARRY4 3 1 10 8
|
||||||
223 - - - 482 - - - - 222
|
482 - - - - 223 - - - 222
|
||||||
400 205 - - 598 407 - - - 334
|
598 407 - - - 400 205 - - 334
|
||||||
523 558 226 - 584 556 537 - - 239
|
584 556 537 - - 523 558 226 - 239
|
||||||
582 618 330 227 642 615 596 438 - 313
|
642 615 596 438 - 582 618 330 227 313
|
||||||
340 - - - 536 379 - - - 271
|
536 379 - - - 340 - - - 271
|
||||||
433 469 - - 494 465 445 - - 157
|
494 465 445 - - 433 469 - - 157
|
||||||
512 548 292 - 592 540 520 356 - 228
|
592 540 520 356 - 512 548 292 - 228
|
||||||
508 528 378 380 580 526 507 398 385 114
|
580 526 507 398 385 508 528 378 380 114
|
||||||
|
|
||||||
|
# SLICEM/A6LUT
|
||||||
|
# Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE
|
||||||
|
# Outputs: DPO SPO
|
||||||
|
RAM32X1D 4 0 13 2
|
||||||
|
- - - - - - 631 472 407 238 127 - -
|
||||||
|
631 472 407 238 127 - - - - - - - -
|
||||||
|
|
||||||
# SLICEM/A6LUT
|
# SLICEM/A6LUT
|
||||||
# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
|
# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
|
||||||
# Outputs: DPO SPO
|
# Outputs: DPO SPO
|
||||||
RAM64X1D 4 0 15 2
|
RAM64X1D 5 0 15 2
|
||||||
- - - - - - - 124 124 124 124 124 124 - -
|
- - - - - - - 642 631 472 407 238 127 - -
|
||||||
124 124 124 124 124 124 - - - - - - 124 - -
|
642 631 472 407 238 127 - - - - - - - - -
|
||||||
|
|
||||||
# SLICEM/A6LUT + F7[AB]MUX
|
# SLICEM/A6LUT + F7[AB]MUX
|
||||||
# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
|
# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
|
||||||
# Outputs: DPO SPO
|
# Outputs: DPO SPO
|
||||||
RAM128X1D 5 0 17 2
|
RAM128X1D 6 0 17 2
|
||||||
- - - - - - - - 314 314 314 314 314 314 292 - -
|
- - - - - - - - 1009 998 839 774 605 494 450 - -
|
||||||
347 347 347 347 347 347 296 - - - - - - - - - -
|
1047 1036 877 812 643 532 478 - - - - - - - - - -
|
||||||
|
|
||||||
# Inputs: C CE D R \$pastQ
|
# Inputs: C CE D R \$pastQ
|
||||||
# Outputs: Q
|
# Outputs: Q
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
4 3 127 238 407 472
|
4 3 127 238 407 472
|
||||||
5 3 127 238 407 472 631
|
5 3 127 238 407 472 631
|
||||||
6 5 127 238 407 472 631 642
|
6 5 127 238 407 472 631 642
|
||||||
# F7AMUX.S+F7BMUX.S + AOUTMUX+COUTMUX / 2
|
# (F7[AB]MUX.S + [AC]OUTMUX) / 2
|
||||||
7 10 464 513 624 793 858 1017 1028
|
7 10 464 513 624 793 858 1017 1028
|
||||||
# F8MUX.S+BOUTMUX
|
# F8MUX.S+BOUTMUX
|
||||||
# F8MUX.I0+F7MUX.S+BOUTMUX
|
# F8MUX.I0+F7MUX.S+BOUTMUX
|
||||||
|
|
10
techlibs/xilinx/abc_xc7_nowide.lut
Normal file
10
techlibs/xilinx/abc_xc7_nowide.lut
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf
|
||||||
|
# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json
|
||||||
|
|
||||||
|
# K area delay
|
||||||
|
1 1 127
|
||||||
|
2 2 127 238
|
||||||
|
3 3 127 238 407
|
||||||
|
4 3 127 238 407 472
|
||||||
|
5 3 127 238 407 472 631
|
||||||
|
6 5 127 238 407 472 631 642
|
|
@ -20,16 +20,14 @@
|
||||||
|
|
||||||
// Convert negative-polarity reset to positive-polarity
|
// Convert negative-polarity reset to positive-polarity
|
||||||
(* techmap_celltype = "$_DFF_NN0_" *)
|
(* techmap_celltype = "$_DFF_NN0_" *)
|
||||||
module _90_dff_nn0_to_np0(input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
(* techmap_celltype = "$_DFF_PN0_" *)
|
(* techmap_celltype = "$_DFF_PN0_" *)
|
||||||
module _90_dff_pn0_to_pp0(input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
|
||||||
(* techmap_celltype = "$_DFF_NN1_" *)
|
(* techmap_celltype = "$_DFF_NN1_" *)
|
||||||
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
(* techmap_celltype = "$_DFF_PN1_" *)
|
(* techmap_celltype = "$_DFF_PN1_" *)
|
||||||
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
|
||||||
|
|
||||||
module \$__SHREG_ (input C, input D, input E, output Q);
|
module \$__SHREG_ (input C, input D, input E, output Q);
|
||||||
parameter DEPTH = 0;
|
parameter DEPTH = 0;
|
||||||
parameter [DEPTH-1:0] INIT = 0;
|
parameter [DEPTH-1:0] INIT = 0;
|
||||||
|
|
|
@ -173,8 +173,8 @@ module XORCY(output O, input CI, LI);
|
||||||
assign O = CI ^ LI;
|
assign O = CI ^ LI;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
(* abc_box_id = 3, abc_carry, lib_whitebox *)
|
(* abc_box_id = 3, abc_carry="CI,CO", lib_whitebox *)
|
||||||
module CARRY4((* abc_carry_out *) output [3:0] CO, output [3:0] O, (* abc_carry_in *) input CI, input CYINIT, input [3:0] DI, S);
|
module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
|
||||||
assign O = S ^ {CO[2:0], CI | CYINIT};
|
assign O = S ^ {CO[2:0], CI | CYINIT};
|
||||||
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
|
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
|
||||||
assign CO[1] = S[1] ? CO[0] : DI[1];
|
assign CO[1] = S[1] ? CO[0] : DI[1];
|
||||||
|
@ -281,7 +281,25 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE);
|
||||||
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
|
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
//(* abc_box_id = 4 /*, lib_whitebox*/ *)
|
(* abc_box_id = 4, abc_scc_break="D,WE" *)
|
||||||
|
module RAM32X1D (
|
||||||
|
output DPO, SPO,
|
||||||
|
input D, WCLK, WE,
|
||||||
|
input A0, A1, A2, A3, A4,
|
||||||
|
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
|
||||||
|
);
|
||||||
|
parameter INIT = 32'h0;
|
||||||
|
parameter IS_WCLK_INVERTED = 1'b0;
|
||||||
|
wire [4:0] a = {A4, A3, A2, A1, A0};
|
||||||
|
wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
|
||||||
|
reg [31:0] mem = INIT;
|
||||||
|
assign SPO = mem[a];
|
||||||
|
assign DPO = mem[dpra];
|
||||||
|
wire clk = WCLK ^ IS_WCLK_INVERTED;
|
||||||
|
always @(posedge clk) if (WE) mem[a] <= D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
(* abc_box_id = 5, abc_scc_break="D,WE" *)
|
||||||
module RAM64X1D (
|
module RAM64X1D (
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D, WCLK, WE,
|
input D, WCLK, WE,
|
||||||
|
@ -299,7 +317,7 @@ module RAM64X1D (
|
||||||
always @(posedge clk) if (WE) mem[a] <= D;
|
always @(posedge clk) if (WE) mem[a] <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
//(* abc_box_id = 5 /*, lib_whitebox*/ *)
|
(* abc_box_id = 6, abc_scc_break="D,WE" *)
|
||||||
module RAM128X1D (
|
module RAM128X1D (
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D, WCLK, WE,
|
input D, WCLK, WE,
|
||||||
|
|
|
@ -120,7 +120,7 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl RAM128X1S
|
xtract_cell_decl RAM128X1S
|
||||||
xtract_cell_decl RAM256X1S
|
xtract_cell_decl RAM256X1S
|
||||||
xtract_cell_decl RAM32M
|
xtract_cell_decl RAM32M
|
||||||
xtract_cell_decl RAM32X1D
|
#xtract_cell_decl RAM32X1D
|
||||||
xtract_cell_decl RAM32X1S
|
xtract_cell_decl RAM32X1S
|
||||||
xtract_cell_decl RAM32X1S_1
|
xtract_cell_decl RAM32X1S_1
|
||||||
xtract_cell_decl RAM32X2S
|
xtract_cell_decl RAM32X2S
|
||||||
|
|
|
@ -3694,13 +3694,6 @@ module RAM32M (...);
|
||||||
input WE;
|
input WE;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM32X1D (...);
|
|
||||||
parameter [31:0] INIT = 32'h00000000;
|
|
||||||
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
|
||||||
output DPO, SPO;
|
|
||||||
input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module RAM32X1S (...);
|
module RAM32X1S (...);
|
||||||
parameter [31:0] INIT = 32'h00000000;
|
parameter [31:0] INIT = 32'h00000000;
|
||||||
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
|
||||||
|
bram $__XILINX_RAM32X1D
|
||||||
|
init 1
|
||||||
|
abits 5
|
||||||
|
dbits 1
|
||||||
|
groups 2
|
||||||
|
ports 1 1
|
||||||
|
wrmode 0 1
|
||||||
|
enable 0 1
|
||||||
|
transp 0 0
|
||||||
|
clocks 0 1
|
||||||
|
clkpol 0 2
|
||||||
|
endbram
|
||||||
|
|
||||||
bram $__XILINX_RAM64X1D
|
bram $__XILINX_RAM64X1D
|
||||||
init 1
|
init 1
|
||||||
abits 6
|
abits 6
|
||||||
|
@ -25,6 +38,13 @@ bram $__XILINX_RAM128X1D
|
||||||
clkpol 0 2
|
clkpol 0 2
|
||||||
endbram
|
endbram
|
||||||
|
|
||||||
|
match $__XILINX_RAM32X1D
|
||||||
|
min bits 3
|
||||||
|
min wports 1
|
||||||
|
make_outreg
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
match $__XILINX_RAM64X1D
|
match $__XILINX_RAM64X1D
|
||||||
min bits 5
|
min bits 5
|
||||||
min wports 1
|
min wports 1
|
||||||
|
|
|
@ -1,4 +1,38 @@
|
||||||
|
|
||||||
|
module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [31:0] INIT = 32'bx;
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [4:0] A1ADDR;
|
||||||
|
output A1DATA;
|
||||||
|
|
||||||
|
input [4:0] B1ADDR;
|
||||||
|
input B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
RAM32X1D #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.DPRA0(A1ADDR[0]),
|
||||||
|
.DPRA1(A1ADDR[1]),
|
||||||
|
.DPRA2(A1ADDR[2]),
|
||||||
|
.DPRA3(A1ADDR[3]),
|
||||||
|
.DPRA4(A1ADDR[4]),
|
||||||
|
.DPO(A1DATA),
|
||||||
|
|
||||||
|
.A0(B1ADDR[0]),
|
||||||
|
.A1(B1ADDR[1]),
|
||||||
|
.A2(B1ADDR[2]),
|
||||||
|
.A3(B1ADDR[3]),
|
||||||
|
.A4(B1ADDR[4]),
|
||||||
|
.D(B1DATA),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
parameter [63:0] INIT = 64'bx;
|
parameter [63:0] INIT = 64'bx;
|
||||||
parameter CLKPOL2 = 1;
|
parameter CLKPOL2 = 1;
|
||||||
|
|
|
@ -29,61 +29,86 @@ module \$lut (A, Y);
|
||||||
input [WIDTH-1:0] A;
|
input [WIDTH-1:0] A;
|
||||||
output Y;
|
output Y;
|
||||||
|
|
||||||
|
// Need to swap input ordering, and fix init accordingly,
|
||||||
|
// to match ABC's expectation of LUT inputs in non-decreasing
|
||||||
|
// delay order
|
||||||
|
function [WIDTH-1:0] permute_index;
|
||||||
|
input [WIDTH-1:0] i;
|
||||||
|
integer j;
|
||||||
|
begin
|
||||||
|
permute_index = 0;
|
||||||
|
for (j = 0; j < WIDTH; j = j + 1)
|
||||||
|
permute_index[WIDTH-1 - j] = i[j];
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [2**WIDTH-1:0] permute_init;
|
||||||
|
input [2**WIDTH-1:0] orig;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
permute_init = 0;
|
||||||
|
for (i = 0; i < 2**WIDTH; i = i + 1)
|
||||||
|
permute_init[i] = orig[permute_index(i)];
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT);
|
||||||
|
|
||||||
generate
|
generate
|
||||||
if (WIDTH == 1) begin
|
if (WIDTH == 1) begin
|
||||||
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]));
|
.I0(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 2) begin
|
if (WIDTH == 2) begin
|
||||||
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]), .I1(A[1]));
|
.I0(A[1]), .I1(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 3) begin
|
if (WIDTH == 3) begin
|
||||||
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]));
|
.I0(A[2]), .I1(A[1]), .I2(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 4) begin
|
if (WIDTH == 4) begin
|
||||||
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[3]), .I1(A[2]), .I2(A[1]),
|
||||||
.I3(A[3]));
|
.I3(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 5) begin
|
if (WIDTH == 5) begin
|
||||||
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[4]), .I1(A[3]), .I2(A[2]),
|
||||||
.I3(A[3]), .I4(A[4]));
|
.I3(A[1]), .I4(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 6) begin
|
if (WIDTH == 6) begin
|
||||||
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[5]), .I1(A[4]), .I2(A[3]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[2]), .I4(A[1]), .I5(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 7) begin
|
if (WIDTH == 7) begin
|
||||||
wire T0, T1;
|
wire T0, T1;
|
||||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
|
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
|
||||||
end else
|
end else
|
||||||
if (WIDTH == 8) begin
|
if (WIDTH == 8) begin
|
||||||
wire T0, T1, T2, T3, T4, T5;
|
wire T0, T1, T2, T3, T4, T5;
|
||||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||||
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
|
LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||||
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
|
LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||||
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
|
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1]));
|
||||||
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
|
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1]));
|
||||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
|
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
|
||||||
end else begin
|
end else begin
|
||||||
wire _TECHMAP_FAIL_ = 1;
|
wire _TECHMAP_FAIL_ = 1;
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,8 +45,9 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" -top <module>\n");
|
log(" -top <module>\n");
|
||||||
log(" use the specified module as top module\n");
|
log(" use the specified module as top module\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -arch {xcup|xcu|xc7|xc6s}\n");
|
log(" -family {xcup|xcu|xc7|xc6s}\n");
|
||||||
log(" run synthesis for the specified Xilinx architecture\n");
|
log(" run synthesis for the specified Xilinx architecture\n");
|
||||||
|
log(" generate the synthesis netlist for the specified family.\n");
|
||||||
log(" default: xc7\n");
|
log(" default: xc7\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -edif <file>\n");
|
log(" -edif <file>\n");
|
||||||
|
@ -61,9 +62,6 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
|
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
|
||||||
log(" (this feature is experimental and incomplete)\n");
|
log(" (this feature is experimental and incomplete)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -nocarry\n");
|
|
||||||
log(" disable inference of carry chains\n");
|
|
||||||
log("\n");
|
|
||||||
log(" -nobram\n");
|
log(" -nobram\n");
|
||||||
log(" disable inference of block rams\n");
|
log(" disable inference of block rams\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -73,6 +71,12 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" -nosrl\n");
|
log(" -nosrl\n");
|
||||||
log(" disable inference of shift registers\n");
|
log(" disable inference of shift registers\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -nocarry\n");
|
||||||
|
log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nowidelut\n");
|
||||||
|
log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
|
||||||
|
log("\n");
|
||||||
log(" -run <from_label>:<to_label>\n");
|
log(" -run <from_label>:<to_label>\n");
|
||||||
log(" only run the commands between the labels (see below). an empty\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(" from label is synonymous to 'begin', and empty to label is\n");
|
||||||
|
@ -93,15 +97,15 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string top_opt, edif_file, blif_file, abc, arch;
|
std::string top_opt, edif_file, blif_file, family;
|
||||||
bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl;
|
bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
top_opt = "-auto-top";
|
top_opt = "-auto-top";
|
||||||
edif_file.clear();
|
edif_file.clear();
|
||||||
blif_file.clear();
|
blif_file.clear();
|
||||||
abc = "abc";
|
family = "xc7";
|
||||||
flatten = false;
|
flatten = false;
|
||||||
retime = false;
|
retime = false;
|
||||||
vpr = false;
|
vpr = false;
|
||||||
|
@ -109,7 +113,9 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
nobram = false;
|
nobram = false;
|
||||||
nodram = false;
|
nodram = false;
|
||||||
nosrl = false;
|
nosrl = false;
|
||||||
arch = "xc7";
|
nocarry = false;
|
||||||
|
nowidelut = false;
|
||||||
|
abc9 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
@ -124,8 +130,8 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
top_opt = "-top " + args[++argidx];
|
top_opt = "-top " + args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
|
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
|
||||||
arch = args[++argidx];
|
family = args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
|
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
|
||||||
|
@ -152,6 +158,14 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
retime = true;
|
retime = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-nocarry") {
|
||||||
|
nocarry = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nowidelut") {
|
||||||
|
nowidelut = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-vpr") {
|
if (args[argidx] == "-vpr") {
|
||||||
vpr = true;
|
vpr = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -173,15 +187,15 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-abc9") {
|
if (args[argidx] == "-abc9") {
|
||||||
abc = "abc9";
|
abc9 = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
|
if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s")
|
||||||
log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
|
log_cmd_error("Invalid Xilinx -family setting: %s\n", family.c_str());
|
||||||
|
|
||||||
if (!design->full_selection())
|
if (!design->full_selection())
|
||||||
log_cmd_error("This command only operates on fully selected designs!\n");
|
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||||
|
@ -225,11 +239,6 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
// so attempt to convert $pmux-es to the former
|
// so attempt to convert $pmux-es to the former
|
||||||
if (!nosrl || help_mode)
|
if (!nosrl || help_mode)
|
||||||
run("pmux2shiftx", "(skip if '-nosrl')");
|
run("pmux2shiftx", "(skip if '-nosrl')");
|
||||||
|
|
||||||
// Run a number of peephole optimisations, including one
|
|
||||||
// that optimises $mul cells driving $shiftx's B input
|
|
||||||
// and that aids wide mux analysis
|
|
||||||
run("peepopt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("bram", "(skip if '-nobram')")) {
|
if (check_label("bram", "(skip if '-nobram')")) {
|
||||||
|
@ -268,7 +277,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
techmap_files += " -map +/xilinx/arith_map.v";
|
techmap_files += " -map +/xilinx/arith_map.v";
|
||||||
if (vpr)
|
if (vpr)
|
||||||
techmap_files += " -D _EXPLICIT_CARRY";
|
techmap_files += " -D _EXPLICIT_CARRY";
|
||||||
else if (abc == "abc9")
|
else if (abc9)
|
||||||
techmap_files += " -D _CLB_CARRY";
|
techmap_files += " -D _CLB_CARRY";
|
||||||
}
|
}
|
||||||
run("techmap " + techmap_files);
|
run("techmap " + techmap_files);
|
||||||
|
@ -276,7 +285,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_cells")) {
|
if (check_label("map_cells")) {
|
||||||
if (abc == "abc9")
|
if (abc9)
|
||||||
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v -D _ABC -map +/xilinx/ff_map.v");
|
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v -D _ABC -map +/xilinx/ff_map.v");
|
||||||
else
|
else
|
||||||
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
|
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
|
||||||
|
@ -284,21 +293,31 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_luts")) {
|
if (check_label("map_luts")) {
|
||||||
if (abc == "abc9") {
|
run("opt_expr -mux_undef");
|
||||||
|
if (help_mode)
|
||||||
|
run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(skip if 'nowidelut', only for '-retime')");
|
||||||
|
else if (abc9) {
|
||||||
|
if (family != "xc7")
|
||||||
|
log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n");
|
||||||
run("read_verilog -icells -lib +/xilinx/abc_ff.v");
|
run("read_verilog -icells -lib +/xilinx/abc_ff.v");
|
||||||
run(abc + " -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + XC7_WIRE_DELAY + string(retime ? " -retime" : ""));
|
if (nowidelut)
|
||||||
|
run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
|
||||||
|
else
|
||||||
|
run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (nowidelut)
|
||||||
|
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
|
||||||
|
else
|
||||||
|
run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
|
||||||
}
|
}
|
||||||
else if (help_mode)
|
|
||||||
run(abc + " -luts 2:2,3,6:5,10,20 [-dff]");
|
|
||||||
else
|
|
||||||
run(abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
|
|
||||||
run("clean");
|
run("clean");
|
||||||
|
|
||||||
// This shregmap call infers fixed length shift registers after abc
|
// This shregmap call infers fixed length shift registers after abc
|
||||||
// has performed any necessary retiming
|
// has performed any necessary retiming
|
||||||
if (!nosrl || help_mode)
|
if (!nosrl || help_mode)
|
||||||
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
|
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
|
||||||
if (abc == "abc9")
|
if (abc9)
|
||||||
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v");
|
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v");
|
||||||
else
|
else
|
||||||
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
|
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
|
||||||
|
|
3
tests/aiger/.gitignore
vendored
3
tests/aiger/.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
*.log
|
/*_ref.v
|
||||||
*.out
|
|
||||||
|
|
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
OPTIND=1
|
||||||
|
abcprog="../../yosys-abc" # default to built-in version of abc
|
||||||
|
while getopts "A:" opt
|
||||||
|
do
|
||||||
|
case "$opt" in
|
||||||
|
A) abcprog="$OPTARG" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
# NB: *.aag and *.aig must contain a symbol table naming the primary
|
# NB: *.aag and *.aig must contain a symbol table naming the primary
|
||||||
# inputs and outputs, otherwise ABC and Yosys will name them
|
# inputs and outputs, otherwise ABC and Yosys will name them
|
||||||
# arbitrarily (and inconsistently with each other).
|
# arbitrarily (and inconsistently with each other).
|
||||||
|
@ -10,8 +20,9 @@ for aag in *.aag; do
|
||||||
# Since ABC cannot read *.aag, read the *.aig instead
|
# Since ABC cannot read *.aag, read the *.aig instead
|
||||||
# (which would have been created by the reference aig2aig utility,
|
# (which would have been created by the reference aig2aig utility,
|
||||||
# available from http://fmv.jku.at/aiger/)
|
# available from http://fmv.jku.at/aiger/)
|
||||||
../../yosys-abc -c "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
|
echo "Checking $aag."
|
||||||
../../yosys -p "
|
$abcprog -q "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
|
||||||
|
../../yosys -qp "
|
||||||
read_verilog ${aag%.*}_ref.v
|
read_verilog ${aag%.*}_ref.v
|
||||||
prep
|
prep
|
||||||
design -stash gold
|
design -stash gold
|
||||||
|
@ -26,8 +37,9 @@ sat -verify -prove-asserts -show-ports -seq 16 miter
|
||||||
done
|
done
|
||||||
|
|
||||||
for aig in *.aig; do
|
for aig in *.aig; do
|
||||||
../../yosys-abc -c "read -c $aig; write ${aig%.*}_ref.v"
|
echo "Checking $aig."
|
||||||
../../yosys -p "
|
$abcprog -q "read -c $aig; write ${aig%.*}_ref.v"
|
||||||
|
../../yosys -qp "
|
||||||
read_verilog ${aig%.*}_ref.v
|
read_verilog ${aig%.*}_ref.v
|
||||||
prep
|
prep
|
||||||
design -stash gold
|
design -stash gold
|
||||||
|
|
18
tests/arch/run-test.sh
Executable file
18
tests/arch/run-test.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Running syntax check on arch sim models"
|
||||||
|
for arch in ../../techlibs/*; do
|
||||||
|
find $arch -name cells_sim.v | while read path; do
|
||||||
|
echo -n "Test $path ->"
|
||||||
|
iverilog -t null -I$arch $path
|
||||||
|
echo " ok"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
for path in "../../techlibs/common/simcells.v" "../../techlibs/common/simlib.v"; do
|
||||||
|
echo -n "Test $path ->"
|
||||||
|
iverilog -t null $path
|
||||||
|
echo " ok"
|
||||||
|
done
|
28
tests/memories/issue00335.v
Normal file
28
tests/memories/issue00335.v
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// expect-wr-ports 1
|
||||||
|
// expect-rd-ports 1
|
||||||
|
// expect-rd-clk \clk
|
||||||
|
|
||||||
|
module ram2 (input clk,
|
||||||
|
input sel,
|
||||||
|
input we,
|
||||||
|
input [SIZE-1:0] adr,
|
||||||
|
input [63:0] dat_i,
|
||||||
|
output reg [63:0] dat_o);
|
||||||
|
parameter SIZE = 5; // Address size
|
||||||
|
|
||||||
|
reg [63:0] mem [0:(1 << SIZE)-1];
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (i = 0; i < (1<<SIZE) - 1; i = i + 1)
|
||||||
|
mem[i] <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (sel) begin
|
||||||
|
if (~we)
|
||||||
|
dat_o <= mem[adr];
|
||||||
|
else
|
||||||
|
mem[adr] <= dat_i;
|
||||||
|
end
|
||||||
|
endmodule
|
17
tests/memories/issue00710.v
Normal file
17
tests/memories/issue00710.v
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// expect-wr-ports 1
|
||||||
|
// expect-rd-ports 1
|
||||||
|
// expect-rd-clk \clk
|
||||||
|
|
||||||
|
module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata);
|
||||||
|
|
||||||
|
reg [7:0] bram[0:255];
|
||||||
|
(* keep *) reg dummy;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset)
|
||||||
|
dummy <= 1'b0;
|
||||||
|
else if (re)
|
||||||
|
rdata <= bram[addr];
|
||||||
|
else if (we)
|
||||||
|
bram[addr] <= wdata;
|
||||||
|
endmodule
|
|
@ -4,17 +4,19 @@ set -e
|
||||||
|
|
||||||
OPTIND=1
|
OPTIND=1
|
||||||
seed="" # default to no seed specified
|
seed="" # default to no seed specified
|
||||||
while getopts "S:" opt
|
abcopt=""
|
||||||
|
while getopts "A:S:" opt
|
||||||
do
|
do
|
||||||
case "$opt" in
|
case "$opt" in
|
||||||
|
A) abcopt="-A $OPTARG" ;;
|
||||||
S) seed="-S $OPTARG" ;;
|
S) seed="-S $OPTARG" ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
shift "$((OPTIND-1))"
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
bash ../tools/autotest.sh $seed -G *.v
|
bash ../tools/autotest.sh $abcopt $seed -G *.v
|
||||||
|
|
||||||
for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do
|
for f in `egrep -l 'expect-(wr-ports|rd-ports|rd-clk)' *.v`; do
|
||||||
echo -n "Testing expectations for $f .."
|
echo -n "Testing expectations for $f .."
|
||||||
../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f
|
../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f
|
||||||
if grep -q expect-wr-ports $f; then
|
if grep -q expect-wr-ports $f; then
|
||||||
|
@ -25,6 +27,10 @@ for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do
|
||||||
grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp ||
|
grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp ||
|
||||||
{ echo " ERROR: Unexpected number of read ports."; false; }
|
{ echo " ERROR: Unexpected number of read ports."; false; }
|
||||||
fi
|
fi
|
||||||
|
if grep -q expect-rd-clk $f; then
|
||||||
|
grep -q "connect \\\\RD_CLK \\$(gawk '/expect-rd-clk/ { print $3; }' $f)\$" ${f%.v}.dmp ||
|
||||||
|
{ echo " ERROR: Unexpected read clock."; false; }
|
||||||
|
fi
|
||||||
echo " ok."
|
echo " ok."
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
12
tests/opt/opt_ff_sat.v
Normal file
12
tests/opt/opt_ff_sat.v
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
output reg [7:0] cnt
|
||||||
|
);
|
||||||
|
initial cnt = 0;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (cnt < 20)
|
||||||
|
cnt <= cnt + 1;
|
||||||
|
else
|
||||||
|
cnt <= 0;
|
||||||
|
end
|
||||||
|
endmodule
|
5
tests/opt/opt_ff_sat.ys
Normal file
5
tests/opt/opt_ff_sat.ys
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
read_verilog opt_ff_sat.v
|
||||||
|
prep -flatten
|
||||||
|
opt_rmdff -sat
|
||||||
|
synth
|
||||||
|
select -assert-count 5 t:$_DFF_P_
|
16
tests/simple/arrays02.sv
Normal file
16
tests/simple/arrays02.sv
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
module uut_arrays02(clock, we, addr, wr_data, rd_data);
|
||||||
|
|
||||||
|
input clock, we;
|
||||||
|
input [3:0] addr, wr_data;
|
||||||
|
output [3:0] rd_data;
|
||||||
|
reg [3:0] rd_data;
|
||||||
|
|
||||||
|
reg [3:0] memory [16];
|
||||||
|
|
||||||
|
always @(posedge clock) begin
|
||||||
|
if (we)
|
||||||
|
memory[addr] <= wr_data;
|
||||||
|
rd_data <= memory[addr];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
22
tests/simple/defvalue.sv
Normal file
22
tests/simple/defvalue.sv
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
module top(input clock, input [3:0] delta, output [3:0] cnt1, cnt2);
|
||||||
|
cnt #(1) foo (.clock, .cnt(cnt1), .delta);
|
||||||
|
cnt #(2) bar (.clock, .cnt(cnt2));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module cnt #(
|
||||||
|
parameter integer initval = 0
|
||||||
|
) (
|
||||||
|
input clock,
|
||||||
|
output logic [3:0] cnt = initval,
|
||||||
|
`ifdef __ICARUS__
|
||||||
|
input [3:0] delta
|
||||||
|
`else
|
||||||
|
input [3:0] delta = 10
|
||||||
|
`endif
|
||||||
|
);
|
||||||
|
`ifdef __ICARUS__
|
||||||
|
assign (weak0, weak1) delta = 10;
|
||||||
|
`endif
|
||||||
|
always @(posedge clock)
|
||||||
|
cnt <= cnt + delta;
|
||||||
|
endmodule
|
|
@ -148,3 +148,14 @@ generate
|
||||||
endgenerate
|
endgenerate
|
||||||
assign out = steps[WIDTH].outer[0].val;
|
assign out = steps[WIDTH].outer[0].val;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
|
||||||
|
module gen_test6(output [3:0] o);
|
||||||
|
generate
|
||||||
|
genvar i;
|
||||||
|
for (i = 3; i >= 0; i = i-1) begin
|
||||||
|
assign o[i] = 1'b0;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
|
@ -262,3 +262,8 @@ endmodule
|
||||||
module abc9_test025(input [3:0] i, output [3:0] o);
|
module abc9_test025(input [3:0] i, output [3:0] o);
|
||||||
abc9_test024_sub a(i[2:1], o[2:1]);
|
abc9_test024_sub a(i[2:1], o[2:1]);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module abc9_test026(output [3:0] o, p);
|
||||||
|
assign o = { 1'b1, 1'bx };
|
||||||
|
assign p = { 1'b1, 1'bx, 1'b0 };
|
||||||
|
endmodule
|
||||||
|
|
|
@ -23,12 +23,13 @@ warn_iverilog_git=false
|
||||||
# The tests are skipped if firrtl2verilog is the empty string (the default).
|
# The tests are skipped if firrtl2verilog is the empty string (the default).
|
||||||
firrtl2verilog=""
|
firrtl2verilog=""
|
||||||
xfirrtl="../xfirrtl"
|
xfirrtl="../xfirrtl"
|
||||||
|
abcprog="$toolsdir/../../yosys-abc"
|
||||||
|
|
||||||
if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
|
if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
|
||||||
( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
|
( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do
|
while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do
|
||||||
case "$opt" in
|
case "$opt" in
|
||||||
x)
|
x)
|
||||||
use_xsim=true ;;
|
use_xsim=true ;;
|
||||||
|
@ -65,6 +66,8 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do
|
||||||
include_opts="$include_opts -I $OPTARG"
|
include_opts="$include_opts -I $OPTARG"
|
||||||
xinclude_opts="$xinclude_opts -i $OPTARG"
|
xinclude_opts="$xinclude_opts -i $OPTARG"
|
||||||
minclude_opts="$minclude_opts +incdir+$OPTARG" ;;
|
minclude_opts="$minclude_opts +incdir+$OPTARG" ;;
|
||||||
|
A)
|
||||||
|
abcprog="$OPTARG" ;;
|
||||||
-)
|
-)
|
||||||
case "${OPTARG}" in
|
case "${OPTARG}" in
|
||||||
xfirrtl)
|
xfirrtl)
|
||||||
|
@ -89,8 +92,7 @@ done
|
||||||
|
|
||||||
compile_and_run() {
|
compile_and_run() {
|
||||||
exe="$1"; output="$2"; shift 2
|
exe="$1"; output="$2"; shift 2
|
||||||
ext=${1##*.}
|
if [ "${2##*.}" == "sv" ]; then
|
||||||
if [ "$ext" == "sv" ]; then
|
|
||||||
language_gen="-g2012"
|
language_gen="-g2012"
|
||||||
else
|
else
|
||||||
language_gen="-g2005"
|
language_gen="-g2005"
|
||||||
|
@ -142,23 +144,25 @@ do
|
||||||
cd ${bn}.out
|
cd ${bn}.out
|
||||||
fn=$(basename $fn)
|
fn=$(basename $fn)
|
||||||
bn=$(basename $bn)
|
bn=$(basename $bn)
|
||||||
|
refext=v
|
||||||
|
|
||||||
rm -f ${bn}_ref.fir
|
rm -f ${bn}_ref.fir
|
||||||
if [[ "$ext" == "v" ]]; then
|
if [[ "$ext" == "v" ]]; then
|
||||||
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
|
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
|
||||||
elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then
|
elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then
|
||||||
"$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.v"
|
$abcprog -c "read_aiger ../${fn}; write ${bn}_ref.${refext}"
|
||||||
else
|
else
|
||||||
cp ../${fn} ${bn}_ref.${ext}
|
refext=$ext
|
||||||
|
cp ../${fn} ${bn}_ref.${refext}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f ../${bn}_tb.v ]; then
|
if [ ! -f ../${bn}_tb.v ]; then
|
||||||
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v
|
"$toolsdir"/../../yosys -f "$frontend $include_opts -D_AUTOTB" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.${refext}
|
||||||
else
|
else
|
||||||
cp ../${bn}_tb.v ${bn}_tb.v
|
cp ../${bn}_tb.v ${bn}_tb.v
|
||||||
fi
|
fi
|
||||||
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
|
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
|
||||||
compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
|
compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} $libs \
|
||||||
"$toolsdir"/../../techlibs/common/simlib.v \
|
"$toolsdir"/../../techlibs/common/simlib.v \
|
||||||
"$toolsdir"/../../techlibs/common/simcells.v
|
"$toolsdir"/../../techlibs/common/simcells.v
|
||||||
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
|
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
|
||||||
|
@ -175,25 +179,25 @@ do
|
||||||
test_count=$(( test_count + 1 ))
|
test_count=$(( test_count + 1 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.v; then
|
if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.${refext}; then
|
||||||
touch ../${bn}.skip
|
touch ../${bn}.skip
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$scriptfiles" ]; then
|
if [ -n "$scriptfiles" ]; then
|
||||||
test_passes -f "$frontend $include_opts" ${bn}_ref.v $scriptfiles
|
test_passes -f "$frontend $include_opts" ${bn}_ref.${refext} $scriptfiles
|
||||||
elif [ -n "$scriptopt" ]; then
|
elif [ -n "$scriptopt" ]; then
|
||||||
test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.v
|
test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.${refext}
|
||||||
elif [ "$frontend" = "verific" ]; then
|
elif [ "$frontend" = "verific" ]; then
|
||||||
test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -all; opt; memory;;"
|
test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -all; opt; memory;;"
|
||||||
elif [ "$frontend" = "verific_gates" ]; then
|
elif [ "$frontend" = "verific_gates" ]; then
|
||||||
test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -gates -all; opt; memory;;"
|
test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -gates -all; opt; memory;;"
|
||||||
else
|
else
|
||||||
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v
|
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.${refext}
|
||||||
test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v
|
test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.${refext}
|
||||||
if [ -n "$firrtl2verilog" ]; then
|
if [ -n "$firrtl2verilog" ]; then
|
||||||
if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
|
if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
|
||||||
"$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v
|
"$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.${refext}
|
||||||
$firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v
|
$firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v
|
||||||
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
|
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
|
||||||
fi
|
fi
|
||||||
|
|
3
tests/various/.gitignore
vendored
3
tests/various/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
*.log
|
/*.log
|
||||||
|
/*.out
|
||||||
|
|
5
tests/various/abc9.v
Normal file
5
tests/various/abc9.v
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module abc9_test027(output reg o);
|
||||||
|
initial o = 1'b0;
|
||||||
|
always @*
|
||||||
|
o <= ~o;
|
||||||
|
endmodule
|
14
tests/various/abc9.ys
Normal file
14
tests/various/abc9.ys
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
read_verilog abc9.v
|
||||||
|
proc
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
abc9 -lut 4
|
||||||
|
check
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
|
@ -13,7 +13,7 @@ read_verilog -formal <<EOT
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
|
|
||||||
## Examle usage for "pmuxtree" and "muxcover"
|
## Example usage for "pmuxtree" and "muxcover"
|
||||||
|
|
||||||
proc
|
proc
|
||||||
pmuxtree
|
pmuxtree
|
||||||
|
@ -49,3 +49,462 @@ hierarchy -top equiv
|
||||||
equiv_simple -undef
|
equiv_simple -undef
|
||||||
equiv_status -assert
|
equiv_status -assert
|
||||||
|
|
||||||
|
## Partial matching MUX4
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux_if_bal_3_1 #(parameter N=3, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {{W{{1'bx}}}};
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux4=150
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 1 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX4_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## Partial matching MUX8
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {{W{{1'bx}}}};
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux4=150 -mux8=200
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 1 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX8_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## Partial matching MUX16
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {{W{{1'bx}}}};
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[5*W+:W];
|
||||||
|
else
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
o <= i[6*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[7*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
o <= i[8*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux4=150 -mux8=200 -mux16=250
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX2 in MUX4 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux2in4(input [1:0] i, input s, output o);
|
||||||
|
assign o = s ? i[1] : i[0];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux4=99 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 1 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX4_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX2 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux2in8(input [1:0] i, input s, output o);
|
||||||
|
assign o = s ? i[1] : i[0];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux8=99 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 1 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX8_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX4 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux4in8(input [3:0] i, input [1:0] s, output o);
|
||||||
|
assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux8=299 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 1 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX8_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX2 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux2in16(input [1:0] i, input s, output o);
|
||||||
|
assign o = s ? i[1] : i[0];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux16=99 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX4 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux4in16(input [3:0] i, input [1:0] s, output o);
|
||||||
|
assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux16=299 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## MUX8 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux4in16(input [7:0] i, input [2:0] s, output o);
|
||||||
|
assign o = s[2] ? s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0])
|
||||||
|
: s[1] ? (s[0] ? i[7] : i[6]) : (s[0] ? i[5] : i[4]);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
muxcover -mux16=699 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## mux_if_bal_5_1 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {{W{{1'bx}}}};
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
wreduce
|
||||||
|
opt -full
|
||||||
|
techmap
|
||||||
|
muxcover -mux8=350
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 1 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX8_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## mux_if_bal_5_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
design -load gold
|
||||||
|
|
||||||
|
wreduce
|
||||||
|
opt -full
|
||||||
|
techmap
|
||||||
|
muxcover -mux8=350 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 1 t:$_MUX8_
|
||||||
|
select -assert-count 0 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX8_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## mux_if_bal_9_1 :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {{W{{1'bx}}}};
|
||||||
|
if (s[3] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[5*W+:W];
|
||||||
|
else
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
o <= i[6*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[7*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
o <= i[8*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
wreduce
|
||||||
|
opt -full
|
||||||
|
techmap
|
||||||
|
muxcover -mux16=750
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
## mux_if_bal_9_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
|
||||||
|
|
||||||
|
design -load gold
|
||||||
|
|
||||||
|
wreduce
|
||||||
|
opt -full
|
||||||
|
techmap
|
||||||
|
muxcover -mux16=750 -nodecode
|
||||||
|
clean
|
||||||
|
opt_expr -mux_bool
|
||||||
|
select -assert-count 0 t:$_MUX_
|
||||||
|
select -assert-count 0 t:$_MUX4_
|
||||||
|
select -assert-count 0 t:$_MUX8_
|
||||||
|
select -assert-count 1 t:$_MUX16_
|
||||||
|
techmap -map +/simcells.v t:$_MUX16_
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
259
tests/various/muxpack.v
Normal file
259
tests/various/muxpack.v
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @*
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
else if (s == 1) o <= i[1*W+:W];
|
||||||
|
else if (s == 2) o <= i[2*W+:W];
|
||||||
|
else if (s == 3) o <= i[3*W+:W];
|
||||||
|
else o <= {W{1'bx}};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {W{1'bx}};
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
if (s == 1) o <= i[1*W+:W];
|
||||||
|
if (s == 2) o <= i[2*W+:W];
|
||||||
|
if (s == 3) o <= i[3*W+:W];
|
||||||
|
if (s == 4) o <= i[4*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @*
|
||||||
|
if (s != 0)
|
||||||
|
if (s != 1)
|
||||||
|
if (s != 2)
|
||||||
|
if (s != 3)
|
||||||
|
if (s != 4) o <= i[4*W+:W];
|
||||||
|
else o <= i[0*W+:W];
|
||||||
|
else o <= i[3*W+:W];
|
||||||
|
else o <= i[2*W+:W];
|
||||||
|
else o <= i[1*W+:W];
|
||||||
|
else o <= {W{1'bx}};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {W{1'bx}};
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
if (s == 1) o <= i[1*W+:W];
|
||||||
|
if (s == 2) o[W-2:0] <= i[2*W+:W-1];
|
||||||
|
if (s == 3) o <= i[3*W+:W];
|
||||||
|
if (s == 4) o <= i[4*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
// else if (s == 1) o <= i[1*W+:W];
|
||||||
|
// else if (s == 2) o <= i[2*W+:W];
|
||||||
|
else if (s == 3) o <= i[3*W+:W];
|
||||||
|
else o <= {W{1'bx}};
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {W{1'bx}};
|
||||||
|
if (s == 3) o <= i[3*W+:W];
|
||||||
|
if (s == 2) o <= i[2*W+:W];
|
||||||
|
if (s == 1) o <= i[1*W+:W];
|
||||||
|
if (s == 4) o <= i[4*W+:W];
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @*
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
else if (s == 1) o <= i[1*W+:W];
|
||||||
|
else if (s == 2) o <= i[2*W+:W];
|
||||||
|
else if (s == 3) o <= i[3*W+:W];
|
||||||
|
else if (s == 0) o <= {W{1'b0}};
|
||||||
|
else o <= {W{1'bx}};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {W{1'bx}};
|
||||||
|
if (s == 0) o <= i[0*W+:W];
|
||||||
|
if (s == 1) o <= i[1*W+:W];
|
||||||
|
if (s == 2) o <= i[2*W+:W];
|
||||||
|
if (s == 3) o <= i[3*W+:W];
|
||||||
|
if (s == 4) o <= i[4*W+:W];
|
||||||
|
if (s == 0) o <= i[2*W+:W];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @* begin
|
||||||
|
o <= {W{1'bx}};
|
||||||
|
case (s)
|
||||||
|
0: o <= i[0*W+:W];
|
||||||
|
default:
|
||||||
|
case (s)
|
||||||
|
1: o <= i[1*W+:W];
|
||||||
|
2: o <= i[2*W+:W];
|
||||||
|
default:
|
||||||
|
case (s)
|
||||||
|
3: o <= i[3*W+:W];
|
||||||
|
4: o <= i[4*W+:W];
|
||||||
|
5: o <= i[5*W+:W];
|
||||||
|
default:
|
||||||
|
case (s)
|
||||||
|
6: o <= i[6*W+:W];
|
||||||
|
default: o <= i[7*W+:W];
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @*
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[5*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[6*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[7*W+:W];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
|
||||||
|
always @*
|
||||||
|
if (s[0] == 1'b0)
|
||||||
|
if (s[1] == 1'b0)
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[0*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[1*W+:W];
|
||||||
|
else
|
||||||
|
if (s[2] == 1'b0)
|
||||||
|
o <= i[2*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[3*W+:W];
|
||||||
|
else
|
||||||
|
o <= i[4*W+:W];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module cliffordwolf_nonexclusive_select (
|
||||||
|
input wire x, y, z,
|
||||||
|
input wire a, b, c, d,
|
||||||
|
output reg o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
o = a;
|
||||||
|
if (x) o = b;
|
||||||
|
if (y) o = c;
|
||||||
|
if (z) o = d;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module cliffordwolf_freduce (
|
||||||
|
input wire [1:0] s,
|
||||||
|
input wire a, b, c, d,
|
||||||
|
output reg [3:0] o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
o = {4{a}};
|
||||||
|
if (s == 0) o = {3{b}};
|
||||||
|
if (s == 1) o = {2{c}};
|
||||||
|
if (s == 2) o = d;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module case_nonexclusive_select (
|
||||||
|
input wire [1:0] x, y,
|
||||||
|
input wire a, b, c, d, e,
|
||||||
|
output reg o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
case (x)
|
||||||
|
0: o = b;
|
||||||
|
2: o = b;
|
||||||
|
1: o = c;
|
||||||
|
default: begin
|
||||||
|
o = a;
|
||||||
|
if (y == 0) o = d;
|
||||||
|
if (y == 1) o = e;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module case_nonoverlap (
|
||||||
|
input wire [2:0] x,
|
||||||
|
input wire a, b, c, d, e,
|
||||||
|
output reg o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
case (x)
|
||||||
|
0, 2: o = b; // Creates $reduce_or
|
||||||
|
1: o = c;
|
||||||
|
default:
|
||||||
|
case (x)
|
||||||
|
3: o = d; 4: o = d; // Creates $reduce_or
|
||||||
|
5: o = e;
|
||||||
|
default: o = 1'b0;
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module case_overlap (
|
||||||
|
input wire [2:0] x,
|
||||||
|
input wire a, b, c, d, e,
|
||||||
|
output reg o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
case (x)
|
||||||
|
0, 2: o = b; // Creates $reduce_or
|
||||||
|
1: o = c;
|
||||||
|
default:
|
||||||
|
case (x)
|
||||||
|
0: o = 1'b1; // OVERLAP!
|
||||||
|
3, 4: o = d; // Creates $reduce_or
|
||||||
|
5: o = e;
|
||||||
|
default: o = 1'b0;
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module case_overlap2 (
|
||||||
|
input wire [2:0] x,
|
||||||
|
input wire a, b, c, d, e,
|
||||||
|
output reg o
|
||||||
|
);
|
||||||
|
always @* begin
|
||||||
|
case (x)
|
||||||
|
0: o = b; 2: o = b; // Creates $reduce_or
|
||||||
|
1: o = c;
|
||||||
|
default:
|
||||||
|
case (x)
|
||||||
|
0: o = d; 2: o = d; // Creates $reduce_or
|
||||||
|
3: o = d; 4: o = d; // Creates $reduce_or
|
||||||
|
5: o = e;
|
||||||
|
default: o = 1'b0;
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
268
tests/various/muxpack.ys
Normal file
268
tests/various/muxpack.ys
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
read_verilog muxpack.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
hierarchy -top mux_if_unbal_4_1
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_5_3
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
# TODO: Currently ExclusiveDatabase only analyses $eq cells
|
||||||
|
#design -load read
|
||||||
|
#hierarchy -top mux_if_unbal_5_3_invert
|
||||||
|
#prep
|
||||||
|
#design -save gold
|
||||||
|
#muxpack
|
||||||
|
#opt
|
||||||
|
#stat
|
||||||
|
#select -assert-count 0 t:$mux
|
||||||
|
#select -assert-count 1 t:$pmux
|
||||||
|
#design -stash gate
|
||||||
|
#design -import gold -as gold
|
||||||
|
#design -import gate -as gate
|
||||||
|
#miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
#sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_5_3_width_mismatch
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_4_1_missing
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_5_3_order
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_4_1_nonexcl
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_unbal_5_3_nonexcl
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_case_unbal_8_7
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_bal_8_2
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 7 t:$mux
|
||||||
|
select -assert-count 0 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top mux_if_bal_5_1
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 4 t:$mux
|
||||||
|
select -assert-count 0 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top cliffordwolf_nonexclusive_select
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 3 t:$mux
|
||||||
|
select -assert-count 0 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
#design -load read
|
||||||
|
#hierarchy -top cliffordwolf_freduce
|
||||||
|
#prep
|
||||||
|
#design -save gold
|
||||||
|
#proc; opt; freduce; opt
|
||||||
|
#show
|
||||||
|
#muxpack
|
||||||
|
#opt
|
||||||
|
#stat
|
||||||
|
#select -assert-count 0 t:$mux
|
||||||
|
#select -assert-count 1 t:$pmux
|
||||||
|
#design -stash gate
|
||||||
|
#design -import gold -as gold
|
||||||
|
#design -import gate -as gate
|
||||||
|
#miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
#sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top case_nonexclusive_select
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top case_nonoverlap
|
||||||
|
#prep # Do not prep otherwise $pmux's overlapping entry will get removed
|
||||||
|
proc
|
||||||
|
design -save gold
|
||||||
|
opt -fast -mux_undef
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top case_overlap
|
||||||
|
#prep # Do not prep otherwise $pmux's overlapping entry will get removed
|
||||||
|
proc
|
||||||
|
design -save gold
|
||||||
|
opt -fast -mux_undef
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
hierarchy -top case_overlap2
|
||||||
|
#prep # Do not prep otherwise $pmux's overlapping entry will get removed
|
||||||
|
proc
|
||||||
|
design -save gold
|
||||||
|
opt -fast -mux_undef
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
muxpack
|
||||||
|
opt
|
||||||
|
stat
|
||||||
|
select -assert-count 0 t:$mux
|
||||||
|
select -assert-count 2 t:$pmux
|
||||||
|
design -stash gate
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports miter
|
|
@ -32,3 +32,13 @@ module pmux2shiftx_test (
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module issue01135(input [7:0] i, output o);
|
||||||
|
always @*
|
||||||
|
case (i[6:3])
|
||||||
|
4: o <= i[0];
|
||||||
|
3: o <= i[2];
|
||||||
|
7: o <= i[3];
|
||||||
|
default: o <= 1'b0;
|
||||||
|
endcase
|
||||||
|
endmodule
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
read_verilog pmux2shiftx.v
|
read_verilog pmux2shiftx.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
hierarchy -top pmux2shiftx_test
|
||||||
prep
|
prep
|
||||||
design -save gold
|
design -save gold
|
||||||
|
|
||||||
|
@ -21,8 +24,16 @@ design -import gate -as gate
|
||||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
sat -verify -prove-asserts -show-ports miter
|
sat -verify -prove-asserts -show-ports miter
|
||||||
|
|
||||||
design -load gold
|
#design -load gold
|
||||||
stat
|
#stat
|
||||||
|
#
|
||||||
|
#design -load gate
|
||||||
|
#stat
|
||||||
|
|
||||||
design -load gate
|
design -load read
|
||||||
stat
|
hierarchy -top issue01135
|
||||||
|
proc
|
||||||
|
pmux2shiftx -norange
|
||||||
|
opt -full
|
||||||
|
select -assert-count 0 t:$shift*
|
||||||
|
select -assert-count 1 t:$pmux
|
||||||
|
|
48
tests/various/shregmap.v
Normal file
48
tests/various/shregmap.v
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
module shregmap_static_test(input i, clk, output [1:0] q);
|
||||||
|
reg head = 1'b0;
|
||||||
|
reg [3:0] shift1 = 4'b0000;
|
||||||
|
reg [3:0] shift2 = 4'b0000;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
head <= i;
|
||||||
|
shift1 <= {shift1[2:0], head};
|
||||||
|
shift2 <= {shift2[2:0], head};
|
||||||
|
end
|
||||||
|
|
||||||
|
assign q = {shift2[3], shift1[3]};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module $__SHREG_DFF_P_(input C, D, output Q);
|
||||||
|
parameter DEPTH = 1;
|
||||||
|
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
|
||||||
|
reg [DEPTH-1:0] r = INIT;
|
||||||
|
always @(posedge C)
|
||||||
|
r <= { r[DEPTH-2:0], D };
|
||||||
|
assign Q = r[DEPTH-1];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module shregmap_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q);
|
||||||
|
reg head = 1'b0;
|
||||||
|
reg [3:0] shift1 = 4'b0000;
|
||||||
|
reg [3:0] shift2 = 4'b0000;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
head <= i;
|
||||||
|
shift1 <= {shift1[2:0], head};
|
||||||
|
shift2 <= {shift2[2:0], head};
|
||||||
|
end
|
||||||
|
|
||||||
|
assign q = {shift2[l2], shift1[l1]};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module $__XILINX_SHREG_(input C, D, input [1:0] L, output Q);
|
||||||
|
parameter CLKPOL = 1;
|
||||||
|
parameter ENPOL = 1;
|
||||||
|
parameter DEPTH = 1;
|
||||||
|
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
|
||||||
|
reg [DEPTH-1:0] r = INIT;
|
||||||
|
wire clk = C ^ CLKPOL;
|
||||||
|
always @(posedge C)
|
||||||
|
r <= { r[DEPTH-2:0], D };
|
||||||
|
assign Q = r[L];
|
||||||
|
endmodule
|
66
tests/various/shregmap.ys
Normal file
66
tests/various/shregmap.ys
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
read_verilog shregmap.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
design -copy-to model $__SHREG_DFF_P_
|
||||||
|
hierarchy -top shregmap_static_test
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
shregmap -init
|
||||||
|
|
||||||
|
opt
|
||||||
|
|
||||||
|
stat
|
||||||
|
# show -width
|
||||||
|
select -assert-count 1 t:$_DFF_P_
|
||||||
|
select -assert-count 2 t:$__SHREG_DFF_P_
|
||||||
|
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
design -copy-from model -as $__SHREG_DFF_P_ \$__SHREG_DFF_P_
|
||||||
|
prep
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports -seq 5 miter
|
||||||
|
|
||||||
|
design -load gold
|
||||||
|
stat
|
||||||
|
|
||||||
|
design -load gate
|
||||||
|
stat
|
||||||
|
|
||||||
|
##########
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
design -copy-to model $__XILINX_SHREG_
|
||||||
|
hierarchy -top shregmap_variable_test
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
simplemap t:$dff t:$dffe
|
||||||
|
shregmap -tech xilinx
|
||||||
|
|
||||||
|
stat
|
||||||
|
# show -width
|
||||||
|
write_verilog -noexpr -norename
|
||||||
|
select -assert-count 1 t:$_DFF_P_
|
||||||
|
select -assert-count 2 t:$__XILINX_SHREG_
|
||||||
|
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
|
||||||
|
prep
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports -seq 5 miter
|
||||||
|
|
||||||
|
design -load gold
|
||||||
|
stat
|
||||||
|
|
||||||
|
design -load gate
|
||||||
|
stat
|
33
tests/various/signext.ys
Normal file
33
tests/various/signext.ys
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module gate(input clk, output [32:0] o, p, q, r, s, t, u);
|
||||||
|
assign o = 'bx;
|
||||||
|
assign p = 1'bx;
|
||||||
|
assign q = 'bz;
|
||||||
|
assign r = 1'bz;
|
||||||
|
assign s = 1'b0;
|
||||||
|
assign t = 'b1;
|
||||||
|
assign u = -'sb1;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
proc
|
||||||
|
|
||||||
|
## Equivalence checking
|
||||||
|
|
||||||
|
read_verilog -formal <<EOT
|
||||||
|
module gold(input clk, output [32:0] o, p, q, r, s, t, u);
|
||||||
|
assign o = {33{1'bx}};
|
||||||
|
assign p = {{32{1'b0}}, 1'bx};
|
||||||
|
assign q = {33{1'bz}};
|
||||||
|
assign r = {{32{1'b0}}, 1'bz};
|
||||||
|
assign s = {33{1'b0}};
|
||||||
|
assign t = {{32{1'b0}}, 1'b1};
|
||||||
|
assign u = {33{1'b1}};
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
proc
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports -enable_undef miter
|
Loading…
Reference in a new issue