Merge branch 'master' of github.com:YosysHQ/yosys into clifford/fix968

This commit is contained in:
Clifford Wolf 2019-05-06 15:41:13 +02:00
commit d187be39d6
35 changed files with 788 additions and 291 deletions

View File

@ -163,31 +163,61 @@ struct FirrtlWorker
} }
}; };
/* Memories defined within this module. */ /* Memories defined within this module. */
struct memory { struct memory {
string name; // memory name Cell *pCell; // for error reporting
int abits; // number of address bits string name; // memory name
int size; // size (in units) of the memory int abits; // number of address bits
int width; // size (in bits) of each element int size; // size (in units) of the memory
int read_latency; int width; // size (in bits) of each element
int write_latency; int read_latency;
vector<read_port> read_ports; int write_latency;
vector<write_port> write_ports; vector<read_port> read_ports;
std::string init_file; vector<write_port> write_ports;
std::string init_file_srcFileSpec; std::string init_file;
memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} std::string init_file_srcFileSpec;
memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} string srcLine;
void add_memory_read_port(read_port &rp) { memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
read_ports.push_back(rp); // Provide defaults for abits or size if one (but not the other) is specified.
} if (this->abits == 0 && this->size != 0) {
void add_memory_write_port(write_port &wp) { this->abits = ceil_log2(this->size);
write_ports.push_back(wp); } else if (this->abits != 0 && this->size == 0) {
} this->size = 1 << this->abits;
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { }
this->init_file = init_file; // Sanity-check this construction.
this->init_file_srcFileSpec = init_file_srcFileSpec; if (this->name == "") {
log_error("Nameless memory%s\n", this->atLine());
}
if (this->abits == 0 && this->size == 0) {
log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
}
if (this->width == 0) {
log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
}
} }
// We need a default constructor for the dict insert.
memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
}; const char *atLine() {
if (srcLine == "") {
if (pCell) {
auto p = pCell->attributes.find("\\src");
srcLine = " at " + p->second.decode_string();
}
}
return srcLine.c_str();
}
void add_memory_read_port(read_port &rp) {
read_ports.push_back(rp);
}
void add_memory_write_port(write_port &wp) {
write_ports.push_back(wp);
}
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
this->init_file = init_file;
this->init_file_srcFileSpec = init_file_srcFileSpec;
}
};
dict<string, memory> memories; dict<string, memory> memories;
void register_memory(memory &m) void register_memory(memory &m)
@ -604,7 +634,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int(); int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int(); int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int(); int size = cell->parameters.at("\\SIZE").as_int();
memory m(mem_id, abits, size, width); memory m(cell, mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@ -681,6 +711,8 @@ struct FirrtlWorker
{ {
std::string cell_type = fid(cell->type); std::string cell_type = fid(cell->type);
std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
memory *mp = nullptr; memory *mp = nullptr;
if (cell->type == "$meminit" ) { if (cell->type == "$meminit" ) {
log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
@ -693,6 +725,11 @@ struct FirrtlWorker
Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
// Do we already have an entry for this memory?
if (memories.count(mem_id) == 0) {
memory m(cell, mem_id, abits, 0, width);
register_memory(m);
}
mp = &memories.at(mem_id); mp = &memories.at(mem_id);
int portNum = 0; int portNum = 0;
bool transparency = false; bool transparency = false;
@ -890,7 +927,7 @@ struct FirrtlWorker
// If we have any memory definitions, output them. // If we have any memory definitions, output them.
for (auto kv : memories) { for (auto kv : memories) {
memory m = kv.second; memory &m = kv.second;
f << stringf(" mem %s:\n", m.name.c_str()); f << stringf(" mem %s:\n", m.name.c_str());
f << stringf(" data-type => UInt<%d>\n", m.width); f << stringf(" data-type => UInt<%d>\n", m.width);
f << stringf(" depth => %d\n", m.size); f << stringf(" depth => %d\n", m.size);

View File

@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid) if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
} else } else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) { if (range) {

View File

@ -1605,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp; current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str; wire_tmp_id->str = wire_tmp->str;

View File

@ -45,7 +45,7 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
%} %}
%name-prefix "rtlil_frontend_ilang_yy" %define api.prefix {rtlil_frontend_ilang_yy}
%union { %union {
char *string; char *string;

View File

@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); } "logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }

View File

@ -96,7 +96,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%} %}
%name-prefix "frontend_verilog_yy" %define api.prefix {frontend_verilog_yy}
%union { %union {
std::string *string; std::string *string;
@ -106,11 +106,11 @@ static void free_attr(std::map<std::string, AstNode*> *al)
} }
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@ -456,6 +456,9 @@ wire_type_token:
TOK_LOGIC { TOK_LOGIC {
astbuf3->is_logic = true; astbuf3->is_logic = true;
} | } |
TOK_VAR {
astbuf3->is_logic = true;
} |
TOK_INTEGER { TOK_INTEGER {
astbuf3->is_reg = true; astbuf3->is_reg = true;
astbuf3->range_left = 31; astbuf3->range_left = 31;
@ -1341,6 +1344,9 @@ opt_property:
TOK_PROPERTY { TOK_PROPERTY {
$$ = true; $$ = true;
} | } |
TOK_FINAL {
$$ = false;
} |
/* empty */ { /* empty */ {
$$ = false; $$ = false;
}; };

View File

@ -291,7 +291,7 @@ struct QwpWorker
// gaussian elimination // gaussian elimination
for (int i = 0; i < N; i++) for (int i = 0; i < N; i++)
{ {
if (config.verbose && ((i+1) % (N/15)) == 0) if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0)
log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
// find best row // find best row

View File

@ -272,6 +272,10 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
} }
} }
SigPool raw_used_signals_noaliases;
for (auto &it : module->connections_)
raw_used_signals_noaliases.add(it.second);
module->connections_.clear(); module->connections_.clear();
SigPool used_signals; SigPool used_signals;
@ -281,6 +285,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
for (auto &it2 : cell->connections_) { for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second); assign_map.apply(it2.second);
used_signals.add(it2.second); used_signals.add(it2.second);
raw_used_signals_noaliases.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first)) if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second); used_signals_nodrivers.add(it2.second);
} }
@ -301,53 +306,63 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
} }
} }
std::vector<RTLIL::Wire*> maybe_del_wires; pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1; log_assert(GetSize(s1) == GetSize(s2));
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) { Const initval;
maybe_del_wires.push_back(wire); if (wire->attributes.count("\\init"))
} else { initval = wire->attributes.at("\\init");
log_assert(GetSize(s1) == GetSize(s2)); if (GetSize(initval) != GetSize(wire))
Const initval; initval.bits.resize(GetSize(wire), State::Sx);
if (wire->attributes.count("\\init")) if (initval.is_fully_undef())
initval = wire->attributes.at("\\init"); wire->attributes.erase("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx); bool delete_this_wire = false;
RTLIL::SigSig new_conn; if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
for (int i = 0; i < GetSize(s1); i++) /* do not delete anything with "keep" or module ports or initialized wires */
if (s1[i] != s2[i]) { } else
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { if (!purge_mode && check_public_name(wire->name)) {
s2[i] = initval[i]; /* do not get rid of public names unless in purge mode */
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
}
} else { } else {
if (!used_signals.check_any(RTLIL::SigSpec(wire))) if (!raw_used_signals_noaliases.check_any(s1))
maybe_del_wires.push_back(wire); delete_this_wire = true;
if (!used_signals_nodrivers.check_any(s2))
delete_this_wire = true;
} }
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); if (delete_this_wire) {
if (!used_signals_nodrivers.check_any(sig)) { del_wires_queue.insert(wire);
} else {
RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
}
if (!used_signals_nodrivers.check_all(s2)) {
std::string unused_bits; std::string unused_bits;
for (int i = 0; i < GetSize(sig); i++) { for (int i = 0; i < GetSize(s2); i++) {
if (sig[i].wire == NULL) if (s2[i].wire == NULL)
continue; continue;
if (!used_signals_nodrivers.check(sig[i])) { if (!used_signals_nodrivers.check(s2[i])) {
if (!unused_bits.empty()) if (!unused_bits.empty())
unused_bits += " "; unused_bits += " ";
unused_bits += stringf("%d", i); unused_bits += stringf("%d", i);
@ -362,24 +377,19 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
} }
} }
int del_temp_wires_count = 0;
for (auto wire : del_wires_queue) {
if (ys_debug() || (check_public_name(wire->name) && verbose))
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
else
del_temp_wires_count++;
}
pool<RTLIL::Wire*> del_wires; module->remove(del_wires_queue);
count_rm_wires += GetSize(del_wires_queue);
int del_wires_count = 0; if (verbose && del_temp_wires_count)
for (auto wire : maybe_del_wires) log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
}
del_wires.insert(wire);
del_wires_count++;
}
module->remove(del_wires);
count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0)
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -526,6 +536,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design); ct_all.setup(design);
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules_warn()) { for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn()) if (module->has_processes_warn())
continue; continue;
@ -591,7 +604,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) { for (auto module : design->selected_whole_modules()) {
if (module->has_processes()) if (module->has_processes())
continue; continue;
rmunused_module(module, purge_mode, false, false); rmunused_module(module, purge_mode, ys_debug(), false);
} }
log_suppressed(); log_suppressed();

View File

@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
} }
if (wire->port_input) if (wire->port_input)
driven_signals.add(sigmap(wire)); driven_signals.add(sigmap(wire));
if (wire->port_output) if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire)); used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire)); all_signals.add(sigmap(wire));
} }
@ -88,7 +88,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
} }
} }
log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val)); log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val); module->connect(sig, val);
did_something = true; did_something = true;
} }
@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (SigBit(initval[i]) == sig[i]) if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx; initval[i] = State::Sx;
} }
if (initval.is_fully_undef()) if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init"); wire->attributes.erase("\\init");
else did_something = true;
} else if (initval != wire->attributes.at("\\init")) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes["\\init"] = initval; wire->attributes["\\init"] = initval;
did_something = true;
}
} }
} }
} }

View File

@ -531,6 +531,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig))); module->connect(sig, Const(0, GetSize(sig)));
} }
} }
if (c->type.in("$div", "$mod", "$pow"))
{
SigSpec A = c->getPort("\\A");
int original_a_width = GetSize(A);
if (c->getParam("\\A_SIGNED").as_bool()) {
while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
A.remove(GetSize(A)-1, 1);
} else {
while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
A.remove(GetSize(A)-1, 1);
}
if (original_a_width != GetSize(A)) {
log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\A", A);
c->setParam("\\A_WIDTH", GetSize(A));
}
SigSpec B = c->getPort("\\B");
int original_b_width = GetSize(B);
if (c->getParam("\\B_SIGNED").as_bool()) {
while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
B.remove(GetSize(B)-1, 1);
} else {
while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
B.remove(GetSize(B)-1, 1);
}
if (original_b_width != GetSize(B)) {
log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\B", B);
c->setParam("\\B_WIDTH", GetSize(B));
}
}
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string(); IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid); RTLIL::Memory *mem = module->memories.at(memid);

View File

@ -1 +1,2 @@
/ice40_dsp_pm.h /ice40_dsp_pm.h
/peepopt_pm.h

View File

@ -1,8 +1,23 @@
OBJS += passes/pmgen/ice40_dsp.o OBJS += passes/pmgen/ice40_dsp.o
OBJS += passes/pmgen/peepopt.o
# --------------------------------------
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
.SECONDARY: passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
$(P) mkdir -p passes/pmgen && python3 $^ $@ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
# --------------------------------------
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
EXTRA_OBJS += passes/pmgen/peepopt_pm.h
.SECONDARY: passes/pmgen/peepopt_pm.h
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)

View File

@ -29,19 +29,25 @@ up in any future matches:
pm.blacklist(some_cell); pm.blacklist(some_cell);
The `.run(callback_function)` method searches for all matches and calls the The `.run_<pattern_name>(callback_function)` method searches for all matches
callback function for each found match: for the pattern`<pattern_name>` and calls the callback function for each found
match:
pm.run([&](){ pm.run_foobar([&](){
log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
}); });
The `.pmg` file declares matcher state variables that are accessible via the The `.pmg` file declares matcher state variables that are accessible via the
`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.) `.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of Similarly the `.pmg` file declares user data variables that become members of
`.ud`, a struct of type `foobar_pm::udata_t`. `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with
reference to `pm.st_<pattern_name>`.
The .pmg File Format The .pmg File Format
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
Lines in `.pmg` files starting with `//` are comments. Lines in `.pmg` files starting with `//` are comments.
Declaring a pattern
-------------------
A `.pmg` file contains one or more patterns. Each pattern starts with a line
with the `pattern` keyword followed by the name of the pattern.
Declaring state variables Declaring state variables
------------------------- -------------------------
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
and saved and restored as needed. and saved and restored as needed.
They are automatically initialized to the default constructed value of their type They are automatically initialized to the default constructed value of their type
when `.run(callback_function)` is called. when `.run_<pattern_name>(callback_function)` is called.
Declaring udata variables Declaring udata variables
------------------------- -------------------------

View File

@ -19,47 +19,50 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "passes/pmgen/ice40_dsp_pm.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
#include "passes/pmgen/ice40_dsp_pm.h"
void create_ice40_dsp(ice40_dsp_pm &pm) void create_ice40_dsp(ice40_dsp_pm &pm)
{ {
auto &st = pm.st_ice40_dsp;
#if 0 #if 0
log("\n"); log("\n");
log("ffA: %s\n", log_id(pm.st.ffA, "--")); log("ffA: %s\n", log_id(st.ffA, "--"));
log("ffB: %s\n", log_id(pm.st.ffB, "--")); log("ffB: %s\n", log_id(st.ffB, "--"));
log("mul: %s\n", log_id(pm.st.mul, "--")); log("mul: %s\n", log_id(st.mul, "--"));
log("ffY: %s\n", log_id(pm.st.ffY, "--")); log("ffY: %s\n", log_id(st.ffY, "--"));
log("addAB: %s\n", log_id(pm.st.addAB, "--")); log("addAB: %s\n", log_id(st.addAB, "--"));
log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--"));
log("ffS: %s\n", log_id(pm.st.ffS, "--")); log("ffS: %s\n", log_id(st.ffS, "--"));
#endif #endif
log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
if (GetSize(pm.st.sigA) > 16) { if (GetSize(st.sigA) > 16) {
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
return; return;
} }
if (GetSize(pm.st.sigB) > 16) { if (GetSize(st.sigB) > 16) {
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
return; return;
} }
if (GetSize(pm.st.sigS) > 32) { if (GetSize(st.sigS) > 32) {
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
return; return;
} }
if (GetSize(pm.st.sigY) > 32) { if (GetSize(st.sigY) > 32) {
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
return; return;
} }
bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
if (mul_signed) { if (mul_signed) {
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
@ -69,21 +72,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log(" replacing $mul with SB_MAC16 cell.\n"); log(" replacing $mul with SB_MAC16 cell.\n");
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
pm.module->swap_names(cell, pm.st.mul); pm.module->swap_names(cell, st.mul);
// SB_MAC16 Input Interface // SB_MAC16 Input Interface
SigSpec A = pm.st.sigA; SigSpec A = st.sigA;
A.extend_u0(16, mul_signed); A.extend_u0(16, mul_signed);
SigSpec B = pm.st.sigB; SigSpec B = st.sigB;
B.extend_u0(16, mul_signed); B.extend_u0(16, mul_signed);
SigSpec CD; SigSpec CD;
if (pm.st.muxA) if (st.muxA)
CD = pm.st.muxA->getPort("\\B"); CD = st.muxA->getPort("\\B");
if (pm.st.muxB) if (st.muxB)
CD = pm.st.muxB->getPort("\\A"); CD = st.muxB->getPort("\\A");
CD.extend_u0(32, mul_signed); CD.extend_u0(32, mul_signed);
cell->setPort("\\A", A); cell->setPort("\\A", A);
@ -91,8 +94,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\C", CD.extract(0, 16)); cell->setPort("\\C", CD.extract(0, 16));
cell->setPort("\\D", CD.extract(16, 16)); cell->setPort("\\D", CD.extract(16, 16));
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
cell->setPort("\\AHOLD", State::S0); cell->setPort("\\AHOLD", State::S0);
cell->setPort("\\BHOLD", State::S0); cell->setPort("\\BHOLD", State::S0);
@ -102,25 +105,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\IRSTTOP", State::S0); cell->setPort("\\IRSTTOP", State::S0);
cell->setPort("\\IRSTBOT", State::S0); cell->setPort("\\IRSTBOT", State::S0);
if (pm.st.clock_vld) if (st.clock_vld)
{ {
cell->setPort("\\CLK", pm.st.clock); cell->setPort("\\CLK", st.clock);
cell->setPort("\\CE", State::S1); cell->setPort("\\CE", State::S1);
cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1);
log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge");
if (pm.st.ffA) if (st.ffA)
log(" ffA:%s", log_id(pm.st.ffA)); log(" ffA:%s", log_id(st.ffA));
if (pm.st.ffB) if (st.ffB)
log(" ffB:%s", log_id(pm.st.ffB)); log(" ffB:%s", log_id(st.ffB));
if (pm.st.ffY) if (st.ffY)
log(" ffY:%s", log_id(pm.st.ffY)); log(" ffY:%s", log_id(st.ffY));
if (pm.st.ffS) if (st.ffS)
log(" ffS:%s", log_id(pm.st.ffS)); log(" ffS:%s", log_id(st.ffS));
log("\n"); log("\n");
} }
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
// SB_MAC16 Output Interface // SB_MAC16 Output Interface
SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; SigSpec O = st.ffS ? st.sigS : st.sigY;
if (GetSize(O) < 32) if (GetSize(O) < 32)
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
cell->setPort("\\O", O); cell->setPort("\\O", O);
if (pm.st.addAB) { if (st.addAB) {
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
} else { } else {
cell->setPort("\\ADDSUBTOP", State::S0); cell->setPort("\\ADDSUBTOP", State::S0);
cell->setPort("\\ADDSUBBOT", State::S0); cell->setPort("\\ADDSUBBOT", State::S0);
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\OHOLDBOT", State::S0); cell->setPort("\\OHOLDBOT", State::S0);
SigSpec acc_reset = State::S0; SigSpec acc_reset = State::S0;
if (pm.st.muxA) if (st.muxA)
acc_reset = pm.st.muxA->getPort("\\S"); acc_reset = st.muxA->getPort("\\S");
if (pm.st.muxB) if (st.muxB)
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADTOP", acc_reset);
cell->setPort("\\OLOADBOT", acc_reset); cell->setPort("\\OLOADBOT", acc_reset);
@ -179,17 +182,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\C_REG", State::S0); cell->setParam("\\C_REG", State::S0);
cell->setParam("\\D_REG", State::S0); cell->setParam("\\D_REG", State::S0);
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
@ -198,9 +201,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
pm.autoremove(pm.st.mul); pm.autoremove(st.mul);
pm.autoremove(pm.st.ffY); pm.autoremove(st.ffY);
pm.autoremove(pm.st.ffS); pm.autoremove(st.ffS);
} }
struct Ice40DspPass : public Pass { struct Ice40DspPass : public Pass {
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
} }
} Ice40DspPass; } Ice40DspPass;

View File

@ -1,3 +1,5 @@
pattern ice40_dsp
state <SigBit> clock state <SigBit> clock
state <bool> clock_pol clock_vld state <bool> clock_pol clock_vld
state <SigSpec> sigA sigB sigY sigS state <SigSpec> sigA sigB sigY sigS

68
passes/pmgen/peepopt.cc Normal file
View File

@ -0,0 +1,68 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/pmgen/peepopt_pm.h"
struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" peepopt [options] [selection]\n");
log("\n");
log("This pass applies a collection of peephole optimizers to the current design.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules()) {
did_something = true;
while (did_something) {
did_something = false;
peepopt_pm pm(module, module->selected_cells());
pm.run_shiftmul();
pm.run_muldiv();
}
}
}
} PeepoptPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,36 @@
pattern muldiv
state <SigSpec> t x y
match mul
select mul->type == $mul
select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y))
endmatch
code t x y
t = port(mul, \Y);
x = port(mul, \A);
y = port(mul, \B);
branch;
std::swap(x, y);
endcode
match div
select div->type.in($div)
index <SigSpec> port(div, \A) === t
index <SigSpec> port(div, \B) === x
endmatch
code
SigSpec div_y = port(div, \Y);
SigSpec val_y = y;
if (GetSize(div_y) != GetSize(val_y))
val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool());
did_something = true;
log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
module->connect(div_y, val_y);
autoremove(div);
reject;
endcode

View File

@ -0,0 +1,87 @@
pattern shiftmul
state <SigSpec> shamt
match shift
select shift->type.in($shift, $shiftx, $shr)
endmatch
code shamt
shamt = port(shift, \B);
if (shamt.empty())
reject;
if (shamt[GetSize(shamt)-1] == State::S0) {
do {
shamt.remove(GetSize(shamt)-1);
if (shamt.empty())
reject;
} while (shamt[GetSize(shamt)-1] == State::S0);
} else
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
reject;
}
if (GetSize(shamt) > 20)
reject;
endcode
match mul
select mul->type.in($mul)
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
index <SigSpec> port(mul, \Y) === shamt
endmatch
code
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const();
int const_factor = const_factor_cnst.as_int();
if (GetSize(const_factor_cnst) == 0)
reject;
if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 &&
param(mul, const_factor_signed).as_bool())
reject;
if (GetSize(const_factor_cnst) > 20)
reject;
if (GetSize(port(shift, \Y)) > const_factor)
reject;
did_something = true;
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
int new_const_factor_log2 = ceil_log2(const_factor);
int new_const_factor = 1 << new_const_factor_log2;
SigSpec padding(State::Sx, new_const_factor-const_factor);
SigSpec old_a = port(shift, \A), new_a;
int trunc = 0;
if (GetSize(old_a) % const_factor != 0) {
trunc = const_factor - GetSize(old_a) % const_factor;
old_a.append(SigSpec(State::Sx, trunc));
}
for (int i = 0; i*const_factor < GetSize(old_a); i++) {
SigSpec slice = old_a.extract(i*const_factor, const_factor);
new_a.append(slice);
new_a.append(padding);
}
if (trunc > 0)
new_a.remove(GetSize(new_a)-trunc, trunc);
SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
if (param(shift, \B_SIGNED).as_bool())
new_b.append(State::S0);
shift->setPort(\A, new_a);
shift->setParam(\A_WIDTH, GetSize(new_a));
shift->setPort(\B, new_b);
shift->setParam(\B_WIDTH, GetSize(new_b));
blacklist(shift);
reject;
endcode

View File

@ -3,15 +3,42 @@
import re import re
import sys import sys
import pprint import pprint
import getopt
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
pmgfile = sys.argv[1] prefix = None
assert pmgfile.endswith(".pmg") pmgfiles = list()
prefix = pmgfile[0:-4] outfile = None
prefix = prefix.split('/')[-1] debug = False
outfile = sys.argv[2] genhdr = False
opts, args = getopt.getopt(sys.argv[1:], "p:o:dg")
for o, a in opts:
if o == "-p":
prefix = a
elif o == "-o":
outfile = a
elif o == "-d":
debug = True
elif o == "-g":
genhdr = True
if outfile is None:
outfile = "/dev/stdout"
for a in args:
assert a.endswith(".pmg")
if prefix is None and len(args) == 1:
prefix = a[0:-4]
prefix = prefix.split('/')[-1]
pmgfiles.append(a)
assert prefix is not None
current_pattern = None
patterns = dict()
state_types = dict() state_types = dict()
udata_types = dict() udata_types = dict()
blocks = list() blocks = list()
@ -77,7 +104,8 @@ def rewrite_cpp(s):
return "".join(t) return "".join(t)
with open(pmgfile, "r") as f: def process_pmgfile(f):
global current_pattern
while True: while True:
line = f.readline() line = f.readline()
if line == "": break if line == "": break
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
if len(cmd) == 0 or cmd[0].startswith("//"): continue if len(cmd) == 0 or cmd[0].startswith("//"): continue
cmd = cmd[0] cmd = cmd[0]
if cmd == "pattern":
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
line = line.split()
assert len(line) == 2
assert line[1] not in patterns
current_pattern = line[1]
patterns[current_pattern] = len(blocks)
state_types[current_pattern] = dict()
udata_types[current_pattern] = dict()
continue
assert current_pattern is not None
if cmd == "state": if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m assert m
type_str = m.group(1) type_str = m.group(1)
states_str = m.group(2) states_str = m.group(2)
for s in re.split(r"\s+", states_str): for s in re.split(r"\s+", states_str):
assert s not in state_types assert s not in state_types[current_pattern]
state_types[s] = type_str state_types[current_pattern][s] = type_str
continue continue
if cmd == "udata": if cmd == "udata":
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
type_str = m.group(1) type_str = m.group(1)
udatas_str = m.group(2) udatas_str = m.group(2)
for s in re.split(r"\s+", udatas_str): for s in re.split(r"\s+", udatas_str):
assert s not in udata_types assert s not in udata_types[current_pattern]
udata_types[s] = type_str udata_types[current_pattern][s] = type_str
continue continue
if cmd == "match": if cmd == "match":
block = dict() block = dict()
block["type"] = "match" block["type"] = "match"
block["pattern"] = current_pattern
line = line.split() line = line.split()
assert len(line) == 2 assert len(line) == 2
assert line[1] not in state_types assert line[1] not in state_types[current_pattern]
block["cell"] = line[1] block["cell"] = line[1]
state_types[line[1]] = "Cell*"; state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list() block["if"] = list()
block["select"] = list() block["select"] = list()
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
assert False assert False
blocks.append(block) blocks.append(block)
continue
if cmd == "code": if cmd == "code":
block = dict() block = dict()
block["type"] = "code" block["type"] = "code"
block["pattern"] = current_pattern
block["code"] = list() block["code"] = list()
block["states"] = set() block["states"] = set()
for s in line.split()[1:]: for s in line.split()[1:]:
assert s in state_types assert s in state_types[current_pattern]
block["states"].add(s) block["states"].add(s)
while True: while True:
@ -179,17 +228,36 @@ with open(pmgfile, "r") as f:
block["code"].append(rewrite_cpp(l.rstrip())) block["code"].append(rewrite_cpp(l.rstrip()))
blocks.append(block) blocks.append(block)
continue
assert False
for fn in pmgfiles:
with open(fn, "r") as f:
process_pmgfile(f)
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
current_pattern = None
if debug:
pp.pprint(blocks)
with open(outfile, "w") as f: with open(outfile, "w") as f:
print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) for fn in pmgfiles:
print("// Generated by pmgen.py from {}".format(fn), file=f)
print("", file=f) print("", file=f)
print("#include \"kernel/yosys.h\"", file=f) if genhdr:
print("#include \"kernel/sigtools.h\"", file=f) print("#include \"kernel/yosys.h\"", file=f)
print("", file=f) print("#include \"kernel/sigtools.h\"", file=f)
print("", file=f)
print("YOSYS_NAMESPACE_BEGIN", file=f) print("YOSYS_NAMESPACE_BEGIN", file=f)
print("", file=f) print("", file=f)
print("struct {}_pm {{".format(prefix), file=f) print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f) print(" Module *module;", file=f)
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
print(" int rollback;", file=f) print(" int rollback;", file=f)
print("", file=f) print("", file=f)
print(" struct state_t {", file=f) for current_pattern in sorted(patterns.keys()):
for s, t in sorted(state_types.items()): print(" struct state_{}_t {{".format(current_pattern), file=f)
print(" {} {};".format(t, s), file=f) for s, t in sorted(state_types[current_pattern].items()):
print(" } st;", file=f) print(" {} {};".format(t, s), file=f)
print("", file=f) print(" }} st_{};".format(current_pattern), file=f)
print("", file=f)
print(" struct udata_t {", file=f) print(" struct udata_{}_t {{".format(current_pattern), file=f)
for s, t in sorted(udata_types.items()): for s, t in sorted(udata_types[current_pattern].items()):
print(" {} {};".format(t, s), file=f) print(" {} {};".format(t, s), file=f)
print(" } ud;", file=f) print(" }} ud_{};".format(current_pattern), file=f)
print("", file=f) print("", file=f)
current_pattern = None
for v, n in sorted(ids.items()): for v, n in sorted(ids.items()):
if n[0] == "\\": if n[0] == "\\":
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void check_blacklist() {", file=f) for current_pattern in sorted(patterns.keys()):
print(" if (!blacklist_dirty)", file=f) print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
print(" return;", file=f) print(" if (!blacklist_dirty)", file=f)
print(" blacklist_dirty = false;", file=f) print(" return;", file=f)
for index in range(len(blocks)): print(" blacklist_dirty = false;", file=f)
block = blocks[index] for index in range(len(blocks)):
if block["type"] == "match": block = blocks[index]
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) if block["pattern"] != current_pattern:
print(" rollback = {};".format(index+1), file=f) continue
print(" return;", file=f) if block["type"] == "match":
print(" }", file=f) print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
print(" rollback = 0;", file=f) print(" rollback = {};".format(index+1), file=f)
print(" }", file=f) print(" return;", file=f)
print("", file=f) print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f) print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
print(" return sigmap(cell->getPort(portname));", file=f) print(" return sigmap(cell->getPort(portname));", file=f)
@ -294,11 +368,13 @@ with open(outfile, "w") as f:
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module) {", file=f) print(" module(module), sigmap(module) {", file=f)
for s, t in sorted(udata_types.items()): for current_pattern in sorted(patterns.keys()):
if t.endswith("*"): for s, t in sorted(udata_types[current_pattern].items()):
print(" ud.{} = nullptr;".format(s), file=f) if t.endswith("*"):
else: print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f)
print(" ud.{} = {}();".format(s, t), file=f) else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None
print(" for (auto cell : module->cells()) {", file=f) print(" for (auto cell : module->cells()) {", file=f)
print(" for (auto &conn : cell->connections())", file=f) print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f) print(" add_siguser(conn.second, cell);", file=f)
@ -328,34 +404,52 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run(std::function<void()> on_accept_f) {", file=f) for current_pattern in sorted(patterns.keys()):
print(" on_accept = on_accept_f;", file=f) print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" rollback = 0;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" blacklist_dirty = false;", file=f) print(" rollback = 0;", file=f)
for s, t in sorted(state_types.items()): print(" blacklist_dirty = false;", file=f)
if t.endswith("*"): for s, t in sorted(state_types[current_pattern].items()):
print(" st.{} = nullptr;".format(s), file=f) if t.endswith("*"):
else: print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
print(" st.{} = {}();".format(s, t), file=f) else:
print(" block_0();", file=f) print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
print(" }", file=f) print(" block_{}();".format(patterns[current_pattern]), file=f)
print("", file=f) print(" }", file=f)
print("", file=f)
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f) print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
print(" run([&](){on_accept_f(*this);});", file=f) print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f)
print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
print(" void run_{}() {{".format(current_pattern), file=f)
print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None
for index in range(len(blocks)): for index in range(len(blocks)):
block = blocks[index] block = blocks[index]
print(" void block_{}() {{".format(index), file=f) print(" void block_{}() {{".format(index), file=f)
current_pattern = block["pattern"]
if block["type"] == "final":
print(" on_accept();", file=f)
print(" check_blacklist_{}();".format(current_pattern), file=f)
print(" }", file=f)
if index+1 != len(blocks):
print("", file=f)
continue
const_st = set() const_st = set()
nonconst_st = set() nonconst_st = set()
restore_st = set() restore_st = set()
for i in range(index): for i in range(patterns[current_pattern], index):
if blocks[i]["type"] == "code": if blocks[i]["type"] == "code":
for s in blocks[i]["states"]: for s in blocks[i]["states"]:
const_st.add(s) const_st.add(s)
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
assert False assert False
for s in sorted(const_st): for s in sorted(const_st):
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
else: else:
print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
if len(restore_st): if len(restore_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} backup_{} = {};".format(t, s, s), file=f) print(" {} backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code": if block["type"] == "code":
print("", file=f) print("", file=f)
print(" do {", file=f) print(" do {", file=f)
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
for line in block["code"]: for line in block["code"]:
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
if len(restore_st) or len(nonconst_st): if len(restore_st) or len(nonconst_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} = backup_{};".format(s, s), file=f) print(" {} = backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
if s not in restore_st: if s not in restore_st:
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} = nullptr;".format(s), file=f) print(" {} = nullptr;".format(s), file=f)
else: else:
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
else: else:
assert False assert False
current_pattern = None
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void block_{}() {{".format(len(blocks)), file=f)
print(" on_accept();", file=f)
print(" check_blacklist();", file=f)
print(" }", file=f)
print("};", file=f) print("};", file=f)
print("", file=f) if genhdr:
print("YOSYS_NAMESPACE_END", file=f) print("", file=f)
print("YOSYS_NAMESPACE_END", file=f)
# pp.pprint(blocks)

View File

@ -508,7 +508,7 @@ struct ExposePass : public Pass {
} }
for (auto &conn : module->connections_) for (auto &conn : module->connections_)
conn.first = out_to_in_map(sigmap(conn.first)); conn.first = out_to_in_map(conn.first);
} }
if (flag_cut) if (flag_cut)

View File

@ -1169,6 +1169,7 @@ struct SatPass : public Pass {
if (args[argidx] == "-tempinduct-def") { if (args[argidx] == "-tempinduct-def") {
tempinduct = true; tempinduct = true;
tempinduct_def = true; tempinduct_def = true;
enable_undef = true;
continue; continue;
} }
if (args[argidx] == "-tempinduct-baseonly") { if (args[argidx] == "-tempinduct-baseonly") {

View File

@ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{ {
std::string abc_sname = abc_name.substr(1); std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") { bool isnew = false;
bool inv = abc_sname.back() == 'v'; if (abc_sname.substr(0, 4) == "new_")
if (inv) abc_sname.pop_back(); {
abc_sname.erase(0, 4);
isnew = true;
}
if (abc_sname.substr(0, 5) == "ys__n")
{
abc_sname.erase(0, 5); abc_sname.erase(0, 5);
if (abc_sname.find_last_not_of("012345689") == std::string::npos) { if (std::isdigit(abc_sname.at(0)))
{
int sid = std::stoi(abc_sname); int sid = std::stoi(abc_sname);
for (auto sig : signal_list) { size_t postfix_start = abc_sname.find_first_not_of("0123456789");
if (sig.id == sid && sig.bit.wire != nullptr) { std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
if (sid < GetSize(signal_list))
{
auto sig = signal_list.at(sid);
if (sig.bit.wire != nullptr)
{
std::stringstream sstr; std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1) if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]"; sstr << "[" << sig.bit.offset << "]";
if (inv) if (isnew)
sstr << "_inv"; sstr << "_new";
sstr << postfix;
if (orig_wire != nullptr) if (orig_wire != nullptr)
*orig_wire = sig.bit.wire; *orig_wire = sig.bit.wire;
return sstr.str(); return sstr.str();

View File

@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) { if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init"); Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
init_bits[sigmap(SigBit(wire, i))] = value[i]; if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i];
} }
if (wire->port_output) if (wire->port_output)
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire))

View File

@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech
// Only map if $shiftx exclusively covers the shift register // Only map if $shiftx exclusively covers the shift register
if (shiftx->type == "$shiftx") { if (shiftx->type == "$shiftx") {
if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int())
return false;
// Due to padding the most significant bits of A may be 1'bx,
// and if so, discount them
if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) {
const SigSpec A = shiftx->getPort("\\A");
const int A_width = shiftx->getParam("\\A_WIDTH").as_int();
for (int i = GetSize(taps); i < A_width; ++i)
if (A[i] != RTLIL::Sx) return false;
}
else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
return false; return false;
} }
else if (shiftx->type == "$mux") { else if (shiftx->type == "$mux") {

View File

@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
if (help_mode) if (help_mode)
run("techmap -map +/cmp2lut.v", " (if -lut)"); run("techmap -map +/cmp2lut.v", " (if -lut)");
else else

View File

@ -241,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
run("share"); run("share");
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
run("opt_expr"); run("opt_expr");

View File

@ -17,6 +17,16 @@
* *
*/ */
// 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
(* 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
(* 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); module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0; parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0; parameter [DEPTH-1:0] INIT = 0;

View File

@ -22,26 +22,21 @@
`ifndef _NO_FFS `ifndef _NO_FFS
`ifndef _NO_POS_SR
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
`endif
module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
`endif
`endif `endif

View File

@ -205,45 +205,41 @@ struct SynthXilinxPass : public ScriptPass
} }
if (check_label("fine")) { if (check_label("fine")) {
run("opt -fast"); // shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifiying variable-length shift registers,
// so attempt to convert $pmux-es to the former
if (!nosrl || help_mode)
run("pmux2shiftx", "(skip if '-nosrl')");
run("opt -fast -full");
run("memory_map"); run("memory_map");
run("dffsr2dff"); run("dffsr2dff");
run("dff2dffe"); run("dff2dffe");
run("opt -full");
if (!vpr || help_mode) if (!vpr || help_mode)
run("techmap -map +/xilinx/arith_map.v"); run("techmap -map +/xilinx/arith_map.v");
else else
run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
run("hierarchy -check");
run("opt -fast");
}
if (check_label("map_cells"))
{
if (!nosrl || help_mode) { if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level, // shregmap operates on bit-level flops, not word-level,
// so break those down here // so break those down here
run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')"); run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifiying variable-length shift registers,
// so attempt to convert $pmux-es to the former
run("pmux2shiftx", "(skip if '-nosrl')");
// pmux2shiftx can leave behind a $pmux with a single entry
// -- need this to clean that up before shregmap
run("opt_expr -mux_undef", "(skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs // shregmap with '-tech xilinx' infers variable length shift regs
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
} }
run("techmap -map +/xilinx/cells_map.v"); run("techmap");
run("opt -fast");
}
if (check_label("map_cells")) {
run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
run("clean"); run("clean");
} }
if (check_label("map_luts")) if (check_label("map_luts")) {
{
run("opt -full");
run("techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
if (help_mode) if (help_mode)
run("abc -luts 2:2,3,6:5,10,20 [-dff]"); run("abc -luts 2:2,3,6:5,10,20 [-dff]");
else else
@ -259,21 +255,18 @@ struct SynthXilinxPass : public ScriptPass
run("clean"); run("clean");
} }
if (check_label("check")) if (check_label("check")) {
{
run("hierarchy -check"); run("hierarchy -check");
run("stat"); run("stat");
run("check -noinit"); run("check -noinit");
} }
if (check_label("edif")) if (check_label("edif")) {
{
if (!edif_file.empty() || help_mode) if (!edif_file.empty() || help_mode)
run(stringf("write_edif -pvector bra %s", edif_file.c_str())); run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
} }
if (check_label("blif")) if (check_label("blif")) {
{
if (!blif_file.empty() || help_mode) if (!blif_file.empty() || help_mode)
run(stringf("write_blif %s", edif_file.c_str())); run(stringf("write_blif %s", edif_file.c_str()));
} }

View File

@ -0,0 +1,22 @@
module top
(
input [7:0] data_a,
input [6:1] addr_a,
input we_a, clk,
output reg [7:0] q_a
);
// Declare the RAM variable
reg [7:0] ram[63:0];
// Port A
always @ (posedge clk)
begin
if (we_a)
begin
ram[addr_a] <= data_a;
q_a <= data_a;
end
q_a <= ram[addr_a];
end
endmodule

View File

@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out);
assign out = bar[foo[0]]; assign out = bar[foo[0]];
endmodule endmodule
// ------------------------------------------------------
module mem2reg_test6 (din, dout);
input wire [3:0] din;
output reg [3:0] dout;
reg [1:0] din_array [1:0];
reg [1:0] dout_array [1:0];
always @* begin
din_array[0] = din[0 +: 2];
din_array[1] = din[2 +: 2];
dout_array[0] = din_array[0];
dout_array[1] = din_array[1];
{dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0];
dout[0 +: 2] = dout_array[0];
dout[2 +: 2] = dout_array[1];
end
endmodule

9
tests/simple/peepopt.v Normal file
View File

@ -0,0 +1,9 @@
module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o);
assign o = i[s*W+:W];
endmodule
module peepopt_muldiv_0(input [1:0] i, output [1:0] o);
wire [3:0] t;
assign t = i * 3;
assign o = t / 3;
endmodule

View File

@ -16,6 +16,7 @@ operators.v $pow
partsel.v drops modules partsel.v drops modules
process.v drops modules process.v drops modules
realexpr.v drops modules realexpr.v drops modules
retime.v Initial value (11110101) for (retime_test.ff) not supported
scopes.v original verilog issues ( -x where x isn't declared signed) scopes.v original verilog issues ( -x where x isn't declared signed)
sincos.v $adff sincos.v $adff
specify.v no code (empty module generates error specify.v no code (empty module generates error

View File

@ -11,13 +11,13 @@ echo "" > $STDERRFILE
echo -n "Test: ${TESTNAME} -> " echo -n "Test: ${TESTNAME} -> "
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE set -e
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
rm -f a.out reference_result.txt dut_result.txt rm -f a.out reference_result.txt dut_result.txt
set -e
iverilog -g2012 ${TESTNAME}_syn.v iverilog -g2012 ${TESTNAME}_syn.v
iverilog -g2012 ${TESTNAME}_ref_syn.v iverilog -g2012 ${TESTNAME}_ref_syn.v

View File

@ -147,7 +147,8 @@ do
fi fi
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
"$toolsdir"/../../techlibs/common/simlib.v "$toolsdir"/../../techlibs/common/simlib.v \
"$toolsdir"/../../techlibs/common/simcells.v
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
test_count=0 test_count=0