mirror of https://github.com/YosysHQ/yosys.git
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
|
||||
--------------------------
|
||||
|
||||
|
@ -16,12 +27,18 @@ Yosys 0.8 .. Yosys 0.8-dev
|
|||
- Added "gate2lut.v" techmap rule
|
||||
- Added "rename -src"
|
||||
- Added "equiv_opt" pass
|
||||
- Added "shregmap -tech xilinx"
|
||||
- Added "read_aiger" frontend
|
||||
- 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)
|
||||
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
|
||||
- Added "muxcover -mux{4,8,16}=<cost>"
|
||||
- Added "muxcover -dmux=<cost>"
|
||||
- Added "muxcover -nopartial"
|
||||
- Added "muxpack" pass
|
||||
- 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
|
||||
|
@ -35,7 +52,7 @@ Yosys 0.7 .. Yosys 0.8
|
|||
- Added "write_verilog -decimal"
|
||||
- Added "scc -set_attr"
|
||||
- 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 FIRRTL back-end
|
||||
- Improved ABC default scripts
|
||||
|
@ -44,7 +61,7 @@ Yosys 0.7 .. Yosys 0.8
|
|||
- Added Verilog $rtoi and $itor support
|
||||
- Added "check -initdrv"
|
||||
- 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 "write_edif" options for edif "flavors"
|
||||
- Added support for resetall compiler directive
|
||||
|
|
12
Makefile
12
Makefile
|
@ -666,6 +666,12 @@ else
|
|||
SEEDOPT=""
|
||||
endif
|
||||
|
||||
ifneq ($(ABCEXTERNAL),)
|
||||
ABCOPT="-A $(ABCEXTERNAL)"
|
||||
else
|
||||
ABCOPT=""
|
||||
endif
|
||||
|
||||
test: $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd tests/simple && 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/fsm && bash run-test.sh $(SEEDOPT)
|
||||
+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/various && bash run-test.sh
|
||||
+cd tests/sat && bash run-test.sh
|
||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||
+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 " Passed \"make test\"."
|
||||
@echo ""
|
||||
|
|
|
@ -350,6 +350,14 @@ Verilog Attributes and non-standard features
|
|||
through the synthesis. When entities are combined, a new |-separated
|
||||
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
|
||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||
|
|
|
@ -70,34 +70,35 @@ struct AigerWriter
|
|||
|
||||
int bit2aig(SigBit bit)
|
||||
{
|
||||
if (aig_map.count(bit) == 0)
|
||||
{
|
||||
aig_map[bit] = -1;
|
||||
|
||||
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");
|
||||
auto it = aig_map.find(bit);
|
||||
if (it != aig_map.end()) {
|
||||
log_assert(it->second >= 0);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
log_assert(aig_map.at(bit) >= 0);
|
||||
return aig_map.at(bit);
|
||||
// NB: Cannot use iterator returned from aig_map.insert()
|
||||
// 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)
|
||||
|
@ -776,6 +777,7 @@ struct AigerBackend : public Backend {
|
|||
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||
|
||||
if (!map_filename.empty()) {
|
||||
rewrite_filename(filename);
|
||||
std::ofstream mapf;
|
||||
mapf.open(map_filename.c_str(), std::ofstream::trunc);
|
||||
if (mapf.fail())
|
||||
|
|
|
@ -25,6 +25,21 @@
|
|||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#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
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
@ -79,6 +94,7 @@ struct XAigerWriter
|
|||
dict<SigBit, int> ordered_latches;
|
||||
|
||||
vector<Cell*> box_list;
|
||||
bool omode = false;
|
||||
|
||||
//dict<SigBit, int> init_inputs;
|
||||
//int initstate_ff = 0;
|
||||
|
@ -92,30 +108,37 @@ struct XAigerWriter
|
|||
|
||||
int bit2aig(SigBit bit)
|
||||
{
|
||||
if (aig_map.count(bit) == 0)
|
||||
{
|
||||
aig_map[bit] = -1;
|
||||
|
||||
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");
|
||||
auto it = aig_map.find(bit);
|
||||
if (it != aig_map.end()) {
|
||||
log_assert(it->second >= 0);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
log_assert(aig_map.at(bit) >= 0);
|
||||
return aig_map.at(bit);
|
||||
// NB: Cannot use iterator returned from aig_map.insert()
|
||||
// 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)
|
||||
|
@ -167,9 +190,13 @@ struct XAigerWriter
|
|||
}
|
||||
|
||||
if (wire->port_output || keep) {
|
||||
if (bit != wirebit)
|
||||
alias_map[wirebit] = bit;
|
||||
output_bits.insert(wirebit);
|
||||
if (bit != RTLIL::Sx) {
|
||||
if (bit != 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;
|
||||
auto is_input = cell->input(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) {
|
||||
for (auto b : c.second.bits()) {
|
||||
|
@ -313,8 +341,6 @@ struct XAigerWriter
|
|||
for (auto user_cell : it.second)
|
||||
toposort.edge(driver_cell, user_cell);
|
||||
|
||||
pool<RTLIL::Module*> abc_carry_modules;
|
||||
|
||||
#if 0
|
||||
toposort.analyze_loops = true;
|
||||
#endif
|
||||
|
@ -322,53 +348,63 @@ struct XAigerWriter
|
|||
#if 0
|
||||
unsigned i = 0;
|
||||
for (auto &it : toposort.loops) {
|
||||
log(" loop %d", i++);
|
||||
for (auto cell : it)
|
||||
log(" %s", log_id(cell));
|
||||
log("\n");
|
||||
log(" loop %d\n", i++);
|
||||
for (auto cell_name : it) {
|
||||
auto cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
log_assert(no_loops);
|
||||
|
||||
pool<IdString> seen_boxes;
|
||||
for (auto cell_name : toposort.sorted) {
|
||||
RTLIL::Cell *cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
|
||||
RTLIL::Module* box_module = module->design->module(cell->type);
|
||||
if (!box_module || !box_module->attributes.count("\\abc_box_id"))
|
||||
continue;
|
||||
|
||||
if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
|
||||
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
|
||||
RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
|
||||
for (const auto &port_name : box_module->ports) {
|
||||
RTLIL::Wire* w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (w->port_input) {
|
||||
if (w->attributes.count("\\abc_carry_in")) {
|
||||
log_assert(!carry_in);
|
||||
carry_in = w;
|
||||
}
|
||||
log_assert(!last_in || last_in->port_id < w->port_id);
|
||||
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 (seen_boxes.insert(cell->type).second) {
|
||||
auto it = box_module->attributes.find("\\abc_carry");
|
||||
if (it != box_module->attributes.end()) {
|
||||
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
|
||||
auto carry_in_out = it->second.decode_string();
|
||||
auto pos = carry_in_out.find(',');
|
||||
if (pos == std::string::npos)
|
||||
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
|
||||
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
|
||||
carry_in = box_module->wire(carry_in_name);
|
||||
if (!carry_in || !carry_in->port_input)
|
||||
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());
|
||||
|
||||
if (carry_in) {
|
||||
log_assert(last_in);
|
||||
std::swap(box_module->ports[carry_in->port_id-1], box_module->ports[last_in->port_id-1]);
|
||||
std::swap(carry_in->port_id, last_in->port_id);
|
||||
}
|
||||
if (carry_out) {
|
||||
log_assert(last_out);
|
||||
std::swap(box_module->ports[carry_out->port_id-1], box_module->ports[last_out->port_id-1]);
|
||||
std::swap(carry_out->port_id, last_out->port_id);
|
||||
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
|
||||
carry_out = box_module->wire(carry_out_name);
|
||||
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());
|
||||
|
||||
auto &ports = box_module->ports;
|
||||
for (auto jt = ports.begin(); jt != ports.end(); ) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,10 +429,16 @@ struct XAigerWriter
|
|||
}
|
||||
|
||||
int offset = 0;
|
||||
for (const auto &b : rhs.bits()) {
|
||||
for (auto b : rhs.bits()) {
|
||||
SigBit I = sigmap(b);
|
||||
if (I != b)
|
||||
alias_map[b] = I;
|
||||
if (b == RTLIL::Sx)
|
||||
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);
|
||||
unused_bits.erase(b);
|
||||
}
|
||||
|
@ -437,27 +479,33 @@ struct XAigerWriter
|
|||
}
|
||||
|
||||
for (auto bit : input_bits) {
|
||||
if (!output_bits.count(bit))
|
||||
continue;
|
||||
RTLIL::Wire *wire = bit.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
|
||||
// inherit existing inout's drivers
|
||||
if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
|
||||
|| wire->attributes.count("\\keep")) {
|
||||
log_assert(input_bits.count(bit) && output_bits.count(bit));
|
||||
RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
|
||||
RTLIL::Wire *new_wire = module->wire(wire_name);
|
||||
if (!new_wire)
|
||||
new_wire = module->addWire(wire_name, GetSize(wire));
|
||||
SigBit new_bit(new_wire, bit.offset);
|
||||
module->connect(new_bit, bit);
|
||||
if (not_map.count(bit))
|
||||
not_map[new_bit] = not_map.at(bit);
|
||||
else if (and_map.count(bit))
|
||||
and_map[new_bit] = and_map.at(bit);
|
||||
else if (alias_map.count(bit))
|
||||
alias_map[new_bit] = alias_map.at(bit);
|
||||
if (not_map.count(bit)) {
|
||||
auto a = not_map.at(bit);
|
||||
not_map[new_bit] = a;
|
||||
}
|
||||
else if (and_map.count(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
|
||||
//log_abort();
|
||||
alias_map[new_bit] = bit;
|
||||
output_bits.erase(bit);
|
||||
output_bits.insert(new_bit);
|
||||
|
@ -590,6 +638,12 @@ struct XAigerWriter
|
|||
aig_o++;
|
||||
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)
|
||||
|
@ -796,6 +850,8 @@ struct XAigerWriter
|
|||
f.write(buffer_str.data(), buffer_str.size());
|
||||
|
||||
if (holes_module) {
|
||||
log_push();
|
||||
|
||||
// NB: fixup_ports() will sort ports by name
|
||||
//holes_module->fixup_ports();
|
||||
holes_module->check();
|
||||
|
@ -832,6 +888,8 @@ struct XAigerWriter
|
|||
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
||||
f.write(buffer_str.data(), buffer_str.size());
|
||||
holes_module->design->remove(holes_module);
|
||||
|
||||
log_pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,6 +973,8 @@ struct XAigerWriter
|
|||
for (auto &it : output_lines)
|
||||
f << it.second;
|
||||
log_assert(output_lines.size() == output_bits.size());
|
||||
if (omode && output_bits.empty())
|
||||
f << "output " << output_lines.size() << " 0 $__dummy__\n";
|
||||
|
||||
latch_lines.sort();
|
||||
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/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
@ -875,9 +880,28 @@ struct BtorWorker
|
|||
else
|
||||
{
|
||||
if (bit_cell.count(bit) == 0)
|
||||
log_error("No driver for signal bit %s.\n", log_signal(bit));
|
||||
export_cell(bit_cell.at(bit));
|
||||
log_assert(bit_nid.count(bit));
|
||||
{
|
||||
SigSpec s = 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;
|
||||
|
||||
if (!filename.empty()) {
|
||||
rewrite_filename(filename);
|
||||
std::ofstream *ff = new std::ofstream;
|
||||
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
|
||||
if (ff->fail()) {
|
||||
|
|
|
@ -126,6 +126,10 @@ struct JsonWriter
|
|||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(n).c_str());
|
||||
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(" }");
|
||||
first = false;
|
||||
|
@ -189,6 +193,10 @@ struct JsonWriter
|
|||
f << stringf(" %s: {\n", get_name(w->name).c_str());
|
||||
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
|
||||
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\": {");
|
||||
write_parameters(w->attributes);
|
||||
f << stringf("\n }\n");
|
||||
|
@ -525,6 +533,7 @@ struct JsonPass : public Pass {
|
|||
std::stringstream buf;
|
||||
|
||||
if (!filename.empty()) {
|
||||
rewrite_filename(filename);
|
||||
std::ofstream *ff = new std::ofstream;
|
||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||
if (ff->fail()) {
|
||||
|
|
|
@ -336,6 +336,7 @@ struct ProtobufPass : public Pass {
|
|||
std::stringstream buf;
|
||||
|
||||
if (!filename.empty()) {
|
||||
rewrite_filename(filename);
|
||||
std::ofstream *ff = new std::ofstream;
|
||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||
if (ff->fail()) {
|
||||
|
|
|
@ -1023,6 +1023,8 @@ class MkVcd:
|
|||
assert t >= self.t
|
||||
if t != self.t:
|
||||
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 event 1 ! smt_clock $end", file=self.f)
|
||||
|
||||
|
@ -1041,7 +1043,10 @@ class MkVcd:
|
|||
scope = scope[:-1]
|
||||
|
||||
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)])
|
||||
|
||||
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.
|
||||
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
// https://stackoverflow.com/a/46137633
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
|
@ -52,6 +49,9 @@ inline int32_t from_big_endian(int32_t i32) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#define log_debug2(...) ;
|
||||
//#define log_debug2(...) log_debug(__VA_ARGS__)
|
||||
|
||||
struct ConstEvalAig
|
||||
{
|
||||
RTLIL::Module *module;
|
||||
|
@ -117,13 +117,20 @@ struct ConstEvalAig
|
|||
|
||||
RTLIL::Cell *cell = sig2driver.at(output);
|
||||
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());
|
||||
if (!inputs.count(sig_a))
|
||||
compute_deps(sig_a, inputs);
|
||||
|
||||
if (cell->type == "$_AND_") {
|
||||
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());
|
||||
|
||||
if (!inputs.count(sig_b))
|
||||
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::Wire *wire = module->wire(wire_name);
|
||||
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->port_input = wire->port_output = false;
|
||||
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;
|
||||
}
|
||||
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->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);
|
||||
|
||||
return wire;
|
||||
|
@ -369,7 +376,11 @@ void AigerReader::parse_xaiger()
|
|||
continue;
|
||||
if (m->name.begins_with("$paramod"))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -396,13 +407,13 @@ void AigerReader::parse_xaiger()
|
|||
for (unsigned i = 0; i < lutNum; ++i) {
|
||||
uint32_t rootNodeID = 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));
|
||||
uint32_t nodeID;
|
||||
RTLIL::SigSpec input_sig;
|
||||
for (unsigned j = 0; j < cutLeavesM; ++j) {
|
||||
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));
|
||||
log_assert(wire);
|
||||
input_sig.append(wire);
|
||||
|
@ -487,7 +498,7 @@ void AigerReader::parse_aiger_ascii()
|
|||
for (unsigned i = 1; i <= I; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
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
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_input = true;
|
||||
|
@ -499,7 +510,7 @@ void AigerReader::parse_aiger_ascii()
|
|||
if (L > 0 && !clk_name.empty()) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
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->port_input = true;
|
||||
clk_wire->port_output = false;
|
||||
|
@ -507,7 +518,7 @@ void AigerReader::parse_aiger_ascii()
|
|||
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||
if (!(f >> l1 >> l2))
|
||||
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));
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
|
@ -544,7 +555,7 @@ void AigerReader::parse_aiger_ascii()
|
|||
if (!(f >> l1))
|
||||
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 bool invert = l1 & 1;
|
||||
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))
|
||||
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);
|
||||
wire->port_output = true;
|
||||
bad_properties.push_back(wire);
|
||||
|
@ -588,7 +599,7 @@ void AigerReader::parse_aiger_ascii()
|
|||
if (!(f >> l1 >> l2 >> l3))
|
||||
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));
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
|
@ -614,7 +625,7 @@ void AigerReader::parse_aiger_binary()
|
|||
|
||||
// Parse inputs
|
||||
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);
|
||||
wire->port_input = true;
|
||||
log_assert(!wire->port_output);
|
||||
|
@ -626,7 +637,7 @@ void AigerReader::parse_aiger_binary()
|
|||
if (L > 0 && !clk_name.empty()) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
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->port_input = true;
|
||||
clk_wire->port_output = false;
|
||||
|
@ -671,7 +682,7 @@ void AigerReader::parse_aiger_binary()
|
|||
if (!(f >> l1))
|
||||
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 bool invert = l1 & 1;
|
||||
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))
|
||||
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);
|
||||
wire->port_output = true;
|
||||
bad_properties.push_back(wire);
|
||||
|
@ -719,7 +730,7 @@ void AigerReader::parse_aiger_binary()
|
|||
l2 = parse_next_delta_literal(f, l1);
|
||||
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));
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
|
@ -730,7 +741,7 @@ void AigerReader::parse_aiger_binary()
|
|||
|
||||
void AigerReader::post_process()
|
||||
{
|
||||
pool<RTLIL::Module*> abc_carry_modules;
|
||||
pool<IdString> seen_boxes;
|
||||
unsigned ci_count = 0, co_count = 0, flop_count = 0;
|
||||
for (auto cell : boxes) {
|
||||
RTLIL::Module* box_module = design->module(cell->type);
|
||||
|
@ -745,38 +756,44 @@ void AigerReader::post_process()
|
|||
log_assert(flop_module);
|
||||
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)) {
|
||||
RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
|
||||
RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
|
||||
for (const auto &port_name : box_module->ports) {
|
||||
RTLIL::Wire* w = box_module->wire(port_name);
|
||||
log_assert(w);
|
||||
if (w->port_input) {
|
||||
if (w->attributes.count("\\abc_carry_in")) {
|
||||
log_assert(!carry_in);
|
||||
carry_in = w;
|
||||
}
|
||||
log_assert(!last_in || last_in->port_id < w->port_id);
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (seen_boxes.insert(cell->type).second) {
|
||||
auto it = box_module->attributes.find("\\abc_carry");
|
||||
if (it != box_module->attributes.end()) {
|
||||
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
|
||||
auto carry_in_out = it->second.decode_string();
|
||||
auto pos = carry_in_out.find(',');
|
||||
if (pos == std::string::npos)
|
||||
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
|
||||
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
|
||||
carry_in = box_module->wire(carry_in_name);
|
||||
if (!carry_in || !carry_in->port_input)
|
||||
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());
|
||||
|
||||
if (carry_in != last_in) {
|
||||
std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]);
|
||||
std::swap(carry_in->port_id, last_in->port_id);
|
||||
}
|
||||
if (carry_out != last_out) {
|
||||
log_assert(last_out);
|
||||
std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]);
|
||||
std::swap(carry_out->port_id, last_out->port_id);
|
||||
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
|
||||
carry_out = box_module->wire(carry_out_name);
|
||||
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());
|
||||
|
||||
auto &ports = box_module->ports;
|
||||
for (auto jt = ports.begin(); jt != ports.end(); ) {
|
||||
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];
|
||||
log_assert(wire);
|
||||
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) {
|
||||
// Cope with the fact that a CO might be identical
|
||||
|
@ -988,10 +1008,15 @@ void AigerReader::post_process()
|
|||
if (other_wire) {
|
||||
other_wire->port_input = false;
|
||||
other_wire->port_output = false;
|
||||
if (wire->port_input)
|
||||
}
|
||||
if (wire->port_input) {
|
||||
if (other_wire)
|
||||
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)
|
||||
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_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;
|
||||
std::map<std::string, AstNode*> current_scope;
|
||||
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->noopt = flag_noopt;
|
||||
current_module->icells = flag_icells;
|
||||
current_module->pwires = flag_pwires;
|
||||
current_module->autowire = flag_autowire;
|
||||
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'
|
||||
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;
|
||||
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_noopt = noopt;
|
||||
flag_icells = icells;
|
||||
flag_pwires = pwires;
|
||||
flag_autowire = autowire;
|
||||
|
||||
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_noopt = noopt;
|
||||
flag_icells = icells;
|
||||
flag_pwires = pwires;
|
||||
flag_autowire = autowire;
|
||||
use_internal_line_num();
|
||||
|
||||
|
@ -1551,6 +1554,7 @@ RTLIL::Module *AstModule::clone() const
|
|||
new_mod->lib = lib;
|
||||
new_mod->noopt = noopt;
|
||||
new_mod->icells = icells;
|
||||
new_mod->pwires = pwires;
|
||||
new_mod->autowire = autowire;
|
||||
|
||||
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
|
||||
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
|
||||
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||
struct AstModule : RTLIL::Module {
|
||||
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;
|
||||
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;
|
||||
|
@ -325,7 +325,7 @@ namespace AST_INTERNAL
|
|||
{
|
||||
// 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_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 std::map<std::string, AST::AstNode*> current_scope;
|
||||
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_DPI_FUNCTION:
|
||||
case AST_AUTOWIRE:
|
||||
case AST_LOCALPARAM:
|
||||
case AST_DEFPARAM:
|
||||
case AST_GENVAR:
|
||||
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
|
||||
case AST_PARAMETER:
|
||||
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;
|
||||
|
||||
// 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)
|
||||
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") {
|
||||
port_wire->port_input = true;
|
||||
} else
|
||||
|
@ -372,6 +384,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
if (wire == nullptr)
|
||||
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++)
|
||||
{
|
||||
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) {
|
||||
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",
|
||||
current_filename.c_str(), get_line_num());
|
||||
return ret;
|
||||
|
@ -204,7 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
{
|
||||
std::vector<RTLIL::State> data;
|
||||
bool is_signed = false;
|
||||
bool is_unsized = false;
|
||||
bool is_unsized = len_in_bits < 0;
|
||||
if (*(endptr+1) == 's') {
|
||||
is_signed = true;
|
||||
endptr++;
|
||||
|
@ -213,25 +213,25 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
char next_char = char(tolower(*(endptr+1)));
|
||||
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;
|
||||
my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -168,6 +168,9 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" -icells\n");
|
||||
log(" interpret cell types starting with '$' as internal cell types\n");
|
||||
log("\n");
|
||||
log(" -pwires\n");
|
||||
log(" add a wire for each module parameter\n");
|
||||
log("\n");
|
||||
log(" -nooverwrite\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");
|
||||
|
@ -228,6 +231,7 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_nodpi = false;
|
||||
bool flag_noopt = false;
|
||||
bool flag_icells = false;
|
||||
bool flag_pwires = false;
|
||||
bool flag_nooverwrite = false;
|
||||
bool flag_overwrite = false;
|
||||
bool flag_defer = false;
|
||||
|
@ -368,6 +372,10 @@ struct VerilogFrontend : public Frontend {
|
|||
flag_icells = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-pwires") {
|
||||
flag_pwires = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
|
||||
flag_nooverwrite = true;
|
||||
flag_overwrite = false;
|
||||
|
@ -458,7 +466,7 @@ struct VerilogFrontend : public Frontend {
|
|||
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,
|
||||
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)
|
||||
delete lexin;
|
||||
|
|
|
@ -313,7 +313,7 @@ supply1 { return TOK_SUPPLY1; }
|
|||
|
||||
"$"(info|warning|error|fatal) {
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
return TOK_ELAB_TASK;
|
||||
return TOK_MSG_TASKS;
|
||||
}
|
||||
|
||||
"$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_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 ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
|
@ -319,15 +319,17 @@ module_para_list:
|
|||
|
||||
single_module_para:
|
||||
/* empty */ |
|
||||
TOK_PARAMETER {
|
||||
attr TOK_PARAMETER {
|
||||
if (astbuf1) delete astbuf1;
|
||||
astbuf1 = new AstNode(AST_PARAMETER);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
append_attr(astbuf1, $1);
|
||||
} param_signed param_integer param_range single_param_decl |
|
||||
TOK_LOCALPARAM {
|
||||
attr TOK_LOCALPARAM {
|
||||
if (astbuf1) delete astbuf1;
|
||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
append_attr(astbuf1, $1);
|
||||
} param_signed param_integer param_range 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) {
|
||||
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||
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))));
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
|
||||
|
@ -509,6 +517,7 @@ wire_type_token:
|
|||
TOK_GENVAR {
|
||||
astbuf3->type = AST_GENVAR;
|
||||
astbuf3->is_reg = true;
|
||||
astbuf3->is_signed = true;
|
||||
astbuf3->range_left = 31;
|
||||
astbuf3->range_right = 0;
|
||||
} |
|
||||
|
@ -1211,6 +1220,7 @@ param_decl:
|
|||
attr TOK_PARAMETER {
|
||||
astbuf1 = new AstNode(AST_PARAMETER);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
append_attr(astbuf1, $1);
|
||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||
delete astbuf1;
|
||||
};
|
||||
|
@ -1219,6 +1229,7 @@ localparam_decl:
|
|||
attr TOK_LOCALPARAM {
|
||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
append_attr(astbuf1, $1);
|
||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||
delete astbuf1;
|
||||
};
|
||||
|
@ -1360,7 +1371,12 @@ wire_name_and_opt_assign:
|
|||
wire_name '=' expr {
|
||||
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||
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))));
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3));
|
||||
|
@ -1385,7 +1401,13 @@ wire_name:
|
|||
node->children.push_back(rng);
|
||||
}
|
||||
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 (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 ';'{
|
||||
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 {
|
||||
AstNode *node = new AstNode(AST_BLOCK);
|
||||
ast_stack.back()->children.push_back(node);
|
||||
|
@ -2177,7 +2209,7 @@ gen_stmt:
|
|||
delete $6;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
TOK_ELAB_TASK {
|
||||
TOK_MSG_TASKS {
|
||||
AstNode *node = new AstNode(AST_TECALL);
|
||||
node->str = *$1;
|
||||
delete $1;
|
||||
|
|
|
@ -246,24 +246,24 @@ struct CellTypes
|
|||
cell_types.clear();
|
||||
}
|
||||
|
||||
bool cell_known(RTLIL::IdString type)
|
||||
bool cell_known(RTLIL::IdString type) const
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return it != cell_types.end() && it->second.is_evaluable;
|
||||
|
@ -482,4 +482,3 @@ extern CellTypes yosys_celltypes;
|
|||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -545,6 +545,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
|
|||
}
|
||||
|
||||
filename = arg;
|
||||
rewrite_filename(filename);
|
||||
std::ofstream *ff = new std::ofstream;
|
||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||
yosys_output_files.insert(filename);
|
||||
|
|
|
@ -1381,7 +1381,34 @@ void RTLIL::Module::check()
|
|||
for (auto &it : processes) {
|
||||
log_assert(it.first == it.second->name);
|
||||
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_) {
|
||||
|
@ -1565,21 +1592,13 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
|||
|
||||
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())
|
||||
cell->unsetPort(cell->connections_.begin()->first);
|
||||
|
||||
log_assert(cells_.count(cell->name) != 0);
|
||||
log_assert(refcount_cells_ == 0);
|
||||
it = cells_.erase(it);
|
||||
cells_.erase(cell->name);
|
||||
delete cell;
|
||||
return it;
|
||||
}
|
||||
|
||||
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.
|
||||
void remove(const pool<RTLIL::Wire*> &wires);
|
||||
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::Cell *cell, RTLIL::IdString new_name);
|
||||
|
|
|
@ -651,6 +651,10 @@ void rewrite_filename(std::string &filename)
|
|||
filename = filename.substr(1, GetSize(filename)-2);
|
||||
if (filename.substr(0, 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
|
||||
|
|
|
@ -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
|
||||
\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
|
||||
a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}.
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ USING_YOSYS_NAMESPACE
|
|||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
{
|
||||
// |---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("\n");
|
||||
log(" -tech <technology>\n");
|
||||
log(" print area estemate for the specified technology. Corrently supported\n");
|
||||
log(" calues for <technology>: xilinx\n");
|
||||
log(" print area estemate for the specified technology. Currently supported\n");
|
||||
log(" values for <technology>: xilinx\n");
|
||||
log("\n");
|
||||
log(" -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)
|
||||
output_filename = args[argidx++];
|
||||
else
|
||||
log_cmd_error("Missing putput filename.\n");
|
||||
log_cmd_error("Missing output filename.\n");
|
||||
|
||||
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(" option disables this behavior.\n");
|
||||
log("\n");
|
||||
log(" -nodefaults\n");
|
||||
log(" do not resolve input port default values\n");
|
||||
log("\n");
|
||||
log(" -nokeep_asserts\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");
|
||||
|
@ -645,6 +648,7 @@ struct HierarchyPass : public Pass {
|
|||
bool generate_mode = false;
|
||||
bool keep_positionals = false;
|
||||
bool keep_portwidths = false;
|
||||
bool nodefaults = false;
|
||||
bool nokeep_asserts = false;
|
||||
std::vector<std::string> generate_cells;
|
||||
std::vector<generate_port_decl_t> generate_ports;
|
||||
|
@ -712,6 +716,10 @@ struct HierarchyPass : public Pass {
|
|||
keep_portwidths = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodefaults") {
|
||||
nodefaults = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nokeep_asserts") {
|
||||
nokeep_asserts = true;
|
||||
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::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))
|
||||
{
|
||||
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);
|
||||
SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
|
||||
RTLIL::SigSpec en;
|
||||
RTLIL::SigSpec check_q;
|
||||
|
||||
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)
|
||||
if (sigbit_users_count[bit] > 1)
|
||||
goto skip_ff_after_read_merging;
|
||||
|
@ -195,7 +201,7 @@ struct MemoryDffWorker
|
|||
{
|
||||
disconnect_dff(sig_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->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
|
||||
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/opt_lut.o
|
||||
OBJS += passes/opt/pmux2shiftx.o
|
||||
OBJS += passes/opt/muxpack.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -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_reduce [-fine] [-full]\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_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
||||
log(" while <changed design>\n");
|
||||
|
@ -54,7 +54,7 @@ struct OptPass : public Pass {
|
|||
log(" do\n");
|
||||
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
|
||||
log(" opt_merge [-share_all]\n");
|
||||
log(" opt_rmdff [-keepdc]\n");
|
||||
log(" opt_rmdff [-keepdc] [-sat]\n");
|
||||
log(" opt_clean [-purge]\n");
|
||||
log(" while <changed design in opt_rmdff>\n");
|
||||
log("\n");
|
||||
|
@ -112,6 +112,10 @@ struct OptPass : public Pass {
|
|||
opt_rmdff_args += " -keepdc";
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sat") {
|
||||
opt_rmdff_args += " -sat";
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-share_all") {
|
||||
opt_merge_args += " -share_all";
|
||||
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()) {
|
||||
// do not delete anything with "keep" or module ports or initialized wires
|
||||
} else
|
||||
if (!purge_mode && check_public_name(wire->name)) {
|
||||
// do not get rid of public names unless in purge mode
|
||||
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 or if the wire is entirely unused, not even aliased
|
||||
} else
|
||||
if (!raw_used_signals.check_any(s1)) {
|
||||
// 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;
|
||||
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();
|
||||
RTLIL::SigSpec a = cell->getPort("\\A");
|
||||
RTLIL::SigSpec y = cell->getPort("\\Y");
|
||||
|
|
|
@ -17,19 +17,24 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.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 <stdlib.h>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
SigMap assign_map, dff_init_map;
|
||||
SigSet<RTLIL::Cell*> mux_drivers;
|
||||
dict<SigBit, RTLIL::Cell*> bit2driver;
|
||||
dict<SigBit, pool<SigBit>> init_attributes;
|
||||
|
||||
bool keepdc;
|
||||
bool sat;
|
||||
|
||||
void remove_init_attr(SigSpec sig)
|
||||
{
|
||||
|
@ -452,12 +457,84 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
|||
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;
|
||||
|
||||
delete_dff:
|
||||
log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
|
||||
remove_init_attr(dff->getPort("\\Q"));
|
||||
mod->remove(dff);
|
||||
|
||||
for (auto &entry : bit2driver)
|
||||
if (entry.second == dff)
|
||||
bit2driver.erase(entry.first);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -467,11 +544,15 @@ struct OptRmdffPass : public Pass {
|
|||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" opt_rmdff [-keepdc] [selection]\n");
|
||||
log(" opt_rmdff [-keepdc] [-sat] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass identifies flip-flops with constant inputs and replaces them with\n");
|
||||
log("a constant driver.\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
|
||||
{
|
||||
|
@ -479,6 +560,7 @@ struct OptRmdffPass : public Pass {
|
|||
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
|
||||
|
||||
keepdc = false;
|
||||
sat = false;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
|
@ -486,18 +568,22 @@ struct OptRmdffPass : public Pass {
|
|||
keepdc = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-sat") {
|
||||
sat = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules())
|
||||
{
|
||||
for (auto module : design->selected_modules()) {
|
||||
pool<SigBit> driven_bits;
|
||||
dict<SigBit, State> init_bits;
|
||||
|
||||
assign_map.set(module);
|
||||
dff_init_map.set(module);
|
||||
mux_drivers.clear();
|
||||
bit2driver.clear();
|
||||
init_attributes.clear();
|
||||
|
||||
for (auto wire : module->wires())
|
||||
|
@ -522,17 +608,21 @@ struct OptRmdffPass : public Pass {
|
|||
driven_bits.insert(bit);
|
||||
}
|
||||
}
|
||||
mux_drivers.clear();
|
||||
|
||||
std::vector<RTLIL::IdString> dff_list;
|
||||
std::vector<RTLIL::IdString> dffsr_list;
|
||||
std::vector<RTLIL::IdString> dlatch_list;
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
for (auto &conn : cell->connections())
|
||||
if (cell->output(conn.first) || !cell->known())
|
||||
for (auto bit : assign_map(conn.second))
|
||||
for (auto &conn : cell->connections()) {
|
||||
bool is_output = cell->output(conn.first);
|
||||
if (is_output || !cell->known())
|
||||
for (auto bit : assign_map(conn.second)) {
|
||||
if (is_output)
|
||||
bit2driver[bit] = cell;
|
||||
driven_bits.insert(bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (cell->type == "$mux" || cell->type == "$pmux") {
|
||||
if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
|
||||
|
@ -604,6 +694,7 @@ struct OptRmdffPass : public Pass {
|
|||
|
||||
assign_map.clear();
|
||||
mux_drivers.clear();
|
||||
bit2driver.clear();
|
||||
init_attributes.clear();
|
||||
|
||||
if (total_count || total_initdrv)
|
||||
|
|
|
@ -221,6 +221,9 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
log(" select strategy for one-hot encoded control signals\n");
|
||||
log(" default: pmux\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
|
||||
{
|
||||
|
@ -230,6 +233,7 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
bool optimize_onehot = true;
|
||||
bool verbose = false;
|
||||
bool verbose_onehot = false;
|
||||
bool norange = false;
|
||||
|
||||
log_header(design, "Executing PMUX2SHIFTX pass.\n");
|
||||
|
||||
|
@ -270,6 +274,10 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
verbose_onehot = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-norange") {
|
||||
norange = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -559,7 +567,7 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
int this_inv_delta = this_maxval - this_minval;
|
||||
bool this_inv = false;
|
||||
|
||||
if (this_delta != this_inv_delta)
|
||||
if (!norange && this_delta != this_inv_delta)
|
||||
this_inv = this_inv_delta < this_delta;
|
||||
else if (this_maxval != this_inv_maxval)
|
||||
this_inv = this_inv_maxval < this_maxval;
|
||||
|
@ -574,7 +582,7 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
|
||||
if (best_src_col < 0)
|
||||
this_is_better = true;
|
||||
else if (this_delta != best_delta)
|
||||
else if (!norange && this_delta != best_delta)
|
||||
this_is_better = this_delta < best_delta;
|
||||
else if (this_maxval != best_maxval)
|
||||
this_is_better = this_maxval < best_maxval;
|
||||
|
@ -656,7 +664,7 @@ struct Pmux2ShiftxPass : public Pass {
|
|||
|
||||
// check density percentages
|
||||
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));
|
||||
log(" offset: %s\n", log_signal(offset));
|
||||
|
|
|
@ -180,7 +180,7 @@ struct AssertpmuxWorker
|
|||
};
|
||||
|
||||
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
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
|
@ -195,8 +195,8 @@ struct AssertpmuxPass : public Pass {
|
|||
log("\n");
|
||||
log(" -always\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(" additional constrained and check the $pmux condition always.\n");
|
||||
log(" is used by the mux tree it drives. this option will deactivate this\n");
|
||||
log(" additional constraint and check the $pmux condition always.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
|
|
|
@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE
|
|||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
{
|
||||
// |---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)
|
||||
{
|
||||
rewrite_filename(vcd_file_name);
|
||||
FILE *f = fopen(vcd_file_name.c_str(), "w");
|
||||
if (!f)
|
||||
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)
|
||||
{
|
||||
rewrite_filename(json_file_name);
|
||||
FILE *f = fopen(json_file_name.c_str(), "w");
|
||||
if (!f)
|
||||
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())
|
||||
{
|
||||
rewrite_filename(cnf_file_name);
|
||||
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
||||
if (!f)
|
||||
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())
|
||||
{
|
||||
rewrite_filename(cnf_file_name);
|
||||
FILE *f = fopen(cnf_file_name.c_str(), "w");
|
||||
if (!f)
|
||||
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
|
||||
ifneq ($(ABCEXTERNAL),)
|
||||
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#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/sigtools.h"
|
||||
|
@ -80,8 +80,7 @@ void handle_loops(RTLIL::Design *design)
|
|||
{
|
||||
Pass::call(design, "scc -set_attr abc_scc_id {}");
|
||||
|
||||
design->selection_stack.emplace_back(false);
|
||||
RTLIL::Selection& sel = design->selection_stack.back();
|
||||
dict<IdString, vector<IdString>> abc_scc_break;
|
||||
|
||||
// For every unique SCC found, (arbitrarily) find the first
|
||||
// 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()) {
|
||||
auto r = ids_seen.insert(it->second);
|
||||
if (r.second) {
|
||||
for (const auto &c : cell->connections()) {
|
||||
for (auto &c : cell->connections_) {
|
||||
if (c.second.is_fully_const()) continue;
|
||||
if (cell->output(c.first)) {
|
||||
SigBit b = c.second.as_bit();
|
||||
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");
|
||||
sel.select(module, w);
|
||||
module->swap_names(b.wire, w);
|
||||
c.second = RTLIL::SigBit(w, b.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
Pass::call(design, "expose -cut -sep .abc");
|
||||
|
||||
design->selection_stack.pop_back();
|
||||
module->fixup_ports();
|
||||
}
|
||||
|
||||
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();
|
||||
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");
|
||||
|
||||
handle_loops(design);
|
||||
|
@ -409,7 +453,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
reader.parse_xaiger();
|
||||
}
|
||||
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__"));
|
||||
#endif
|
||||
|
||||
|
@ -482,7 +526,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
ifs.close();
|
||||
|
||||
#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
|
||||
|
||||
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) {
|
||||
RTLIL::Wire *wire = module->wire(w->name);
|
||||
log_assert(wire);
|
||||
for (int i = 0; i < GetSize(wire); i++)
|
||||
for (int i = 0; i < GetSize(w); 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);
|
||||
}
|
||||
|
||||
dict<IdString, bool> abc_box;
|
||||
vector<RTLIL::Cell*> boxes;
|
||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
|
||||
RTLIL::Cell* cell = it->second;
|
||||
if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) {
|
||||
it = module->remove(it);
|
||||
for (const auto &it : module->cells_) {
|
||||
auto cell = it.second;
|
||||
if (cell->type.in("$_AND_", "$_NOT_")) {
|
||||
module->remove(cell);
|
||||
continue;
|
||||
}
|
||||
RTLIL::Module* box_module = design->module(cell->type);
|
||||
if (box_module && box_module->attributes.count("\\abc_box_id"))
|
||||
auto jt = abc_box.find(cell->type);
|
||||
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);
|
||||
++it;
|
||||
}
|
||||
|
||||
std::map<std::string, int> cell_stats;
|
||||
for (auto c : mapped_mod->cells())
|
||||
{
|
||||
RTLIL::Cell *cell = nullptr;
|
||||
if (c->type == "$_NOT_") {
|
||||
RTLIL::Cell *cell;
|
||||
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
|
||||
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
|
||||
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_stats[RTLIL::unescape_id(c->type)]++;
|
||||
}
|
||||
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
||||
if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
|
||||
continue;
|
||||
}
|
||||
cell_stats[RTLIL::unescape_id(c->type)]++;
|
||||
|
||||
RTLIL::Cell *existing_cell = nullptr;
|
||||
if (c->type == "$lut") {
|
||||
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)];
|
||||
|
@ -602,19 +651,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
|||
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
|
||||
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;
|
||||
RTLIL::Cell *existing_cell = module->cell(c->name);
|
||||
if (existing_cell) {
|
||||
cell->parameters = existing_cell->parameters;
|
||||
cell->attributes = existing_cell->attributes;
|
||||
}
|
||||
else {
|
||||
cell->parameters = c->parameters;
|
||||
cell->attributes = c->attributes;
|
||||
}
|
||||
if (existing_cell) {
|
||||
cell->parameters = existing_cell->parameters;
|
||||
cell->attributes = existing_cell->attributes;
|
||||
}
|
||||
else {
|
||||
cell->parameters = c->parameters;
|
||||
cell->attributes = c->attributes;
|
||||
}
|
||||
for (auto &conn : c->connections()) {
|
||||
RTLIL::SigSpec newsig;
|
||||
for (auto c : conn.second.chunks()) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#define COST_DMUX 90
|
||||
#define COST_MUX2 100
|
||||
#define COST_MUX4 220
|
||||
#define COST_MUX8 460
|
||||
|
@ -57,7 +58,9 @@ struct MuxcoverWorker
|
|||
bool use_mux8;
|
||||
bool use_mux16;
|
||||
bool nodecode;
|
||||
bool nopartial;
|
||||
|
||||
int cost_dmux;
|
||||
int cost_mux2;
|
||||
int cost_mux4;
|
||||
int cost_mux8;
|
||||
|
@ -69,6 +72,8 @@ struct MuxcoverWorker
|
|||
use_mux8 = false;
|
||||
use_mux16 = false;
|
||||
nodecode = false;
|
||||
nopartial = false;
|
||||
cost_dmux = COST_DMUX;
|
||||
cost_mux2 = COST_MUX2;
|
||||
cost_mux4 = COST_MUX4;
|
||||
cost_mux8 = COST_MUX8;
|
||||
|
@ -76,6 +81,23 @@ struct MuxcoverWorker
|
|||
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()
|
||||
{
|
||||
pool<SigBit> roots;
|
||||
|
@ -133,13 +155,22 @@ struct MuxcoverWorker
|
|||
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 (tree.muxes.count(bit) == 0)
|
||||
return false;
|
||||
if (tree.muxes.count(bit) == 0) {
|
||||
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};
|
||||
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 {
|
||||
ret_bit = bit;
|
||||
return true;
|
||||
|
@ -148,7 +179,7 @@ struct MuxcoverWorker
|
|||
|
||||
int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit)
|
||||
{
|
||||
if (A == B)
|
||||
if (A == B || sel == State::Sx)
|
||||
return 0;
|
||||
|
||||
tuple<SigBit, SigBit, SigBit> key(A, B, sel);
|
||||
|
@ -166,7 +197,10 @@ struct MuxcoverWorker
|
|||
if (std::get<2>(entry))
|
||||
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)
|
||||
|
@ -183,9 +217,32 @@ struct MuxcoverWorker
|
|||
implement_decode_mux(std::get<0>(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;
|
||||
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)
|
||||
|
@ -218,9 +275,13 @@ struct MuxcoverWorker
|
|||
mux.inputs.push_back(B);
|
||||
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 += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
mux.cost += sum_best_covers(tree, mux.inputs);
|
||||
|
||||
log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost);
|
||||
|
||||
best_mux = mux;
|
||||
}
|
||||
|
@ -238,7 +299,7 @@ struct MuxcoverWorker
|
|||
ok = ok && follow_muxtree(S2, tree, bit, "BS");
|
||||
|
||||
if (nodecode)
|
||||
ok = ok && S1 == S2;
|
||||
ok = ok && xcmp({S1, S2});
|
||||
|
||||
ok = ok && follow_muxtree(T1, tree, bit, "S");
|
||||
|
||||
|
@ -256,13 +317,15 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(S1);
|
||||
mux.selects.push_back(T1);
|
||||
|
||||
mux.cost += cost_mux4;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
mux.cost += find_best_cover(tree, B);
|
||||
mux.cost += find_best_cover(tree, C);
|
||||
mux.cost += find_best_cover(tree, D);
|
||||
find_best_covers(tree, mux.inputs);
|
||||
log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -286,13 +349,13 @@ struct MuxcoverWorker
|
|||
ok = ok && follow_muxtree(S4, tree, bit, "BBS");
|
||||
|
||||
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(T2, tree, bit, "BS");
|
||||
|
||||
if (nodecode)
|
||||
ok = ok && T1 == T2;
|
||||
ok = ok && xcmp({T1, T2});
|
||||
|
||||
ok = ok && follow_muxtree(U1, tree, bit, "S");
|
||||
|
||||
|
@ -319,17 +382,15 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(T1);
|
||||
mux.selects.push_back(U1);
|
||||
|
||||
mux.cost += cost_mux8;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
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);
|
||||
find_best_covers(tree, mux.inputs);
|
||||
log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +426,7 @@ struct MuxcoverWorker
|
|||
ok = ok && follow_muxtree(S8, tree, bit, "BBBS");
|
||||
|
||||
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(T2, tree, bit, "ABS");
|
||||
|
@ -373,13 +434,13 @@ struct MuxcoverWorker
|
|||
ok = ok && follow_muxtree(T4, tree, bit, "BBS");
|
||||
|
||||
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(U2, tree, bit, "BS");
|
||||
|
||||
if (nodecode)
|
||||
ok = ok && U1 == U2;
|
||||
ok = ok && xcmp({U1, U2});
|
||||
|
||||
ok = ok && follow_muxtree(V1, tree, bit, "S");
|
||||
|
||||
|
@ -423,25 +484,15 @@ struct MuxcoverWorker
|
|||
mux.selects.push_back(U1);
|
||||
mux.selects.push_back(V1);
|
||||
|
||||
mux.cost += cost_mux16;
|
||||
mux.cost += find_best_cover(tree, A);
|
||||
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);
|
||||
find_best_covers(tree, mux.inputs);
|
||||
log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -537,6 +588,7 @@ struct MuxcoverWorker
|
|||
void treecover(tree_t &tree)
|
||||
{
|
||||
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);
|
||||
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),
|
||||
|
@ -553,12 +605,13 @@ struct MuxcoverWorker
|
|||
|
||||
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) {
|
||||
find_best_cover(tree, tree.root);
|
||||
tree.newmuxes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &tree : tree_list)
|
||||
treecover(tree);
|
||||
|
@ -584,11 +637,19 @@ struct MuxcoverPass : public Pass {
|
|||
log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
|
||||
log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
|
||||
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(" Do not insert decoder logic. This reduces the number of possible\n");
|
||||
log(" substitutions, but guarantees that the resulting circuit is not\n");
|
||||
log(" less efficient than the original circuit.\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
|
||||
{
|
||||
|
@ -598,6 +659,8 @@ struct MuxcoverPass : public Pass {
|
|||
bool use_mux8 = false;
|
||||
bool use_mux16 = false;
|
||||
bool nodecode = false;
|
||||
bool nopartial = false;
|
||||
int cost_dmux = COST_DMUX;
|
||||
int cost_mux4 = COST_MUX4;
|
||||
int cost_mux8 = COST_MUX8;
|
||||
int cost_mux16 = COST_MUX16;
|
||||
|
@ -610,7 +673,7 @@ struct MuxcoverPass : public Pass {
|
|||
use_mux4 = true;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux4 = atoi(arg.substr(5).c_str());
|
||||
cost_mux4 = atoi(arg.substr(6).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -618,7 +681,7 @@ struct MuxcoverPass : public Pass {
|
|||
use_mux8 = true;
|
||||
if (arg.size() > 5) {
|
||||
if (arg[5] != '=') break;
|
||||
cost_mux8 = atoi(arg.substr(5).c_str());
|
||||
cost_mux8 = atoi(arg.substr(6).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -626,14 +689,22 @@ struct MuxcoverPass : public Pass {
|
|||
use_mux16 = true;
|
||||
if (arg.size() > 6) {
|
||||
if (arg[6] != '=') break;
|
||||
cost_mux16 = atoi(arg.substr(6).c_str());
|
||||
cost_mux16 = atoi(arg.substr(7).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") {
|
||||
cost_dmux = atoi(arg.substr(6).c_str());
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nodecode") {
|
||||
nodecode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nopartial") {
|
||||
nopartial = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -650,10 +721,12 @@ struct MuxcoverPass : public Pass {
|
|||
worker.use_mux4 = use_mux4;
|
||||
worker.use_mux8 = use_mux8;
|
||||
worker.use_mux16 = use_mux16;
|
||||
worker.cost_dmux = cost_dmux;
|
||||
worker.cost_mux4 = cost_mux4;
|
||||
worker.cost_mux8 = cost_mux8;
|
||||
worker.cost_mux16 = cost_mux16;
|
||||
worker.nodecode = nodecode;
|
||||
worker.nopartial = nopartial;
|
||||
worker.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -293,10 +293,22 @@ struct ShregmapWorker
|
|||
|
||||
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);
|
||||
} else
|
||||
sigbit_chain_next[d_bit] = cell;
|
||||
// ... and clone d_bit into another wire, and use that
|
||||
// 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;
|
||||
continue;
|
||||
|
@ -605,9 +617,11 @@ struct ShregmapPass : public Pass {
|
|||
log("\n");
|
||||
log(" -tech greenpak4\n");
|
||||
log(" map to greenpak4 shift registers.\n");
|
||||
log(" this option also implies -clkpol pos -zinit\n");
|
||||
log("\n");
|
||||
log(" -tech xilinx\n");
|
||||
log(" map to xilinx dynamic-length shift registers.\n");
|
||||
log(" this option also implies -params -init\n");
|
||||
log("\n");
|
||||
}
|
||||
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.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
|
||||
.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)
|
||||
# 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
|
||||
CCU2C 1 1 9 3
|
||||
|
||||
|
@ -9,7 +16,7 @@ CCU2C 1 1 9 3
|
|||
516 516 516 516 412 412 278 278 43
|
||||
|
||||
# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram)
|
||||
# Outputs: DO0, DO1, DO2, DO3, DO4
|
||||
# Outputs: DO0, DO1, DO2, DO3
|
||||
# name ID w/b ins outs
|
||||
TRELLIS_DPR16X4 2 0 14 4
|
||||
|
||||
|
|
|
@ -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] 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] FCO, Y1;
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
|
||||
CCU2C #(
|
||||
.INIT0(16'b0110011010101010),
|
||||
.INIT1(16'b0110011010101010),
|
||||
.INIT0(16'b1001011010101010),
|
||||
.INIT1(16'b1001011010101010),
|
||||
.INJECT1_0("NO"),
|
||||
.INJECT1_1("NO")
|
||||
) ccu2c_i (
|
||||
.CIN(C[i]),
|
||||
.A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1),
|
||||
.A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1),
|
||||
.A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1),
|
||||
.A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1),
|
||||
.S0(Y[i]), .S1(Y1[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_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
|
||||
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
|
||||
|
@ -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 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
|
||||
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
|
||||
// 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")) _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
|
||||
module \$lut (A, Y);
|
||||
parameter WIDTH = 0;
|
||||
parameter LUT = 0;
|
||||
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
|
||||
// Need to swap input ordering, and fix init accordingly,
|
||||
// to match ABC's expectation of LUT inputs in non-decreasing
|
||||
|
@ -86,19 +124,15 @@ module \$lut (A, Y);
|
|||
endfunction
|
||||
|
||||
function [2**P_WIDTH-1:0] permute_init;
|
||||
input [2**P_WIDTH-1:0] orig;
|
||||
integer i;
|
||||
begin
|
||||
permute_init = 0;
|
||||
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
|
||||
endfunction
|
||||
|
||||
parameter [2**P_WIDTH-1:0] P_LUT = permute_init(LUT);
|
||||
|
||||
input [WIDTH-1:0] A;
|
||||
output Y;
|
||||
parameter [2**P_WIDTH-1:0] P_LUT = permute_init();
|
||||
|
||||
generate
|
||||
if (WIDTH == 1) begin
|
||||
|
|
|
@ -15,11 +15,9 @@ module L6MUX21 (input D0, D1, SD, output Z);
|
|||
endmodule
|
||||
|
||||
// ---------------------------------------
|
||||
(* abc_box_id=1, abc_carry, lib_whitebox *)
|
||||
module CCU2C((* abc_carry_in *) input CIN,
|
||||
input A0, B0, C0, D0, A1, B1, C1, D1,
|
||||
output S0, S1,
|
||||
(* abc_carry_out *) output COUT);
|
||||
(* abc_box_id=1, abc_carry="CIN,COUT", lib_whitebox *)
|
||||
module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
|
||||
output S0, S1, COUT);
|
||||
|
||||
parameter [15:0] INIT0 = 16'h0000;
|
||||
parameter [15:0] INIT1 = 16'h0000;
|
||||
|
@ -106,7 +104,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
|
|||
endmodule
|
||||
|
||||
// ---------------------------------------
|
||||
//(* abc_box_id=2 *)
|
||||
//(* abc_box_id=2, abc_scc_break="DI,WAD,WRE" *)
|
||||
module TRELLIS_DPR16X4 (
|
||||
input [3:0] DI,
|
||||
input [3:0] WAD,
|
||||
|
@ -260,18 +258,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
|
|||
endgenerate
|
||||
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 *)
|
||||
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);
|
||||
assign Z = !A;
|
||||
endmodule
|
||||
|
@ -568,19 +541,56 @@ module DP16KD(
|
|||
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
|
||||
endmodule
|
||||
|
||||
// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
|
||||
module FD1S3BX(input PD, D, CK, output Q);
|
||||
TRELLIS_FF #(
|
||||
.GSR("DISABLED"),
|
||||
.CEMUX("1"),
|
||||
.CLKMUX("CLK"),
|
||||
.LSRMUX("LSR"),
|
||||
.REGSET("SET"),
|
||||
.SRMODE("ASYNC")
|
||||
) tff_i (
|
||||
.CLK(CK),
|
||||
.LSR(PD),
|
||||
.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")) tff (.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")) tff (.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")) tff (.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")) tff (.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
|
||||
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(" do not use distributed RAM cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nomux\n");
|
||||
log(" -nowidelut\n");
|
||||
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
||||
log("\n");
|
||||
log(" -abc2\n");
|
||||
|
@ -96,7 +96,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -108,7 +108,7 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
nodffe = false;
|
||||
nobram = false;
|
||||
nodram = false;
|
||||
nomux = false;
|
||||
nowidelut = false;
|
||||
flatten = true;
|
||||
retime = false;
|
||||
abc2 = false;
|
||||
|
@ -176,8 +176,8 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
nodram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nomux") {
|
||||
nomux = true;
|
||||
if (args[argidx] == "-nowidelut" || args[argidx] == "-nomux") {
|
||||
nowidelut = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-abc2") {
|
||||
|
@ -273,14 +273,16 @@ struct SynthEcp5Pass : public ScriptPass
|
|||
}
|
||||
run("techmap -map +/ecp5/latches_map.v");
|
||||
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 {
|
||||
if (nomux)
|
||||
if (nowidelut)
|
||||
run("abc -lut 4 -dress");
|
||||
else
|
||||
run("abc -lut 4:7 -dress");
|
||||
}
|
||||
|
||||
run("clean");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,113 +1,17 @@
|
|||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
|
||||
|
||||
# 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: I0 I1 CI
|
||||
# Outputs: CO
|
||||
SB_CARRY 21 1 3 1
|
||||
126 259 231
|
||||
# (NB: carry chain input/output must be last
|
||||
# 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
|
||||
# Outputs: O
|
||||
SB_LUT4 22 1 4 1
|
||||
SB_LUT4 2 1 4 1
|
||||
449 400 379 316
|
||||
|
|
|
@ -1,113 +1,17 @@
|
|||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
|
||||
|
||||
# NB: Inputs/Outputs must be ordered alphabetically
|
||||
|
||||
# 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
|
||||
- - - -
|
||||
# (with exceptions for carry in/out)
|
||||
|
||||
# Inputs: CI I0 I1
|
||||
# Outputs: CO
|
||||
SB_CARRY 21 1 3 1
|
||||
186 675 609
|
||||
# (NB: carry chain input/output must be last
|
||||
# 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
|
||||
# Outputs: O
|
||||
SB_LUT4 22 1 4 1
|
||||
SB_LUT4 2 1 4 1
|
||||
661 589 558 465
|
||||
|
|
|
@ -1,113 +1,17 @@
|
|||
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
|
||||
|
||||
# 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: I0 I1 CI
|
||||
# Outputs: CO
|
||||
SB_CARRY 21 1 3 1
|
||||
278 675 609
|
||||
# (NB: carry chain input/output must be last
|
||||
# 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
|
||||
# Outputs: O
|
||||
SB_LUT4 22 1 4 1
|
||||
SB_LUT4 2 1 4 1
|
||||
1285 1231 1205 874
|
||||
|
|
|
@ -127,7 +127,7 @@ endmodule
|
|||
|
||||
// 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);
|
||||
parameter [15:0] LUT_INIT = 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];
|
||||
endmodule
|
||||
|
||||
(* abc_box_id = 21, abc_carry, lib_whitebox *)
|
||||
module SB_CARRY ((* abc_carry_out *) output CO, input I0, I1, (* abc_carry_in *) input CI);
|
||||
(* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *)
|
||||
module SB_CARRY (output CO, input I0, I1, CI);
|
||||
assign CO = (I0 && I1) || ((I0 || I1) && CI);
|
||||
endmodule
|
||||
|
||||
// Positive Edge SiliconBlue FF Cells
|
||||
|
||||
module SB_DFF (output `SB_DFF_REG, input C, D);
|
||||
`ifndef _ABC
|
||||
always @(posedge C)
|
||||
Q <= D;
|
||||
`else
|
||||
always @* Q <= D;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
module SB_DFFE (output `SB_DFF_REG, input C, E, D);
|
||||
|
@ -896,7 +892,6 @@ module SB_WARMBOOT (
|
|||
);
|
||||
endmodule
|
||||
|
||||
(* nomem2reg *)
|
||||
module SB_SPRAM256KA (
|
||||
input [13:0] ADDRESS,
|
||||
input [15:0] DATAIN,
|
||||
|
|
|
@ -74,7 +74,7 @@ static void run_ice40_unlut(Module *module)
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
// |---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("\n");
|
||||
log(" -device < hx | lp | u >\n");
|
||||
log(" optimise the synthesis netlist for the specified device.\n");
|
||||
log(" HX is the default target if no device argument specified.\n");
|
||||
log(" relevant only for '-abc9' flow, optimise timing for the specified device.\n");
|
||||
log(" default: hx\n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module\n");
|
||||
|
@ -105,7 +105,6 @@ struct SynthIce40Pass : public ScriptPass
|
|||
log("\n");
|
||||
}
|
||||
|
||||
|
||||
string top_opt, blif_file, edif_file, json_file, abc, device_opt;
|
||||
bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
|
||||
int min_ce_use;
|
||||
|
@ -331,8 +330,16 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
|
||||
}
|
||||
if (!noabc) {
|
||||
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)");
|
||||
if (abc == "abc9") {
|
||||
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
|
||||
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/ff_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_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_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_32.vh))
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# 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
|
||||
# Inputs: I0 I1 S0
|
||||
# Outputs: O
|
||||
|
@ -12,34 +15,42 @@ MUXF8 2 1 3 1
|
|||
104 94 273
|
||||
|
||||
# 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
|
||||
# (NB: carry chain input/output must be last input/output,
|
||||
# swapped with what normally would have been the last
|
||||
# output, here: CI <-> S, CO <-> O
|
||||
# (NB: carry chain input/output must be last
|
||||
# input/output and the entire bus has been
|
||||
# moved there overriding the otherwise
|
||||
# alphabetical ordering)
|
||||
CARRY4 3 1 10 8
|
||||
223 - - - 482 - - - - 222
|
||||
400 205 - - 598 407 - - - 334
|
||||
523 558 226 - 584 556 537 - - 239
|
||||
582 618 330 227 642 615 596 438 - 313
|
||||
340 - - - 536 379 - - - 271
|
||||
433 469 - - 494 465 445 - - 157
|
||||
512 548 292 - 592 540 520 356 - 228
|
||||
508 528 378 380 580 526 507 398 385 114
|
||||
482 - - - - 223 - - - 222
|
||||
598 407 - - - 400 205 - - 334
|
||||
584 556 537 - - 523 558 226 - 239
|
||||
642 615 596 438 - 582 618 330 227 313
|
||||
536 379 - - - 340 - - - 271
|
||||
494 465 445 - - 433 469 - - 157
|
||||
592 540 520 356 - 512 548 292 - 228
|
||||
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
|
||||
# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
|
||||
# Outputs: DPO SPO
|
||||
RAM64X1D 4 0 15 2
|
||||
- - - - - - - 124 124 124 124 124 124 - -
|
||||
124 124 124 124 124 124 - - - - - - 124 - -
|
||||
RAM64X1D 5 0 15 2
|
||||
- - - - - - - 642 631 472 407 238 127 - -
|
||||
642 631 472 407 238 127 - - - - - - - - -
|
||||
|
||||
# SLICEM/A6LUT + F7[AB]MUX
|
||||
# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
|
||||
# Outputs: DPO SPO
|
||||
RAM128X1D 5 0 17 2
|
||||
- - - - - - - - 314 314 314 314 314 314 292 - -
|
||||
347 347 347 347 347 347 296 - - - - - - - - - -
|
||||
RAM128X1D 6 0 17 2
|
||||
- - - - - - - - 1009 998 839 774 605 494 450 - -
|
||||
1047 1036 877 812 643 532 478 - - - - - - - - - -
|
||||
|
||||
# Inputs: C CE D R \$pastQ
|
||||
# Outputs: Q
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
4 3 127 238 407 472
|
||||
5 3 127 238 407 472 631
|
||||
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
|
||||
# F8MUX.S+BOUTMUX
|
||||
# F8MUX.I0+F7MUX.S+BOUTMUX
|
||||
|
|
|
@ -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
|
||||
(* 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_" *)
|
||||
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_" *)
|
||||
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_" *)
|
||||
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);
|
||||
parameter DEPTH = 0;
|
||||
parameter [DEPTH-1:0] INIT = 0;
|
||||
|
|
|
@ -173,8 +173,8 @@ module XORCY(output O, input CI, LI);
|
|||
assign O = CI ^ LI;
|
||||
endmodule
|
||||
|
||||
(* abc_box_id = 3, abc_carry, 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);
|
||||
(* abc_box_id = 3, abc_carry="CI,CO", lib_whitebox *)
|
||||
module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
|
||||
assign O = S ^ {CO[2:0], CI | CYINIT};
|
||||
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
|
||||
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;
|
||||
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 (
|
||||
output DPO, SPO,
|
||||
input D, WCLK, WE,
|
||||
|
@ -299,7 +317,7 @@ module RAM64X1D (
|
|||
always @(posedge clk) if (WE) mem[a] <= D;
|
||||
endmodule
|
||||
|
||||
//(* abc_box_id = 5 /*, lib_whitebox*/ *)
|
||||
(* abc_box_id = 6, abc_scc_break="D,WE" *)
|
||||
module RAM128X1D (
|
||||
output DPO, SPO,
|
||||
input D, WCLK, WE,
|
||||
|
|
|
@ -120,7 +120,7 @@ function xtract_cell_decl()
|
|||
xtract_cell_decl RAM128X1S
|
||||
xtract_cell_decl RAM256X1S
|
||||
xtract_cell_decl RAM32M
|
||||
xtract_cell_decl RAM32X1D
|
||||
#xtract_cell_decl RAM32X1D
|
||||
xtract_cell_decl RAM32X1S
|
||||
xtract_cell_decl RAM32X1S_1
|
||||
xtract_cell_decl RAM32X2S
|
||||
|
|
|
@ -3694,13 +3694,6 @@ module RAM32M (...);
|
|||
input WE;
|
||||
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 (...);
|
||||
parameter [31:0] INIT = 32'h00000000;
|
||||
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
|
||||
init 1
|
||||
abits 6
|
||||
|
@ -25,6 +38,13 @@ bram $__XILINX_RAM128X1D
|
|||
clkpol 0 2
|
||||
endbram
|
||||
|
||||
match $__XILINX_RAM32X1D
|
||||
min bits 3
|
||||
min wports 1
|
||||
make_outreg
|
||||
or_next_if_better
|
||||
endmatch
|
||||
|
||||
match $__XILINX_RAM64X1D
|
||||
min bits 5
|
||||
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);
|
||||
parameter [63:0] INIT = 64'bx;
|
||||
parameter CLKPOL2 = 1;
|
||||
|
|
|
@ -29,61 +29,86 @@ module \$lut (A, Y);
|
|||
input [WIDTH-1:0] A;
|
||||
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
|
||||
if (WIDTH == 1) begin
|
||||
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]));
|
||||
end else
|
||||
if (WIDTH == 2) begin
|
||||
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]));
|
||||
LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[1]), .I1(A[0]));
|
||||
end else
|
||||
if (WIDTH == 3) begin
|
||||
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]));
|
||||
LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[2]), .I1(A[1]), .I2(A[0]));
|
||||
end else
|
||||
if (WIDTH == 4) begin
|
||||
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]));
|
||||
LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[3]), .I1(A[2]), .I2(A[1]),
|
||||
.I3(A[0]));
|
||||
end else
|
||||
if (WIDTH == 5) begin
|
||||
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]));
|
||||
LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[4]), .I1(A[3]), .I2(A[2]),
|
||||
.I3(A[1]), .I4(A[0]));
|
||||
end else
|
||||
if (WIDTH == 6) begin
|
||||
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||
.I0(A[5]), .I1(A[4]), .I2(A[3]),
|
||||
.I3(A[2]), .I4(A[1]), .I5(A[0]));
|
||||
end else
|
||||
if (WIDTH == 7) begin
|
||||
wire T0, T1;
|
||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
|
||||
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[6]), .I1(A[5]), .I2(A[4]),
|
||||
.I3(A[3]), .I4(A[2]), .I5(A[1]));
|
||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
|
||||
end else
|
||||
if (WIDTH == 8) begin
|
||||
wire T0, T1, T2, T3, T4, T5;
|
||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
|
||||
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
|
||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
|
||||
LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||
.I0(A[7]), .I1(A[6]), .I2(A[5]),
|
||||
.I3(A[4]), .I4(A[3]), .I5(A[2]));
|
||||
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[1]));
|
||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
|
||||
end else begin
|
||||
wire _TECHMAP_FAIL_ = 1;
|
||||
end
|
||||
|
|
|
@ -45,8 +45,9 @@ struct SynthXilinxPass : public ScriptPass
|
|||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module\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(" generate the synthesis netlist for the specified family.\n");
|
||||
log(" default: xc7\n");
|
||||
log("\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(" (this feature is experimental and incomplete)\n");
|
||||
log("\n");
|
||||
log(" -nocarry\n");
|
||||
log(" disable inference of carry chains\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" disable inference of block rams\n");
|
||||
log("\n");
|
||||
|
@ -73,6 +71,12 @@ struct SynthXilinxPass : public ScriptPass
|
|||
log(" -nosrl\n");
|
||||
log(" disable inference of shift registers\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(" 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");
|
||||
|
@ -93,15 +97,15 @@ struct SynthXilinxPass : public ScriptPass
|
|||
log("\n");
|
||||
}
|
||||
|
||||
std::string top_opt, edif_file, blif_file, abc, arch;
|
||||
bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl;
|
||||
std::string top_opt, edif_file, blif_file, family;
|
||||
bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
edif_file.clear();
|
||||
blif_file.clear();
|
||||
abc = "abc";
|
||||
family = "xc7";
|
||||
flatten = false;
|
||||
retime = false;
|
||||
vpr = false;
|
||||
|
@ -109,7 +113,9 @@ struct SynthXilinxPass : public ScriptPass
|
|||
nobram = false;
|
||||
nodram = false;
|
||||
nosrl = false;
|
||||
arch = "xc7";
|
||||
nocarry = false;
|
||||
nowidelut = false;
|
||||
abc9 = false;
|
||||
}
|
||||
|
||||
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];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
|
||||
arch = args[++argidx];
|
||||
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
|
||||
family = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
|
||||
|
@ -152,6 +158,14 @@ struct SynthXilinxPass : public ScriptPass
|
|||
retime = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nocarry") {
|
||||
nocarry = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nowidelut") {
|
||||
nowidelut = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vpr") {
|
||||
vpr = true;
|
||||
continue;
|
||||
|
@ -173,15 +187,15 @@ struct SynthXilinxPass : public ScriptPass
|
|||
continue;
|
||||
}
|
||||
if (args[argidx] == "-abc9") {
|
||||
abc = "abc9";
|
||||
abc9 = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
|
||||
log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
|
||||
if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s")
|
||||
log_cmd_error("Invalid Xilinx -family setting: %s\n", family.c_str());
|
||||
|
||||
if (!design->full_selection())
|
||||
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
|
||||
if (!nosrl || help_mode)
|
||||
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')")) {
|
||||
|
@ -268,7 +277,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
techmap_files += " -map +/xilinx/arith_map.v";
|
||||
if (vpr)
|
||||
techmap_files += " -D _EXPLICIT_CARRY";
|
||||
else if (abc == "abc9")
|
||||
else if (abc9)
|
||||
techmap_files += " -D _CLB_CARRY";
|
||||
}
|
||||
run("techmap " + techmap_files);
|
||||
|
@ -276,7 +285,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
}
|
||||
|
||||
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");
|
||||
else
|
||||
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
|
||||
|
@ -284,21 +293,31 @@ struct SynthXilinxPass : public ScriptPass
|
|||
}
|
||||
|
||||
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(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");
|
||||
|
||||
// This shregmap call infers fixed length shift registers after abc
|
||||
// has performed any necessary retiming
|
||||
if (!nosrl || help_mode)
|
||||
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");
|
||||
else
|
||||
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
*.log
|
||||
*.out
|
||||
/*_ref.v
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
|
||||
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
|
||||
# inputs and outputs, otherwise ABC and Yosys will name them
|
||||
# arbitrarily (and inconsistently with each other).
|
||||
|
@ -10,8 +20,9 @@ for aag in *.aag; do
|
|||
# Since ABC cannot read *.aag, read the *.aig instead
|
||||
# (which would have been created by the reference aig2aig utility,
|
||||
# available from http://fmv.jku.at/aiger/)
|
||||
../../yosys-abc -c "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
|
||||
../../yosys -p "
|
||||
echo "Checking $aag."
|
||||
$abcprog -q "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
|
||||
../../yosys -qp "
|
||||
read_verilog ${aag%.*}_ref.v
|
||||
prep
|
||||
design -stash gold
|
||||
|
@ -26,8 +37,9 @@ sat -verify -prove-asserts -show-ports -seq 16 miter
|
|||
done
|
||||
|
||||
for aig in *.aig; do
|
||||
../../yosys-abc -c "read -c $aig; write ${aig%.*}_ref.v"
|
||||
../../yosys -p "
|
||||
echo "Checking $aig."
|
||||
$abcprog -q "read -c $aig; write ${aig%.*}_ref.v"
|
||||
../../yosys -qp "
|
||||
read_verilog ${aig%.*}_ref.v
|
||||
prep
|
||||
design -stash gold
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
seed="" # default to no seed specified
|
||||
while getopts "S:" opt
|
||||
abcopt=""
|
||||
while getopts "A:S:" opt
|
||||
do
|
||||
case "$opt" in
|
||||
A) abcopt="-A $OPTARG" ;;
|
||||
S) seed="-S $OPTARG" ;;
|
||||
esac
|
||||
done
|
||||
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 .."
|
||||
../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f
|
||||
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 ||
|
||||
{ echo " ERROR: Unexpected number of read ports."; false; }
|
||||
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."
|
||||
done
|
||||
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
read_verilog opt_ff_sat.v
|
||||
prep -flatten
|
||||
opt_rmdff -sat
|
||||
synth
|
||||
select -assert-count 5 t:$_DFF_P_
|
|
@ -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
|
|
@ -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
|
||||
assign out = steps[WIDTH].outer[0].val;
|
||||
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);
|
||||
abc9_test024_sub a(i[2:1], o[2:1]);
|
||||
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).
|
||||
firrtl2verilog=""
|
||||
xfirrtl="../xfirrtl"
|
||||
abcprog="$toolsdir/../../yosys-abc"
|
||||
|
||||
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
|
||||
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
|
||||
x)
|
||||
use_xsim=true ;;
|
||||
|
@ -65,6 +66,8 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do
|
|||
include_opts="$include_opts -I $OPTARG"
|
||||
xinclude_opts="$xinclude_opts -i $OPTARG"
|
||||
minclude_opts="$minclude_opts +incdir+$OPTARG" ;;
|
||||
A)
|
||||
abcprog="$OPTARG" ;;
|
||||
-)
|
||||
case "${OPTARG}" in
|
||||
xfirrtl)
|
||||
|
@ -89,8 +92,7 @@ done
|
|||
|
||||
compile_and_run() {
|
||||
exe="$1"; output="$2"; shift 2
|
||||
ext=${1##*.}
|
||||
if [ "$ext" == "sv" ]; then
|
||||
if [ "${2##*.}" == "sv" ]; then
|
||||
language_gen="-g2012"
|
||||
else
|
||||
language_gen="-g2005"
|
||||
|
@ -142,23 +144,25 @@ do
|
|||
cd ${bn}.out
|
||||
fn=$(basename $fn)
|
||||
bn=$(basename $bn)
|
||||
refext=v
|
||||
|
||||
rm -f ${bn}_ref.fir
|
||||
if [[ "$ext" == "v" ]]; then
|
||||
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
|
||||
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
|
||||
cp ../${fn} ${bn}_ref.${ext}
|
||||
refext=$ext
|
||||
cp ../${fn} ${bn}_ref.${refext}
|
||||
fi
|
||||
|
||||
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
|
||||
cp ../${bn}_tb.v ${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/simcells.v
|
||||
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
|
||||
|
@ -175,25 +179,25 @@ do
|
|||
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
|
||||
return
|
||||
fi
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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; synth -run coarse; techmap; opt; abc -dff" ${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.${refext}
|
||||
if [ -n "$firrtl2verilog" ]; 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
|
||||
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
|
||||
fi
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
*.log
|
||||
/*.log
|
||||
/*.out
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
module abc9_test027(output reg o);
|
||||
initial o = 1'b0;
|
||||
always @*
|
||||
o <= ~o;
|
||||
endmodule
|
|
@ -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
|
||||
|
||||
|
||||
## Examle usage for "pmuxtree" and "muxcover"
|
||||
## Example usage for "pmuxtree" and "muxcover"
|
||||
|
||||
proc
|
||||
pmuxtree
|
||||
|
@ -49,3 +49,462 @@ hierarchy -top equiv
|
|||
equiv_simple -undef
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
end
|
||||
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
|
||||
design -save read
|
||||
|
||||
hierarchy -top pmux2shiftx_test
|
||||
prep
|
||||
design -save gold
|
||||
|
||||
|
@ -21,8 +24,16 @@ design -import gate -as gate
|
|||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||
sat -verify -prove-asserts -show-ports miter
|
||||
|
||||
design -load gold
|
||||
stat
|
||||
#design -load gold
|
||||
#stat
|
||||
#
|
||||
#design -load gate
|
||||
#stat
|
||||
|
||||
design -load gate
|
||||
stat
|
||||
design -load read
|
||||
hierarchy -top issue01135
|
||||
proc
|
||||
pmux2shiftx -norange
|
||||
opt -full
|
||||
select -assert-count 0 t:$shift*
|
||||
select -assert-count 1 t:$pmux
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 New Issue