/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
RTLIL::Module *active_module;
dict<RTLIL::SigBit, RTLIL::State> active_initdata;
SigMap active_sigmap;
+IdString initial_id;
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{
if (GetSize(sig) == 0) {
- f << "\"\"";
+ // See IEEE 1364-2005 Clause 5.1.14.
+ f << "{0{1'b0}}";
return;
}
if (sig.is_chunk()) {
dump_const(f, wire->attributes.at(ID::init));
}
f << stringf(";\n");
- } else if (!wire->port_input && !wire->port_output)
+ } else
f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
#endif
}
int start = init.addr.as_int();
for (int i=0; i<words; i++)
{
- f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i + start);
- dump_const(f, init.data.extract(i*mem.width, mem.width));
- f << stringf(";\n");
+ for (int j = 0; j < mem.width; j++)
+ {
+ if (init.en[j] != State::S1)
+ continue;
+
+ int start_j = j, width = 1;
+
+ while (j+1 < mem.width && init.en[j+1] == State::S1)
+ j++, width++;
+
+ if (width == mem.width) {
+ f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i + start);
+ } else {
+ f << stringf("%s" " %s[%d][%d:%d] = ", indent.c_str(), mem_id.c_str(), i + start, j, start_j);
+ }
+ dump_const(f, init.data.extract(i*mem.width+start_j, width));
+ f << stringf(";\n");
+ }
}
}
f << stringf("%s" "end\n", indent.c_str());
clk_to_arst_cond[clk_domain_str] = os2.str();
}
}
- if (!port.transparent)
+
+ // Decide how to represent the transparency; same idea as Mem::extract_rdff.
+ bool trans_use_addr = true;
+ for (auto bit : port.transparency_mask)
+ if (!bit)
+ trans_use_addr = false;
+
+ if (GetSize(mem.wr_ports) == 0)
+ trans_use_addr = false;
+
+ if (port.en != State::S1 || port.srst != State::S0 || port.arst != State::S0 || !port.init_value.is_fully_undef())
+ trans_use_addr = false;
+
+ if (!trans_use_addr)
{
// for clocked read ports make something like:
// reg [..] temp_id;
clk_to_lof_body[clk_domain_str].push_back(os.str());
}
+ for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+ auto &wport = mem.wr_ports[i];
+ if (!port.transparency_mask[i] && !port.collision_x_mask[i])
+ continue;
+ int min_wide_log2 = std::min(port.wide_log2, wport.wide_log2);
+ int max_wide_log2 = std::max(port.wide_log2, wport.wide_log2);
+ bool wide_write = wport.wide_log2 > port.wide_log2;
+ for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) {
+ SigSpec raddr = port.addr;
+ SigSpec waddr = wport.addr;
+ if (wide_write)
+ waddr = wport.sub_addr(sub);
+ else
+ raddr = port.sub_addr(sub);
+ int pos = 0;
+ int ewidth = mem.width << min_wide_log2;
+ int wsub = wide_write ? sub : 0;
+ int rsub = wide_write ? 0 : sub;
+ while (pos < ewidth) {
+ int epos = pos;
+ while (epos < ewidth && wport.en[epos + wsub * mem.width] == wport.en[pos + wsub * mem.width])
+ epos++;
+
+ std::ostringstream os;
+ if (has_indent)
+ os << indent;
+ os << "if (";
+ dump_sigspec(os, wport.en[pos + wsub * mem.width]);
+ if (raddr != waddr) {
+ os << " && ";
+ dump_sigspec(os, raddr);
+ os << " == ";
+ dump_sigspec(os, waddr);
+ }
+ os << ")\n";
+ clk_to_lof_body[clk_domain_str].push_back(os.str());
+
+ std::ostringstream os2;
+ if (has_indent)
+ os2 << indent;
+ os2 << indent;
+ os2 << temp_id;
+ if (epos-pos != GetSize(port.data))
+ os2 << stringf("[%d:%d]", rsub * mem.width + epos-1, rsub * mem.width + pos);
+ os2 << " <= ";
+ if (port.transparency_mask[i])
+ dump_sigspec(os2, wport.data.extract(wsub * mem.width + pos, epos-pos));
+ else
+ dump_sigspec(os2, Const(State::Sx, epos - pos));
+ os2 << ";\n";
+ clk_to_lof_body[clk_domain_str].push_back(os2.str());
+
+ pos = epos;
+ }
+ }
+ }
+
if (port.srst != State::S0 && port.ce_over_srst)
{
std::ostringstream os;
FfData ff(nullptr, cell);
// $ff / $_FF_ cell: not supported.
- if (ff.has_d && !ff.has_clk && !ff.has_en)
+ if (ff.has_gclk)
return false;
std::string reg_name = cellname(cell);
for (int i = 0; i < chunks; i++)
{
- SigSpec sig_d;
+ SigSpec sig_d, sig_ad;
Const val_arst, val_srst;
- std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name;
+ std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name, sig_aload_name;
if (chunky) {
reg_bit_name = stringf("%s[%d]", reg_name.c_str(), i);
- if (ff.has_d)
+ if (ff.has_gclk || ff.has_clk)
sig_d = ff.sig_d[i];
+ if (ff.has_aload)
+ sig_ad = ff.sig_ad[i];
} else {
reg_bit_name = reg_name;
- if (ff.has_d)
- sig_d = ff.sig_d;
+ sig_d = ff.sig_d;
+ sig_ad = ff.sig_ad;
}
if (ff.has_arst)
val_arst = chunky ? ff.val_arst[i] : ff.val_arst;
val_srst = chunky ? ff.val_srst[i] : ff.val_srst;
// If there are constants in the sensitivity list, replace them with an intermediate wire
- if (ff.has_sr) {
- if (ff.sig_set[i].wire == NULL)
- {
- sig_set_name = next_auto_id();
- f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
- dump_const(f, ff.sig_set[i].data);
- f << stringf(";\n");
- }
- if (ff.sig_clr[i].wire == NULL)
- {
- sig_clr_name = next_auto_id();
- f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
- dump_const(f, ff.sig_clr[i].data);
- f << stringf(";\n");
- }
- } else if (ff.has_arst) {
- if (ff.sig_arst[i].wire == NULL)
- {
- sig_arst_name = next_auto_id();
- f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
- dump_const(f, ff.sig_arst[i].data);
- f << stringf(";\n");
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ if (ff.sig_set[i].wire == NULL)
+ {
+ sig_set_name = next_auto_id();
+ f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
+ dump_const(f, ff.sig_set[i].data);
+ f << stringf(";\n");
+ }
+ if (ff.sig_clr[i].wire == NULL)
+ {
+ sig_clr_name = next_auto_id();
+ f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
+ dump_const(f, ff.sig_clr[i].data);
+ f << stringf(";\n");
+ }
+ } else if (ff.has_arst) {
+ if (ff.sig_arst[0].wire == NULL)
+ {
+ sig_arst_name = next_auto_id();
+ f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
+ dump_const(f, ff.sig_arst[0].data);
+ f << stringf(";\n");
+ }
+ } else if (ff.has_aload) {
+ if (ff.sig_aload[0].wire == NULL)
+ {
+ sig_aload_name = next_auto_id();
+ f << stringf("%s" "wire %s = ", indent.c_str(), sig_aload_name.c_str());
+ dump_const(f, ff.sig_aload[0].data);
+ f << stringf(";\n");
+ }
}
}
f << stringf("%s", sig_clr_name.c_str());
else
dump_sigspec(f, ff.sig_clr[i]);
-
} else if (ff.has_arst) {
f << stringf(", %sedge ", ff.pol_arst ? "pos" : "neg");
- if (ff.sig_arst[i].wire == NULL)
+ if (ff.sig_arst[0].wire == NULL)
f << stringf("%s", sig_arst_name.c_str());
else
dump_sigspec(f, ff.sig_arst);
+ } else if (ff.has_aload) {
+ f << stringf(", %sedge ", ff.pol_aload ? "pos" : "neg");
+ if (ff.sig_aload[0].wire == NULL)
+ f << stringf("%s", sig_aload_name.c_str());
+ else
+ dump_sigspec(f, ff.sig_aload);
}
f << stringf(")\n");
f << stringf("%s" " else ", indent.c_str());
} else if (ff.has_arst) {
f << stringf("if (%s", ff.pol_arst ? "" : "!");
- if (ff.sig_arst[i].wire == NULL)
+ if (ff.sig_arst[0].wire == NULL)
f << stringf("%s", sig_arst_name.c_str());
else
dump_sigspec(f, ff.sig_arst);
dump_sigspec(f, val_arst);
f << stringf(";\n");
f << stringf("%s" " else ", indent.c_str());
+ } else if (ff.has_aload) {
+ f << stringf("if (%s", ff.pol_aload ? "" : "!");
+ if (ff.sig_aload[0].wire == NULL)
+ f << stringf("%s", sig_aload_name.c_str());
+ else
+ dump_sigspec(f, ff.sig_aload);
+ f << stringf(") %s <= ", reg_bit_name.c_str());
+ dump_sigspec(f, sig_ad);
+ f << stringf(";\n");
+ f << stringf("%s" " else ", indent.c_str());
}
- if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
- f << stringf("if (%s", ff.pol_en ? "" : "!");
- dump_sigspec(f, ff.sig_en);
+ if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
+ f << stringf("if (%s", ff.pol_ce ? "" : "!");
+ dump_sigspec(f, ff.sig_ce);
f << stringf(")\n");
f << stringf("%s" " if (%s", indent.c_str(), ff.pol_srst ? "" : "!");
dump_sigspec(f, ff.sig_srst);
f << stringf(";\n");
f << stringf("%s" " else ", indent.c_str());
}
- if (ff.has_en) {
- f << stringf("if (%s", ff.pol_en ? "" : "!");
- dump_sigspec(f, ff.sig_en);
+ if (ff.has_ce) {
+ f << stringf("if (%s", ff.pol_ce ? "" : "!");
+ dump_sigspec(f, ff.sig_ce);
f << stringf(") ");
}
}
f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
dump_sigspec(f, ff.sig_set[i]);
f << stringf(") %s = 1'b1;\n", reg_bit_name.c_str());
- if (ff.has_d)
+ if (ff.has_aload)
f << stringf("%s" " else ", indent.c_str());
} else if (ff.has_arst) {
f << stringf("if (%s", ff.pol_arst ? "" : "!");
f << stringf(") %s = ", reg_bit_name.c_str());
dump_sigspec(f, val_arst);
f << stringf(";\n");
- if (ff.has_d)
+ if (ff.has_aload)
f << stringf("%s" " else ", indent.c_str());
}
- if (ff.has_d) {
- f << stringf("if (%s", ff.pol_en ? "" : "!");
- dump_sigspec(f, ff.sig_en);
+ if (ff.has_aload) {
+ f << stringf("if (%s", ff.pol_aload ? "" : "!");
+ dump_sigspec(f, ff.sig_aload);
f << stringf(") %s = ", reg_bit_name.c_str());
- dump_sigspec(f, sig_d);
+ dump_sigspec(f, sig_ad);
f << stringf(";\n");
}
}
f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
if (!systemverilog)
- f << indent + " " << "if (" << id("\\initial") << ") begin end\n";
+ f << indent + " " << "if (" << id(initial_id) << ") begin end\n";
dump_case_body(f, indent, &proc->root_case, true);
std::string backup_indent = indent;
dump_attributes(f, indent, module->attributes, '\n', /*modattr=*/true);
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
+ int cnt = 0;
for (int port_id = 1; keep_running; port_id++) {
keep_running = false;
for (auto wire : module->wires()) {
f << stringf(", ");
f << stringf("%s", id(wire->name).c_str());
keep_running = true;
+ if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
continue;
}
}
}
f << stringf(");\n");
-
- if (!systemverilog && !module->processes.empty())
- f << indent + " " << "reg " << id("\\initial") << " = 0;\n";
+ if (!systemverilog && !module->processes.empty()) {
+ initial_id = NEW_ID;
+ f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
+ }
for (auto w : module->wires())
dump_wire(f, indent + " ", w);
extmem_prefix = filename.substr(0, filename.rfind('.'));
}
+ log_push();
+ Pass::call(design, "bmuxmap");
+ Pass::call(design, "demuxmap");
+ Pass::call(design, "clean_zerowidth");
+ log_pop();
+
design->sort();
*f << stringf("/* Generated by %s */\n", yosys_version_str);