From c4cc888b2c51a6507b73fdcde1dc61c37384105d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 22 May 2021 19:14:13 +0200 Subject: kernel/rtlil: Extract some helpers for checking memory cell types. There will soon be more (versioned) memory cells, so handle passes that only care if a cell is memory-related by a simple helper call instead of a hardcoded list. --- backends/verilog/verilog_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 165ce1ea4..cfdc0316a 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1464,7 +1464,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) { // Handled by dump_memory - if (cell->type.in(ID($mem), ID($memwr), ID($memrd), ID($meminit))) + if (cell->is_mem_cell()) return; if (cell->type[0] == '$' && !noexpr) { -- cgit v1.2.3 From 64ba3c384255335d61e2d07160c57fa74156cde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 25 May 2021 22:37:03 +0200 Subject: backends/verilog: Try to preserve mem write port priorities. --- backends/verilog/verilog_backend.cc | 116 ++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 32 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index cfdc0316a..27a032586 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -594,48 +594,100 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) } } - // write ports - for (auto &port : mem.wr_ports) + // Write ports. Those are messy because we try to preserve priority, as much as we can: + // + // 1. We split all ports into several disjoint processes. + // 2. If a port has priority over another port, the two ports need to share + // a process, so that priority can be reconstructed on the other end. + // 3. We want each process to be as small as possible, to avoid extra + // priorities inferred on the other end. + pool wr_ports_done; + for (int ridx = 0; ridx < GetSize(mem.wr_ports); ridx++) { + if (wr_ports_done.count(ridx)) + continue; + + auto &root = mem.wr_ports[ridx]; + + // Start from a root. + pool wr_ports_now; + wr_ports_now.insert(ridx); + + // Transitively fill list of ports in this process by following priority edges. + while (true) { - std::ostringstream os; - dump_sigspec(os, port.clk); - clk_domain_str = stringf("%sedge %s", port.clk_polarity ? "pos" : "neg", os.str().c_str()); - if( clk_to_lof_body.count(clk_domain_str) == 0 ) - clk_to_lof_body[clk_domain_str] = std::vector(); + bool changed = false; + + for (int i = 0; i < GetSize(mem.wr_ports); i++) + for (int j = 0; j < i; j++) + if (mem.wr_ports[i].priority_mask[j]) + { + if (wr_ports_now.count(i) && !wr_ports_now.count(j)) { + wr_ports_now.insert(j); + changed = true; + } + if (!wr_ports_now.count(i) && wr_ports_now.count(j)) { + wr_ports_now.insert(i); + changed = true; + } + } + + if (!changed) + break; } - // make something like: - // always @(posedge clk) - // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; - // ... - for (int i = 0; i < GetSize(port.en); i++) - { - int start_i = i, width = 1; - SigBit wen_bit = port.en[i]; - while (i+1 < GetSize(port.en) && active_sigmap(port.en[i+1]) == active_sigmap(wen_bit)) - i++, width++; + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg"); + dump_sigspec(f, root.clk); + f << ") begin\n"; - if (wen_bit == State::S0) + for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) + { + if (!wr_ports_now.count(pidx)) continue; + wr_ports_done.insert(pidx); + + auto &port = mem.wr_ports[pidx]; + log_assert(port.clk_enable == root.clk_enable); + if (port.clk_enable) { + log_assert(port.clk == root.clk); + log_assert(port.clk_polarity == root.clk_polarity); + } - std::ostringstream os; - if (wen_bit != State::S1) + // make something like: + // always @(posedge clk) + // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; + // ... + for (int i = 0; i < GetSize(port.en); i++) { - os << stringf("if ("); - dump_sigspec(os, wen_bit); - os << stringf(") "); + int start_i = i, width = 1; + SigBit wen_bit = port.en[i]; + + while (i+1 < GetSize(port.en) && active_sigmap(port.en[i+1]) == active_sigmap(wen_bit)) + i++, width++; + + if (wen_bit == State::S0) + continue; + + f << stringf("%s%s", indent.c_str(), indent.c_str()); + if (wen_bit != State::S1) + { + f << stringf("if ("); + dump_sigspec(f, wen_bit); + f << stringf(")\n"); + f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str()); + } + f << stringf("%s[", mem_id.c_str()); + dump_sigspec(f, port.addr); + if (width == GetSize(port.en)) + f << stringf("] <= "); + else + f << stringf("][%d:%d] <= ", i, start_i); + dump_sigspec(f, port.data.extract(start_i, width)); + f << stringf(";\n"); } - os << stringf("%s[", mem_id.c_str()); - dump_sigspec(os, port.addr); - if (width == GetSize(port.en)) - os << stringf("] <= "); - else - os << stringf("][%d:%d] <= ", i, start_i); - dump_sigspec(os, port.data.extract(start_i, width)); - os << stringf(";\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); } + + f << stringf("%s" "end\n", indent.c_str()); } // Output Verilog that looks something like this: // reg [..] _3_; -- cgit v1.2.3 From aabe1c382e635040d16b6a29c7e2741e8e9d7adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 26 May 2021 01:18:29 +0200 Subject: backends/verilog: Add wide port support. --- backends/verilog/verilog_backend.cc | 131 ++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 43 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 27a032586..95ad69c81 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -541,19 +541,36 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) // assign r_data = temp_id; std::string temp_id = next_auto_id(); lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.data.size() - 1, temp_id.c_str()) ); + + bool has_en = port.en != State::S1; + + if (has_en) { std::ostringstream os; - if (port.en != RTLIL::SigBit(true)) - { - os << stringf("if ("); - dump_sigspec(os, port.en); - os << stringf(") "); - } - os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str()); - dump_sigspec(os, port.addr); + os << stringf("if ("); + dump_sigspec(os, port.en); + os << stringf(") begin\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); + } + + for (int sub = 0; sub < (1 << port.wide_log2); sub++) + { + SigSpec addr = port.sub_addr(sub); + std::ostringstream os; + if (has_en) + os << indent; + os << temp_id; + if (port.wide_log2) + os << stringf("[%d:%d]", (sub + 1) * mem.width - 1, sub * mem.width); + os << stringf(" <= %s[", mem_id.c_str()); + dump_sigspec(os, addr); os << stringf("];\n"); clk_to_lof_body[clk_domain_str].push_back(os.str()); } + + if (has_en) + clk_to_lof_body[clk_domain_str].push_back("end\n"); + { std::ostringstream os; dump_sigspec(os, port.data); @@ -569,28 +586,48 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) // temp_id <= r_addr; // assign r_data = array_reg[temp_id]; std::string temp_id = next_auto_id(); - lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.addr.size() - 1, temp_id.c_str()) ); + lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.addr.size() - 1 - port.wide_log2, temp_id.c_str()) ); { std::ostringstream os; - dump_sigspec(os, port.addr); + dump_sigspec(os, port.addr.extract_end(port.wide_log2)); std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str()); clk_to_lof_body[clk_domain_str].push_back(line); } + for (int sub = 0; sub < (1 << port.wide_log2); sub++) { std::ostringstream os; - dump_sigspec(os, port.data); - std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str()); - clk_to_lof_body[""].push_back(line); + os << "assign "; + dump_sigspec(os, port.data.extract(sub * mem.width, mem.width)); + os << stringf(" = %s[", mem_id.c_str());; + if (port.wide_log2) { + Const addr_lo; + for (int i = 0; i < port.wide_log2; i++) + addr_lo.bits.push_back(State(sub >> i & 1)); + os << "{"; + os << temp_id; + os << ", "; + dump_const(os, addr_lo); + os << "}"; + } else { + os << temp_id; + } + os << "];\n"; + clk_to_lof_body[""].push_back(os.str()); } } } else { // for non-clocked read-ports make something like: // assign r_data = array_reg[r_addr]; - std::ostringstream os, os2; - dump_sigspec(os, port.data); - dump_sigspec(os2, port.addr); - std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); - clk_to_lof_body[""].push_back(line); + for (int sub = 0; sub < (1 << port.wide_log2); sub++) + { + SigSpec addr = port.sub_addr(sub); + + std::ostringstream os, os2; + dump_sigspec(os, port.data.extract(sub * mem.width, mem.width)); + dump_sigspec(os2, addr); + std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); + clk_to_lof_body[""].push_back(line); + } } } @@ -636,9 +673,13 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) break; } - f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg"); - dump_sigspec(f, root.clk); - f << ") begin\n"; + if (root.clk_enable) { + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg"); + dump_sigspec(f, root.clk); + f << ") begin\n"; + } else { + f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_latch" : " @*"); + } for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) { @@ -657,33 +698,37 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) // always @(posedge clk) // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; // ... - for (int i = 0; i < GetSize(port.en); i++) + for (int sub = 0; sub < (1 << port.wide_log2); sub++) { - int start_i = i, width = 1; - SigBit wen_bit = port.en[i]; + SigSpec addr = port.sub_addr(sub); + for (int i = 0; i < mem.width; i++) + { + int start_i = i, width = 1; + SigBit wen_bit = port.en[sub * mem.width + i]; - while (i+1 < GetSize(port.en) && active_sigmap(port.en[i+1]) == active_sigmap(wen_bit)) - i++, width++; + while (i+1 < mem.width && active_sigmap(port.en[sub * mem.width + i+1]) == active_sigmap(wen_bit)) + i++, width++; - if (wen_bit == State::S0) - continue; + if (wen_bit == State::S0) + continue; - f << stringf("%s%s", indent.c_str(), indent.c_str()); - if (wen_bit != State::S1) - { - f << stringf("if ("); - dump_sigspec(f, wen_bit); - f << stringf(")\n"); - f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str()); + f << stringf("%s%s", indent.c_str(), indent.c_str()); + if (wen_bit != State::S1) + { + f << stringf("if ("); + dump_sigspec(f, wen_bit); + f << stringf(")\n"); + f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str()); + } + f << stringf("%s[", mem_id.c_str()); + dump_sigspec(f, addr); + if (width == GetSize(port.en)) + f << stringf("] <= "); + else + f << stringf("][%d:%d] <= ", i, start_i); + dump_sigspec(f, port.data.extract(sub * mem.width + start_i, width)); + f << stringf(";\n"); } - f << stringf("%s[", mem_id.c_str()); - dump_sigspec(f, port.addr); - if (width == GetSize(port.en)) - f << stringf("] <= "); - else - f << stringf("][%d:%d] <= ", i, start_i); - dump_sigspec(f, port.data.extract(start_i, width)); - f << stringf(";\n"); } } -- cgit v1.2.3 From 055ba748bcf8c77bff15bda0de49c0b4b3722bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Thu, 27 May 2021 17:50:59 +0200 Subject: backends/verilog: Add support for memory read port reset and init value. --- backends/verilog/verilog_backend.cc | 90 +++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 9 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 95ad69c81..0dc7113bd 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -515,6 +515,8 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) // create a map : "edge clk" -> expressions within that clock domain dict> clk_to_lof_body; + dict clk_to_arst_cond; + dict> clk_to_arst_body; clk_to_lof_body[""] = std::vector(); std::string clk_domain_str; // create a list of reg declarations @@ -529,8 +531,12 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) std::ostringstream os; dump_sigspec(os, port.clk); clk_domain_str = stringf("%sedge %s", port.clk_polarity ? "pos" : "neg", os.str().c_str()); - if( clk_to_lof_body.count(clk_domain_str) == 0 ) - clk_to_lof_body[clk_domain_str] = std::vector(); + if (port.arst != State::S0) { + std::ostringstream os2; + dump_sigspec(os2, port.arst); + clk_domain_str += stringf(", posedge %s", os2.str().c_str()); + clk_to_arst_cond[clk_domain_str] = os2.str(); + } } if (!port.transparent) { @@ -542,22 +548,51 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) std::string temp_id = next_auto_id(); lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.data.size() - 1, temp_id.c_str()) ); - bool has_en = port.en != State::S1; + bool has_indent = false; - if (has_en) - { + if (port.arst != State::S0) { + std::ostringstream os; + os << stringf("%s <= ", temp_id.c_str()); + dump_sigspec(os, port.arst_value); + os << ";\n"; + clk_to_arst_body[clk_domain_str].push_back(os.str()); + } + + if (port.srst != State::S0 && !port.ce_over_srst) { + std::ostringstream os; + os << stringf("if ("); + dump_sigspec(os, port.srst); + os << stringf(")\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); + std::ostringstream os2; + os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str()); + dump_sigspec(os2, port.srst_value); + os2 << ";\n"; + clk_to_lof_body[clk_domain_str].push_back(os2.str()); + std::ostringstream os3; + if (port.en == State::S1) { + os3 << "else begin\n"; + } else { + os3 << "else if ("; + dump_sigspec(os3, port.en); + os3 << ") begin\n"; + } + clk_to_lof_body[clk_domain_str].push_back(os3.str()); + has_indent = true; + } else if (port.en != State::S1) { std::ostringstream os; os << stringf("if ("); dump_sigspec(os, port.en); os << stringf(") begin\n"); clk_to_lof_body[clk_domain_str].push_back(os.str()); + has_indent = true; } for (int sub = 0; sub < (1 << port.wide_log2); sub++) { SigSpec addr = port.sub_addr(sub); std::ostringstream os; - if (has_en) + if (has_indent) os << indent; os << temp_id; if (port.wide_log2) @@ -568,9 +603,35 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) clk_to_lof_body[clk_domain_str].push_back(os.str()); } - if (has_en) + if (port.srst != State::S0 && port.ce_over_srst) + { + std::ostringstream os; + if (has_indent) + os << indent; + os << stringf("if ("); + dump_sigspec(os, port.srst); + os << stringf(")\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); + std::ostringstream os2; + if (has_indent) + os2 << indent; + os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str()); + dump_sigspec(os2, port.srst_value); + os2 << ";\n"; + clk_to_lof_body[clk_domain_str].push_back(os2.str()); + } + + if (has_indent) clk_to_lof_body[clk_domain_str].push_back("end\n"); + if (!port.init_value.is_fully_undef()) + { + std::ostringstream os; + dump_sigspec(os, port.init_value); + std::string line = stringf("initial %s = %s;\n", temp_id.c_str(), os.str().c_str()); + clk_to_lof_body[""].push_back(line); + } + { std::ostringstream os; dump_sigspec(os, port.data); @@ -765,8 +826,19 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) if( clk_domain != "") { f << stringf("%s" "always%s @(%s) begin\n", indent.c_str(), systemverilog ? "_ff" : "", clk_domain.c_str()); - for(auto &line : lof_lines) - f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str()); + bool has_arst = clk_to_arst_cond.count(clk_domain) != 0; + if (has_arst) { + f << stringf("%s%s" "if (%s) begin\n", indent.c_str(), indent.c_str(), clk_to_arst_cond[clk_domain].c_str()); + for(auto &line : clk_to_arst_body[clk_domain]) + f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str()); + f << stringf("%s%s" "end else begin\n", indent.c_str(), indent.c_str()); + for(auto &line : lof_lines) + f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str()); + f << stringf("%s%s" "end\n", indent.c_str(), indent.c_str()); + } else { + for(auto &line : lof_lines) + f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str()); + } f << stringf("%s" "end\n", indent.c_str()); } else -- cgit v1.2.3 From 72787f52fc31954e4b7dc3dc34d86705fc4e9dd1 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Tue, 8 Jun 2021 00:39:36 +0200 Subject: Fixing old e-mail addresses and deadnames s/((Claire|Xen|Xenia|Clifford)\s+)+(Wolf|Xen)\s+<(claire|clifford)@(symbioticeda.com|clifford.at|yosyshq.com)>/Claire Xenia Wolf /gi; s/((Nina|Nak|N\.)\s+)+Engelhardt\s+/N. Engelhardt /gi; s/((David)\s+)+Shah\s+<(dave|david)@(symbioticeda.com|yosyshq.com|ds0.me)>/David Shah /gi; s/((Miodrag)\s+)+Milanovic\s+<(miodrag|micko)@(symbioticeda.com|yosyshq.com)>/Miodrag Milanovic /gi; s,https?://www.clifford.at/yosys/,http://yosyshq.net/yosys/,g; --- backends/verilog/verilog_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 0dc7113bd..800865414 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- cgit v1.2.3 From e9effd58d24afc8470813aec3028e932ea677aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 12 Jul 2021 20:43:09 +0200 Subject: backends/verilog: Support meminit with mask. --- backends/verilog/verilog_backend.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 800865414..b363bc2fe 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -504,9 +504,24 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) int start = init.addr.as_int(); for (int i=0; i Date: Tue, 25 May 2021 23:42:58 +0200 Subject: 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. --- backends/verilog/verilog_backend.cc | 72 ++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index b363bc2fe..8f96c3a58 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -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; -- cgit v1.2.3 From e6f3d1c225abecf736782f43af4f36526c63f4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 31 Jul 2021 23:21:37 +0200 Subject: kernel/mem: Introduce transparency masks. --- backends/verilog/verilog_backend.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 8f96c3a58..47b48a460 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -555,7 +555,10 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) } // Decide how to represent the transparency; same idea as Mem::extract_rdff. - bool trans_use_addr = port.transparent; + 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; @@ -630,13 +633,7 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) 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) + 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); @@ -679,7 +676,10 @@ void dump_memory(std::ostream &f, std::string indent, Mem &mem) 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)); + 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()); -- cgit v1.2.3 From 63b9df8693840d17def8abcb0e848112283b0231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 1 Oct 2021 23:50:48 +0200 Subject: kernel/ff: Refactor FfData to enable FFs with async load. - *_en is split into *_ce (clock enable) and *_aload (async load aka latch gate enable), so both can be present at once - has_d is removed - has_gclk is added (to have a clear marker for $ff) - d_is_const and val_d leftovers are removed - async2sync, clk2fflogic, opt_dff are updated to operate correctly on FFs with async load --- backends/verilog/verilog_backend.cc | 113 ++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 43 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 47b48a460..6fb14d7fc 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1398,7 +1398,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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); @@ -1419,17 +1419,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *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; @@ -1437,28 +1439,38 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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"); + } } } @@ -1480,13 +1492,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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"); @@ -1507,7 +1524,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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); @@ -1515,11 +1532,21 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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); @@ -1536,9 +1563,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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(") "); } } @@ -1560,7 +1587,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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 ? "" : "!"); @@ -1568,14 +1595,14 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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"); } } -- cgit v1.2.3 From ff8e999a7112a1975d268e6ebb3e751f6f0364c7 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 9 Oct 2021 13:40:55 +0200 Subject: Split module ports, 20 per line --- backends/verilog/verilog_backend.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 6fb14d7fc..dc5c188c0 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2062,6 +2062,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) 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()) { @@ -2070,6 +2071,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) f << stringf(", "); f << stringf("%s", id(wire->name).c_str()); keep_running = true; + if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++; continue; } } -- cgit v1.2.3 From c081c683a4672aa6b6b35d4cc8142719dacb882c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 17 Nov 2021 12:19:06 +0100 Subject: Give initial wire unique ID, fixes #2914 --- backends/verilog/verilog_backend.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index dc5c188c0..47ef1c479 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -44,6 +44,7 @@ std::string auto_prefix, extmem_prefix; RTLIL::Module *active_module; dict active_initdata; SigMap active_sigmap; +IdString initial_id; void reset_auto_counter_id(RTLIL::IdString id, bool may_rename) { @@ -1943,7 +1944,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo 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; @@ -2077,9 +2078,10 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) } } 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); -- cgit v1.2.3 From 86f2804dc3f80cd74349c62888376c8596fb1856 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 11 Dec 2021 12:01:52 +0000 Subject: write_verilog: dump zero width sigspecs correctly. Before this commit, zero width sigspecs were dumped as "" (empty string). Unfortunately, 1364-2005 5.2.3.3 indicates that an empty string is equivalent to "\0", and is 8 bits wide, so that's wrong. After this commit, a replication operation with a count of zero is used instead, which is explicitly permitted per 1364-2005 5.1.14, and is defined to have size zero. (Its operand has to have a non-zero size for it to be legal, though.) PR #1203 has addressed this issue before, but in an incomplete way. --- backends/verilog/verilog_backend.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 47ef1c479..13c78c526 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -358,7 +358,8 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima 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()) { -- cgit v1.2.3 From 0aad88a2fb23e5481538122e1bd4c0fac9ba5e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 11 Dec 2021 16:07:29 +0100 Subject: Add clean_zerowidth pass, use it for Verilog output. This should remove instances of zero-width sigspecs in the netlist, avoiding problems in the Verilog backend with emitting them. See #3103. --- backends/verilog/verilog_backend.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 13c78c526..e4781ef3e 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2300,6 +2300,8 @@ struct VerilogBackend : public Backend { extmem_prefix = filename.substr(0, filename.rfind('.')); } + Pass::call(design, "clean_zerowidth"); + design->sort(); *f << stringf("/* Generated by %s */\n", yosys_version_str); -- cgit v1.2.3 From 93508d58dafbbffcedffa70b21a197b6fca8bb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 24 Jan 2022 16:02:29 +0100 Subject: Add $bmux and $demux cells. --- backends/verilog/verilog_backend.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index e4781ef3e..32003cf54 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2300,7 +2300,11 @@ struct VerilogBackend : public Backend { 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(); -- cgit v1.2.3 From 56e7791760ce67cb1831691460b50bf73a4f5117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 30 Jan 2022 20:48:50 +0100 Subject: verilog backend: Emit a `wire` for ports as well. Fixes #3177. --- backends/verilog/verilog_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/verilog/verilog_backend.cc') diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 32003cf54..aa1d4558c 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -432,7 +432,7 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire) 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 } -- cgit v1.2.3