backend/verilog: Add alternate mode for transparent read port output.

This mode will be used whenever read port cannot be handled in the
"extract address register" way, ie. whenever it has enable, reset,
init functionality or (in the future) mixed transparency mask.
This commit is contained in:
Marcelina Kościelnicka 2021-05-25 23:42:58 +02:00
parent 4451f7f5e9
commit ec2a468bd3
1 changed files with 71 additions and 1 deletions

View File

@ -553,7 +553,17 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem)
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 = port.transparent;
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;
@ -618,6 +628,66 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem)
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.transparent)
continue;
if (!wport.clk_enable)
continue;
if (wport.clk != port.clk)
continue;
if (wport.clk_polarity != port.clk_polarity)
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 << " <= ";
dump_sigspec(os2, wport.data.extract(wsub * mem.width + pos, 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;