mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'master' of github.com:YosysHQ/yosys into clifford/fix968
This commit is contained in:
commit
d187be39d6
|
@ -163,31 +163,61 @@ struct FirrtlWorker
|
|||
}
|
||||
};
|
||||
/* Memories defined within this module. */
|
||||
struct memory {
|
||||
string name; // memory name
|
||||
int abits; // number of address bits
|
||||
int size; // size (in units) of the memory
|
||||
int width; // size (in bits) of each element
|
||||
int read_latency;
|
||||
int write_latency;
|
||||
vector<read_port> read_ports;
|
||||
vector<write_port> write_ports;
|
||||
std::string init_file;
|
||||
std::string init_file_srcFileSpec;
|
||||
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("") {}
|
||||
memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
|
||||
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;
|
||||
struct memory {
|
||||
Cell *pCell; // for error reporting
|
||||
string name; // memory name
|
||||
int abits; // number of address bits
|
||||
int size; // size (in units) of the memory
|
||||
int width; // size (in bits) of each element
|
||||
int read_latency;
|
||||
int write_latency;
|
||||
vector<read_port> read_ports;
|
||||
vector<write_port> write_ports;
|
||||
std::string init_file;
|
||||
std::string init_file_srcFileSpec;
|
||||
string srcLine;
|
||||
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("") {
|
||||
// Provide defaults for abits or size if one (but not the other) is specified.
|
||||
if (this->abits == 0 && this->size != 0) {
|
||||
this->abits = ceil_log2(this->size);
|
||||
} else if (this->abits != 0 && this->size == 0) {
|
||||
this->size = 1 << this->abits;
|
||||
}
|
||||
// Sanity-check this construction.
|
||||
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;
|
||||
|
||||
void register_memory(memory &m)
|
||||
|
@ -604,7 +634,7 @@ struct FirrtlWorker
|
|||
int abits = cell->parameters.at("\\ABITS").as_int();
|
||||
int width = cell->parameters.at("\\WIDTH").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 wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
|
||||
|
||||
|
@ -681,6 +711,8 @@ struct FirrtlWorker
|
|||
{
|
||||
std::string cell_type = fid(cell->type);
|
||||
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;
|
||||
if (cell->type == "$meminit" ) {
|
||||
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_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);
|
||||
int portNum = 0;
|
||||
bool transparency = false;
|
||||
|
@ -890,7 +927,7 @@ struct FirrtlWorker
|
|||
|
||||
// If we have any memory definitions, output them.
|
||||
for (auto kv : memories) {
|
||||
memory m = kv.second;
|
||||
memory &m = kv.second;
|
||||
f << stringf(" mem %s:\n", m.name.c_str());
|
||||
f << stringf(" data-type => UInt<%d>\n", m.width);
|
||||
f << stringf(" depth => %d\n", m.size);
|
||||
|
|
|
@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (!id_ast->children[0]->range_valid)
|
||||
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;
|
||||
if (children.size() > 1)
|
||||
range = children[1];
|
||||
} else
|
||||
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
|
||||
if (range) {
|
||||
|
|
|
@ -1605,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
current_scope[wire_tmp->str] = wire_tmp;
|
||||
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, 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);
|
||||
wire_tmp_id->str = wire_tmp->str;
|
||||
|
|
|
@ -45,7 +45,7 @@ YOSYS_NAMESPACE_END
|
|||
USING_YOSYS_NAMESPACE
|
||||
%}
|
||||
|
||||
%name-prefix "rtlil_frontend_ilang_yy"
|
||||
%define api.prefix {rtlil_frontend_ilang_yy}
|
||||
|
||||
%union {
|
||||
char *string;
|
||||
|
|
|
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
|
|||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
||||
"final" { SV_KEYWORD(TOK_FINAL); }
|
||||
"logic" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"var" { SV_KEYWORD(TOK_VAR); }
|
||||
"bit" { SV_KEYWORD(TOK_REG); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
|
|
|
@ -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 {
|
||||
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 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 TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%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_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
|
||||
|
@ -456,6 +456,9 @@ wire_type_token:
|
|||
TOK_LOGIC {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_VAR {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_INTEGER {
|
||||
astbuf3->is_reg = true;
|
||||
astbuf3->range_left = 31;
|
||||
|
@ -1341,6 +1344,9 @@ opt_property:
|
|||
TOK_PROPERTY {
|
||||
$$ = true;
|
||||
} |
|
||||
TOK_FINAL {
|
||||
$$ = false;
|
||||
} |
|
||||
/* empty */ {
|
||||
$$ = false;
|
||||
};
|
||||
|
|
|
@ -291,7 +291,7 @@ struct QwpWorker
|
|||
// gaussian elimination
|
||||
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);
|
||||
|
||||
// find best row
|
||||
|
|
|
@ -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();
|
||||
|
||||
SigPool used_signals;
|
||||
|
@ -281,6 +285,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
|
|||
for (auto &it2 : cell->connections_) {
|
||||
assign_map.apply(it2.second);
|
||||
used_signals.add(it2.second);
|
||||
raw_used_signals_noaliases.add(it2.second);
|
||||
if (!ct_all.cell_output(cell->type, it2.first))
|
||||
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())
|
||||
{
|
||||
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
|
||||
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
|
||||
assign_map.apply(s2);
|
||||
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
|
||||
maybe_del_wires.push_back(wire);
|
||||
} else {
|
||||
log_assert(GetSize(s1) == GetSize(s2));
|
||||
Const initval;
|
||||
if (wire->attributes.count("\\init"))
|
||||
initval = wire->attributes.at("\\init");
|
||||
if (GetSize(initval) != GetSize(wire))
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
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);
|
||||
}
|
||||
}
|
||||
SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
|
||||
log_assert(GetSize(s1) == GetSize(s2));
|
||||
|
||||
Const initval;
|
||||
if (wire->attributes.count("\\init"))
|
||||
initval = wire->attributes.at("\\init");
|
||||
if (GetSize(initval) != GetSize(wire))
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
if (initval.is_fully_undef())
|
||||
wire->attributes.erase("\\init");
|
||||
|
||||
bool delete_this_wire = false;
|
||||
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 */
|
||||
} else {
|
||||
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
|
||||
maybe_del_wires.push_back(wire);
|
||||
if (!raw_used_signals_noaliases.check_any(s1))
|
||||
delete_this_wire = true;
|
||||
if (!used_signals_nodrivers.check_any(s2))
|
||||
delete_this_wire = true;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
|
||||
if (!used_signals_nodrivers.check_any(sig)) {
|
||||
if (delete_this_wire) {
|
||||
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;
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
if (sig[i].wire == NULL)
|
||||
for (int i = 0; i < GetSize(s2); i++) {
|
||||
if (s2[i].wire == NULL)
|
||||
continue;
|
||||
if (!used_signals_nodrivers.check(sig[i])) {
|
||||
if (!used_signals_nodrivers.check(s2[i])) {
|
||||
if (!unused_bits.empty())
|
||||
unused_bits += " ";
|
||||
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;
|
||||
for (auto wire : maybe_del_wires)
|
||||
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);
|
||||
if (verbose && del_temp_wires_count)
|
||||
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
|
||||
}
|
||||
|
||||
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
|
||||
|
@ -526,6 +536,9 @@ struct OptCleanPass : public Pass {
|
|||
|
||||
ct_all.setup(design);
|
||||
|
||||
count_rm_cells = 0;
|
||||
count_rm_wires = 0;
|
||||
|
||||
for (auto module : design->selected_whole_modules_warn()) {
|
||||
if (module->has_processes_warn())
|
||||
continue;
|
||||
|
@ -591,7 +604,7 @@ struct CleanPass : public Pass {
|
|||
for (auto module : design->selected_whole_modules()) {
|
||||
if (module->has_processes())
|
||||
continue;
|
||||
rmunused_module(module, purge_mode, false, false);
|
||||
rmunused_module(module, purge_mode, ys_debug(), false);
|
||||
}
|
||||
|
||||
log_suppressed();
|
||||
|
|
|
@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
|
|||
}
|
||||
if (wire->port_input)
|
||||
driven_signals.add(sigmap(wire));
|
||||
if (wire->port_output)
|
||||
if (wire->port_output || wire->get_bool_attribute("\\keep"))
|
||||
used_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);
|
||||
did_something = true;
|
||||
}
|
||||
|
@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
|
|||
if (SigBit(initval[i]) == sig[i])
|
||||
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");
|
||||
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;
|
||||
did_something = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -531,6 +531,42 @@ struct WreducePass : public Pass {
|
|||
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")) {
|
||||
IdString memid = c->getParam("\\MEMID").decode_string();
|
||||
RTLIL::Memory *mem = module->memories.at(memid);
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
/ice40_dsp_pm.h
|
||||
/peepopt_pm.h
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
OBJS += passes/pmgen/ice40_dsp.o
|
||||
OBJS += passes/pmgen/peepopt.o
|
||||
|
||||
# --------------------------------------
|
||||
|
||||
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
|
||||
EXTRA_OBJS += 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
|
||||
$(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 $<,$^)
|
||||
|
|
|
@ -29,19 +29,25 @@ up in any future matches:
|
|||
|
||||
pm.blacklist(some_cell);
|
||||
|
||||
The `.run(callback_function)` method searches for all matches and calls the
|
||||
callback function for each found match:
|
||||
The `.run_<pattern_name>(callback_function)` method searches for all matches
|
||||
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(" with 'bar' cell: %s\n", log_id(pm.st.bar));
|
||||
});
|
||||
|
||||
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
|
||||
`.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
|
||||
|
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
|
|||
|
||||
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
|
||||
-------------------------
|
||||
|
||||
|
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
|
|||
and saved and restored as needed.
|
||||
|
||||
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
|
||||
-------------------------
|
||||
|
|
|
@ -19,47 +19,50 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
void create_ice40_dsp(ice40_dsp_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_ice40_dsp;
|
||||
|
||||
#if 0
|
||||
log("\n");
|
||||
log("ffA: %s\n", log_id(pm.st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(pm.st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(pm.st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(pm.st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(pm.st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(pm.st.ffS, "--"));
|
||||
log("ffA: %s\n", log_id(st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(st.ffS, "--"));
|
||||
#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) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
|
||||
if (GetSize(st.sigA) > 16) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
|
||||
if (GetSize(st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
|
||||
if (GetSize(st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
|
||||
if (GetSize(st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
|
||||
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) {
|
||||
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");
|
||||
|
||||
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
|
||||
|
||||
SigSpec A = pm.st.sigA;
|
||||
SigSpec A = st.sigA;
|
||||
A.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec B = pm.st.sigB;
|
||||
SigSpec B = st.sigB;
|
||||
B.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec CD;
|
||||
if (pm.st.muxA)
|
||||
CD = pm.st.muxA->getPort("\\B");
|
||||
if (pm.st.muxB)
|
||||
CD = pm.st.muxB->getPort("\\A");
|
||||
if (st.muxA)
|
||||
CD = st.muxA->getPort("\\B");
|
||||
if (st.muxB)
|
||||
CD = st.muxB->getPort("\\A");
|
||||
CD.extend_u0(32, mul_signed);
|
||||
|
||||
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("\\D", CD.extract(16, 16));
|
||||
|
||||
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
|
||||
cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
|
||||
|
||||
cell->setPort("\\AHOLD", 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("\\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->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)
|
||||
log(" ffA:%s", log_id(pm.st.ffA));
|
||||
if (st.ffA)
|
||||
log(" ffA:%s", log_id(st.ffA));
|
||||
|
||||
if (pm.st.ffB)
|
||||
log(" ffB:%s", log_id(pm.st.ffB));
|
||||
if (st.ffB)
|
||||
log(" ffB:%s", log_id(st.ffB));
|
||||
|
||||
if (pm.st.ffY)
|
||||
log(" ffY:%s", log_id(pm.st.ffY));
|
||||
if (st.ffY)
|
||||
log(" ffY:%s", log_id(st.ffY));
|
||||
|
||||
if (pm.st.ffS)
|
||||
log(" ffS:%s", log_id(pm.st.ffS));
|
||||
if (st.ffS)
|
||||
log(" ffS:%s", log_id(st.ffS));
|
||||
|
||||
log("\n");
|
||||
}
|
||||
|
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
|
||||
// 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)
|
||||
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
|
||||
|
||||
cell->setPort("\\O", O);
|
||||
|
||||
if (pm.st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
if (st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
} else {
|
||||
cell->setPort("\\ADDSUBTOP", State::S0);
|
||||
cell->setPort("\\ADDSUBBOT", State::S0);
|
||||
|
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
cell->setPort("\\OHOLDBOT", State::S0);
|
||||
|
||||
SigSpec acc_reset = State::S0;
|
||||
if (pm.st.muxA)
|
||||
acc_reset = pm.st.muxA->getPort("\\S");
|
||||
if (pm.st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
|
||||
if (st.muxA)
|
||||
acc_reset = st.muxA->getPort("\\S");
|
||||
if (st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
|
||||
|
||||
cell->setPort("\\OLOADTOP", 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("\\D_REG", State::S0);
|
||||
|
||||
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\PIPELINE_16x16_MULT_REG1", 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", 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("\\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_UPPERINPUT", State::S0);
|
||||
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_UPPERINPUT", State::S0);
|
||||
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("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
|
||||
|
||||
pm.autoremove(pm.st.mul);
|
||||
pm.autoremove(pm.st.ffY);
|
||||
pm.autoremove(pm.st.ffS);
|
||||
pm.autoremove(st.mul);
|
||||
pm.autoremove(st.ffY);
|
||||
pm.autoremove(st.ffS);
|
||||
}
|
||||
|
||||
struct Ice40DspPass : public Pass {
|
||||
|
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
|
|||
extra_args(args, argidx, design);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pattern ice40_dsp
|
||||
|
||||
state <SigBit> clock
|
||||
state <bool> clock_pol clock_vld
|
||||
state <SigSpec> sigA sigB sigY sigS
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -3,15 +3,42 @@
|
|||
import re
|
||||
import sys
|
||||
import pprint
|
||||
import getopt
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
pmgfile = sys.argv[1]
|
||||
assert pmgfile.endswith(".pmg")
|
||||
prefix = pmgfile[0:-4]
|
||||
prefix = prefix.split('/')[-1]
|
||||
outfile = sys.argv[2]
|
||||
prefix = None
|
||||
pmgfiles = list()
|
||||
outfile = None
|
||||
debug = False
|
||||
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()
|
||||
udata_types = dict()
|
||||
blocks = list()
|
||||
|
@ -77,7 +104,8 @@ def rewrite_cpp(s):
|
|||
|
||||
return "".join(t)
|
||||
|
||||
with open(pmgfile, "r") as f:
|
||||
def process_pmgfile(f):
|
||||
global current_pattern
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line == "": break
|
||||
|
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
|
|||
if len(cmd) == 0 or cmd[0].startswith("//"): continue
|
||||
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":
|
||||
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
|
||||
type_str = m.group(1)
|
||||
states_str = m.group(2)
|
||||
for s in re.split(r"\s+", states_str):
|
||||
assert s not in state_types
|
||||
state_types[s] = type_str
|
||||
assert s not in state_types[current_pattern]
|
||||
state_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "udata":
|
||||
|
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
|
|||
type_str = m.group(1)
|
||||
udatas_str = m.group(2)
|
||||
for s in re.split(r"\s+", udatas_str):
|
||||
assert s not in udata_types
|
||||
udata_types[s] = type_str
|
||||
assert s not in udata_types[current_pattern]
|
||||
udata_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "match":
|
||||
block = dict()
|
||||
block["type"] = "match"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
line = line.split()
|
||||
assert len(line) == 2
|
||||
assert line[1] not in state_types
|
||||
assert line[1] not in state_types[current_pattern]
|
||||
block["cell"] = line[1]
|
||||
state_types[line[1]] = "Cell*";
|
||||
state_types[current_pattern][line[1]] = "Cell*";
|
||||
|
||||
block["if"] = list()
|
||||
block["select"] = list()
|
||||
|
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
|
|||
assert False
|
||||
|
||||
blocks.append(block)
|
||||
continue
|
||||
|
||||
if cmd == "code":
|
||||
block = dict()
|
||||
block["type"] = "code"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
block["code"] = list()
|
||||
block["states"] = set()
|
||||
|
||||
for s in line.split()[1:]:
|
||||
assert s in state_types
|
||||
assert s in state_types[current_pattern]
|
||||
block["states"].add(s)
|
||||
|
||||
while True:
|
||||
|
@ -179,17 +228,36 @@ with open(pmgfile, "r") as f:
|
|||
block["code"].append(rewrite_cpp(l.rstrip()))
|
||||
|
||||
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:
|
||||
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("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
if genhdr:
|
||||
print("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("struct {}_pm {{".format(prefix), file=f)
|
||||
print(" Module *module;", file=f)
|
||||
|
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
|
|||
print(" int rollback;", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct state_t {", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } st;", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" struct state_{}_t {{".format(current_pattern), file=f)
|
||||
for s, t in sorted(state_types[current_pattern].items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" }} st_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct udata_t {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } ud;", file=f)
|
||||
print("", file=f)
|
||||
print(" struct udata_{}_t {{".format(current_pattern), file=f)
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" }} ud_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
current_pattern = None
|
||||
|
||||
for v, n in sorted(ids.items()):
|
||||
if n[0] == "\\":
|
||||
|
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
|
|||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void check_blacklist() {", file=f)
|
||||
print(" if (!blacklist_dirty)", file=f)
|
||||
print(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["type"] == "match":
|
||||
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
|
||||
print(" rollback = {};".format(index+1), file=f)
|
||||
print(" return;", file=f)
|
||||
print(" }", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
|
||||
print(" if (!blacklist_dirty)", file=f)
|
||||
print(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["pattern"] != current_pattern:
|
||||
continue
|
||||
if block["type"] == "match":
|
||||
print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
|
||||
print(" rollback = {};".format(index+1), file=f)
|
||||
print(" return;", 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(" 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(" module(module), sigmap(module) {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" ud.{} = {}();".format(s, t), file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud_{}.{} = nullptr;".format(current_pattern,s), 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 &conn : cell->connections())", 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(" void run(std::function<void()> on_accept_f) {", file=f)
|
||||
print(" on_accept = on_accept_f;", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" st.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" st.{} = {}();".format(s, t), file=f)
|
||||
print(" block_0();", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
|
||||
print(" run([&](){on_accept_f(*this);});", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
|
||||
print(" on_accept = on_accept_f;", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
|
||||
else:
|
||||
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
||||
print(" block_{}();".format(patterns[current_pattern]), file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
|
||||
print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), 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)):
|
||||
block = blocks[index]
|
||||
|
||||
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()
|
||||
nonconst_st = set()
|
||||
restore_st = set()
|
||||
|
||||
for i in range(index):
|
||||
for i in range(patterns[current_pattern], index):
|
||||
if blocks[i]["type"] == "code":
|
||||
for s in blocks[i]["states"]:
|
||||
const_st.add(s)
|
||||
|
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
|
|||
assert False
|
||||
|
||||
for s in sorted(const_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
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:
|
||||
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):
|
||||
t = state_types[s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
|
||||
|
||||
if len(restore_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} backup_{} = {};".format(t, s, s), file=f)
|
||||
|
||||
if block["type"] == "code":
|
||||
print("", file=f)
|
||||
print(" do {", file=f)
|
||||
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
|
||||
print("#define accept do { on_accept(); check_blacklist(); if (rollback) 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)".format(current_pattern), file=f)
|
||||
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
|
||||
|
||||
for line in block["code"]:
|
||||
|
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
|
|||
if len(restore_st) or len(nonconst_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} = backup_{};".format(s, s), file=f)
|
||||
for s in sorted(nonconst_st):
|
||||
if s not in restore_st:
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
if t.endswith("*"):
|
||||
print(" {} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
|
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
|
|||
else:
|
||||
assert False
|
||||
|
||||
|
||||
current_pattern = None
|
||||
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("YOSYS_NAMESPACE_END", file=f)
|
||||
|
||||
# pp.pprint(blocks)
|
||||
if genhdr:
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_END", file=f)
|
||||
|
|
|
@ -508,7 +508,7 @@ struct ExposePass : public Pass {
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -1169,6 +1169,7 @@ struct SatPass : public Pass {
|
|||
if (args[argidx] == "-tempinduct-def") {
|
||||
tempinduct = true;
|
||||
tempinduct_def = true;
|
||||
enable_undef = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-tempinduct-baseonly") {
|
||||
|
|
|
@ -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 abc_sname = abc_name.substr(1);
|
||||
if (abc_sname.substr(0, 5) == "ys__n") {
|
||||
bool inv = abc_sname.back() == 'v';
|
||||
if (inv) abc_sname.pop_back();
|
||||
bool isnew = false;
|
||||
if (abc_sname.substr(0, 4) == "new_")
|
||||
{
|
||||
abc_sname.erase(0, 4);
|
||||
isnew = true;
|
||||
}
|
||||
if (abc_sname.substr(0, 5) == "ys__n")
|
||||
{
|
||||
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);
|
||||
for (auto sig : signal_list) {
|
||||
if (sig.id == sid && sig.bit.wire != nullptr) {
|
||||
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
|
||||
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;
|
||||
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
|
||||
if (sig.bit.wire->width != 1)
|
||||
sstr << "[" << sig.bit.offset << "]";
|
||||
if (inv)
|
||||
sstr << "_inv";
|
||||
if (isnew)
|
||||
sstr << "_new";
|
||||
sstr << postfix;
|
||||
if (orig_wire != nullptr)
|
||||
*orig_wire = sig.bit.wire;
|
||||
return sstr.str();
|
||||
|
|
|
@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
|
|||
if (wire->attributes.count("\\init")) {
|
||||
Const value = wire->attributes.at("\\init");
|
||||
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)
|
||||
for (auto bit : sigmap(wire))
|
||||
|
|
|
@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech
|
|||
|
||||
// Only map if $shiftx exclusively covers the shift register
|
||||
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;
|
||||
}
|
||||
else if (shiftx->type == "$mux") {
|
||||
|
|
|
@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
if (help_mode)
|
||||
run("techmap -map +/cmp2lut.v", " (if -lut)");
|
||||
else
|
||||
|
|
|
@ -241,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
run("share");
|
||||
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
|
||||
run("opt_expr");
|
||||
|
|
|
@ -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);
|
||||
parameter DEPTH = 0;
|
||||
parameter [DEPTH-1:0] INIT = 0;
|
||||
|
|
|
@ -22,26 +22,21 @@
|
|||
|
||||
`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_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_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_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_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_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
|
||||
`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
|
||||
|
||||
|
|
|
@ -205,45 +205,41 @@ struct SynthXilinxPass : public ScriptPass
|
|||
}
|
||||
|
||||
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("dffsr2dff");
|
||||
run("dff2dffe");
|
||||
run("opt -full");
|
||||
|
||||
if (!vpr || help_mode)
|
||||
run("techmap -map +/xilinx/arith_map.v");
|
||||
else
|
||||
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) {
|
||||
// shregmap operates on bit-level flops, not word-level,
|
||||
// so break those down here
|
||||
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
|
||||
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");
|
||||
}
|
||||
|
||||
if (check_label("map_luts"))
|
||||
{
|
||||
run("opt -full");
|
||||
run("techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
|
||||
if (check_label("map_luts")) {
|
||||
if (help_mode)
|
||||
run("abc -luts 2:2,3,6:5,10,20 [-dff]");
|
||||
else
|
||||
|
@ -259,21 +255,18 @@ struct SynthXilinxPass : public ScriptPass
|
|||
run("clean");
|
||||
}
|
||||
|
||||
if (check_label("check"))
|
||||
{
|
||||
if (check_label("check")) {
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
}
|
||||
|
||||
if (check_label("edif"))
|
||||
{
|
||||
if (check_label("edif")) {
|
||||
if (!edif_file.empty() || help_mode)
|
||||
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("blif"))
|
||||
{
|
||||
if (check_label("blif")) {
|
||||
if (!blif_file.empty() || help_mode)
|
||||
run(stringf("write_blif %s", edif_file.c_str()));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out);
|
|||
assign out = bar[foo[0]];
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -16,6 +16,7 @@ operators.v $pow
|
|||
partsel.v drops modules
|
||||
process.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)
|
||||
sincos.v $adff
|
||||
specify.v no code (empty module generates error
|
||||
|
|
|
@ -11,13 +11,13 @@ echo "" > $STDERRFILE
|
|||
|
||||
echo -n "Test: ${TESTNAME} -> "
|
||||
|
||||
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE
|
||||
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
|
||||
set -e
|
||||
|
||||
$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
|
||||
|
||||
set -e
|
||||
|
||||
iverilog -g2012 ${TESTNAME}_syn.v
|
||||
iverilog -g2012 ${TESTNAME}_ref_syn.v
|
||||
|
||||
|
|
|
@ -147,7 +147,8 @@ do
|
|||
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 \
|
||||
"$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
|
||||
|
||||
test_count=0
|
||||
|
|
Loading…
Reference in New Issue