aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backends/smt2/smt2.cc67
-rw-r--r--kernel/celltypes.h2
-rw-r--r--kernel/cost.h2
-rw-r--r--kernel/rtlil.cc11
-rw-r--r--kernel/rtlil.h1
-rw-r--r--passes/opt/opt_clean.cc9
-rw-r--r--passes/proc/proc_dff.cc5
-rw-r--r--passes/sat/clk2fflogic.cc81
-rw-r--r--techlibs/ice40/cells_sim.v38
9 files changed, 178 insertions, 38 deletions
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 8daa52eb3..5c3ce3753 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -556,15 +556,28 @@ struct Smt2Worker
decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d\n", get_id(cell), abits, width, rd_ports, wr_ports));
+ bool async_read = false;
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) {
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_zero())
+ log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module));
+ async_read = true;
+ }
+
+ string memstate;
+ if (async_read) {
+ memstate = stringf("%s#%d#final", get_id(module), arrayid);
+ } else {
+ memstate = stringf("%s#%d#0", get_id(module), arrayid);
+ }
+
if (statebv)
{
int mem_size = cell->getParam("\\SIZE").as_int();
int mem_offset = cell->getParam("\\OFFSET").as_int();
- makebits(stringf("%s#%d#0", get_id(module), arrayid), width*mem_size, get_id(cell));
-
- decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d#0| state))\n",
- get_id(module), get_id(cell), get_id(module), width*mem_size, get_id(module), arrayid));
+ makebits(memstate, width*mem_size, get_id(cell));
+ decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (_ BitVec %d) (|%s| state))\n",
+ get_id(module), get_id(cell), get_id(module), width*mem_size, memstate.c_str()));
for (int i = 0; i < rd_ports; i++)
{
@@ -584,9 +597,9 @@ struct Smt2Worker
read_expr += "0";
for (int k = 0; k < mem_size; k++)
- read_expr = stringf("(ite (= (|%s_m:R%dA %s| state) #b%s) ((_ extract %d %d) (|%s#%d#0| state))\n %s)",
+ read_expr = stringf("(ite (= (|%s_m:R%dA %s| state) #b%s) ((_ extract %d %d) (|%s| state))\n %s)",
get_id(module), i, get_id(cell), Const(k+mem_offset, abits).as_string().c_str(),
- width*(k+1)-1, width*k, get_id(module), arrayid, read_expr.c_str());
+ width*(k+1)-1, width*k, memstate.c_str(), read_expr.c_str());
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d)\n %s) ; %s\n",
get_id(module), idcounter, get_id(module), width, read_expr.c_str(), log_signal(data_sig)));
@@ -600,14 +613,14 @@ struct Smt2Worker
else
{
if (statedt)
- dtmembers.push_back(stringf(" (|%s#%d#0| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
- get_id(module), arrayid, abits, width, get_id(cell)));
+ dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ memstate.c_str(), abits, width, get_id(cell)));
else
- decls.push_back(stringf("(declare-fun |%s#%d#0| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
- get_id(module), arrayid, get_id(module), abits, width, get_id(cell)));
+ decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ memstate.c_str(), get_id(module), abits, width, get_id(cell)));
- decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s#%d#0| state))\n",
- get_id(module), get_id(cell), get_id(module), abits, width, get_id(module), arrayid));
+ decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s| state))\n",
+ get_id(module), get_id(cell), get_id(module), abits, width, memstate.c_str()));
for (int i = 0; i < rd_ports; i++)
{
@@ -622,8 +635,8 @@ struct Smt2Worker
decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
- decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s#%d#0| state) (|%s_m:R%dA %s| state))) ; %s\n",
- get_id(module), idcounter, get_id(module), width, get_id(module), arrayid, get_id(module), i, get_id(cell), log_signal(data_sig)));
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s| state) (|%s_m:R%dA %s| state))) ; %s\n",
+ get_id(module), idcounter, get_id(module), width, memstate.c_str(), get_id(module), i, get_id(cell), log_signal(data_sig)));
decls.push_back(stringf("(define-fun |%s_m:R%dD %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d| state))\n",
get_id(module), i, get_id(cell), get_id(module), width, get_id(module), idcounter));
@@ -869,11 +882,25 @@ struct Smt2Worker
int width = cell->getParam("\\WIDTH").as_int();
int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+ bool async_read = false;
+ string initial_memstate, final_memstate;
+
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) {
+ log_assert(cell->getParam("\\WR_CLK_ENABLE").is_fully_zero());
+ async_read = true;
+ initial_memstate = stringf("%s#%d#0", get_id(module), arrayid);
+ final_memstate = stringf("%s#%d#final", get_id(module), arrayid);
+ }
+
if (statebv)
{
int mem_size = cell->getParam("\\SIZE").as_int();
int mem_offset = cell->getParam("\\OFFSET").as_int();
+ if (async_read) {
+ makebits(final_memstate, width*mem_size, get_id(cell));
+ }
+
for (int i = 0; i < wr_ports; i++)
{
SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits);
@@ -912,6 +939,15 @@ struct Smt2Worker
}
else
{
+ if (async_read) {
+ if (statedt)
+ dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ initial_memstate.c_str(), abits, width, get_id(cell)));
+ else
+ decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ initial_memstate.c_str(), get_id(module), abits, width, get_id(cell)));
+ }
+
for (int i = 0; i < wr_ports; i++)
{
SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits);
@@ -948,6 +984,9 @@ struct Smt2Worker
std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid);
trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell)));
+ if (async_read)
+ hier.push_back(stringf(" (= %s (|%s| state)) ; %s\n", expr_d.c_str(), final_memstate.c_str(), get_id(cell)));
+
Const init_data = cell->getParam("\\INIT");
int memsize = cell->getParam("\\SIZE").as_int();
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 9f775cde7..5218b5363 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -20,7 +20,7 @@
#ifndef CELLTYPES_H
#define CELLTYPES_H
-#include <kernel/yosys.h>
+#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
diff --git a/kernel/cost.h b/kernel/cost.h
index 84fd6cd6d..e795b571b 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -20,7 +20,7 @@
#ifndef COST_H
#define COST_H
-#include <kernel/yosys.h>
+#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 7dc7107c1..3e873054f 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -172,6 +172,17 @@ bool RTLIL::Const::is_fully_zero() const
return true;
}
+bool RTLIL::Const::is_fully_ones() const
+{
+ cover("kernel.rtlil.const.is_fully_ones");
+
+ for (auto bit : bits)
+ if (bit != RTLIL::State::S1)
+ return false;
+
+ return true;
+}
+
bool RTLIL::Const::is_fully_def() const
{
cover("kernel.rtlil.const.is_fully_def");
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index b33cb53a3..fc29e1e65 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -480,6 +480,7 @@ struct RTLIL::Const
inline const RTLIL::State &operator[](int index) const { return bits.at(index); }
bool is_fully_zero() const;
+ bool is_fully_ones() const;
bool is_fully_def() const;
bool is_fully_undef() const;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 2d2ffa9a1..25d462ada 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -91,9 +91,16 @@ void rmunused_module_cells(Module *module, bool verbose)
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
- for (auto bit : sigmap(it2.second))
+ for (auto raw_bit : it2.second) {
+ if (raw_bit.wire == nullptr)
+ continue;
+ auto bit = sigmap(raw_bit);
+ if (bit.wire == nullptr)
+ log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
+ log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
+ }
}
if (keep_cache.query(cell))
queue.insert(cell);
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 98653dc6b..f732baa17 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -322,6 +322,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
}
}
+ SigSpec sig_q = sig;
ce.assign_map.apply(insig);
ce.assign_map.apply(rstval);
ce.assign_map.apply(sig);
@@ -350,13 +351,13 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
- gen_dffsr(mod, insig, rstval, sig,
+ gen_dffsr(mod, insig, rstval, sig_q,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level->signal, proc);
}
else
- gen_dff(mod, insig, rstval.as_const(), sig,
+ gen_dff(mod, insig, rstval.as_const(), sig_q,
sync_edge && sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge ? sync_edge->signal : SigSpec(),
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index ef6d5dd72..d334cf7d9 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -72,6 +72,87 @@ struct Clk2fflogicPass : public Pass {
for (auto cell : vector<Cell*>(module->selected_cells()))
{
+ if (cell->type.in("$mem"))
+ {
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+
+ for (int i = 0; i < rd_ports; i++) {
+ if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
+ log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module));
+ }
+
+ Const wr_clk_en_param = cell->getParam("\\WR_CLK_ENABLE");
+ Const wr_clk_pol_param = cell->getParam("\\WR_CLK_POLARITY");
+
+ SigSpec wr_clk_port = cell->getPort("\\WR_CLK");
+ SigSpec wr_en_port = cell->getPort("\\WR_EN");
+ SigSpec wr_addr_port = cell->getPort("\\WR_ADDR");
+ SigSpec wr_data_port = cell->getPort("\\WR_DATA");
+
+ for (int wport = 0; wport < wr_ports; wport++)
+ {
+ bool clken = wr_clk_en_param[wport] == State::S1;
+ bool clkpol = wr_clk_pol_param[wport] == State::S1;
+
+ if (!clken)
+ continue;
+
+ SigBit clk = wr_clk_port[wport];
+ SigSpec en = wr_en_port.extract(wport*width, width);
+ SigSpec addr = wr_addr_port.extract(wport*abits, abits);
+ SigSpec data = wr_data_port.extract(wport*width, width);
+
+ log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
+ wport, log_id(module), log_id(cell), log_signal(clk),
+ log_signal(addr), log_signal(data));
+
+ Wire *past_clk = module->addWire(NEW_ID);
+ past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
+ module->addFf(NEW_ID, clk, past_clk);
+
+ SigSpec clock_edge_pattern;
+
+ if (clkpol) {
+ clock_edge_pattern.append_bit(State::S0);
+ clock_edge_pattern.append_bit(State::S1);
+ } else {
+ clock_edge_pattern.append_bit(State::S1);
+ clock_edge_pattern.append_bit(State::S0);
+ }
+
+ SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+
+ SigSpec en_q = module->addWire(NEW_ID, GetSize(addr));
+ module->addFf(NEW_ID, en, en_q);
+
+ SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr));
+ module->addFf(NEW_ID, addr, addr_q);
+
+ SigSpec data_q = module->addWire(NEW_ID, GetSize(data));
+ module->addFf(NEW_ID, data, data_q);
+
+ wr_clk_port[wport] = State::S0;
+ wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge));
+ wr_addr_port.replace(wport*abits, addr_q);
+ wr_data_port.replace(wport*width, data_q);
+
+ wr_clk_en_param[wport] = State::S0;
+ wr_clk_pol_param[wport] = State::S0;
+ }
+
+ cell->setParam("\\WR_CLK_ENABLE", wr_clk_en_param);
+ cell->setParam("\\WR_CLK_POLARITY", wr_clk_pol_param);
+
+ cell->setPort("\\WR_CLK", wr_clk_port);
+ cell->setPort("\\WR_EN", wr_en_port);
+ cell->setPort("\\WR_ADDR", wr_addr_port);
+ cell->setPort("\\WR_DATA", wr_data_port);
+ }
+
if (cell->type.in("$dlatch"))
{
bool enpol = cell->parameters["\\EN_POLARITY"].as_bool();
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index b398c1886..3be5ed28e 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -1193,7 +1193,7 @@ module SB_IO_OD (
input DOUT1,
input DOUT0,
output DIN1,
- output DIN0,
+ output DIN0
);
parameter [5:0] PIN_TYPE = 6'b000000;
parameter [0:0] NEG_TRIGGER = 1'b0;
@@ -1205,44 +1205,44 @@ module SB_IO_OD (
reg outena_q;
generate if (!NEG_TRIGGER) begin
- always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
- always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
- always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
- always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
- always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ always @(posedge INPUTCLK) if (CLOCKENABLE) din_q_0 <= PACKAGEPIN;
+ always @(negedge INPUTCLK) if (CLOCKENABLE) din_q_1 <= PACKAGEPIN;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) dout_q_0 <= DOUT0;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) dout_q_1 <= DOUT1;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) outena_q <= OUTPUTENABLE;
end else begin
- always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
- always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
- always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
- always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
- always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ always @(negedge INPUTCLK) if (CLOCKENABLE) din_q_0 <= PACKAGEPIN;
+ always @(posedge INPUTCLK) if (CLOCKENABLE) din_q_1 <= PACKAGEPIN;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) dout_q_0 <= DOUT0;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) dout_q_1 <= DOUT1;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) outena_q <= OUTPUTENABLE;
end endgenerate
always @* begin
- if (!PIN_TYPE[1] || !LATCH_INPUT_VALUE)
- din_0 = PIN_TYPE[0] ? PACKAGE_PIN : din_q_0;
+ if (!PIN_TYPE[1] || !LATCHINPUTVALUE)
+ din_0 = PIN_TYPE[0] ? PACKAGEPIN : din_q_0;
din_1 = din_q_1;
end
// work around simulation glitches on dout in DDR mode
reg outclk_delayed_1;
reg outclk_delayed_2;
- always @* outclk_delayed_1 <= OUTPUT_CLK;
+ always @* outclk_delayed_1 <= OUTPUTCLK;
always @* outclk_delayed_2 <= outclk_delayed_1;
always @* begin
if (PIN_TYPE[3])
- dout = PIN_TYPE[2] ? !dout_q_0 : D_OUT_0;
+ dout = PIN_TYPE[2] ? !dout_q_0 : DOUT0;
else
dout = (outclk_delayed_2 ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
end
- assign D_IN_0 = din_0, D_IN_1 = din_1;
+ assign DIN0 = din_0, DIN1 = din_1;
generate
- if (PIN_TYPE[5:4] == 2'b01) assign PACKAGE_PIN = dout ? 1'bz : 1'b0;
- if (PIN_TYPE[5:4] == 2'b10) assign PACKAGE_PIN = OUTPUT_ENABLE ? (dout ? 1'bz : 1'b0) : 1'bz;
- if (PIN_TYPE[5:4] == 2'b11) assign PACKAGE_PIN = outena_q ? (dout ? 1'bz : 1'b0) : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b01) assign PACKAGEPIN = dout ? 1'bz : 1'b0;
+ if (PIN_TYPE[5:4] == 2'b10) assign PACKAGEPIN = OUTPUTENABLE ? (dout ? 1'bz : 1'b0) : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b11) assign PACKAGEPIN = outena_q ? (dout ? 1'bz : 1'b0) : 1'bz;
endgenerate
`endif
endmodule