diff options
Diffstat (limited to 'passes/sat')
-rw-r--r-- | passes/sat/clk2fflogic.cc | 113 | ||||
-rw-r--r-- | passes/sat/sim.cc | 193 |
2 files changed, 135 insertions, 171 deletions
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 2cb91c009..cbf7c5435 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -21,6 +21,7 @@ #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" +#include "kernel/mem.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -84,89 +85,65 @@ struct Clk2fflogicPass : public Pass { SigMap sigmap(module); FfInitVals initvals(&sigmap, module); - for (auto cell : vector<Cell*>(module->selected_cells())) + for (auto &mem : Mem::get_selected_memories(module)) { - if (cell->type.in(ID($mem))) - { - int abits = cell->getParam(ID::ABITS).as_int(); - int width = cell->getParam(ID::WIDTH).as_int(); - int rd_ports = cell->getParam(ID::RD_PORTS).as_int(); - int wr_ports = cell->getParam(ID::WR_PORTS).as_int(); - - for (int i = 0; i < rd_ports; i++) { - if (cell->getParam(ID::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(ID::WR_CLK_ENABLE); - Const wr_clk_pol_param = cell->getParam(ID::WR_CLK_POLARITY); - - SigSpec wr_clk_port = cell->getPort(ID::WR_CLK); - SigSpec wr_en_port = cell->getPort(ID::WR_EN); - SigSpec wr_addr_port = cell->getPort(ID::WR_ADDR); - SigSpec wr_data_port = cell->getPort(ID::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); + for (int i = 0; i < GetSize(mem.rd_ports); i++) { + auto &port = mem.rd_ports[i]; + if (port.clk_enable) + 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(mem.memid), log_id(module)); + } - 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)); + for (int i = 0; i < GetSize(mem.wr_ports); i++) + { + auto &port = mem.wr_ports[i]; - Wire *past_clk = module->addWire(NEW_ID); - past_clk->attributes[ID::init] = clkpol ? State::S1 : State::S0; - module->addFf(NEW_ID, clk, past_clk); + if (!port.clk_enable) + continue; - SigSpec clock_edge_pattern; + log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n", + i, log_id(module), log_id(mem.memid), log_signal(port.clk), + log_signal(port.addr), log_signal(port.data)); - if (clkpol) { - clock_edge_pattern.append(State::S0); - clock_edge_pattern.append(State::S1); - } else { - clock_edge_pattern.append(State::S1); - clock_edge_pattern.append(State::S0); - } + Wire *past_clk = module->addWire(NEW_ID); + past_clk->attributes[ID::init] = port.clk_polarity ? State::S1 : State::S0; + module->addFf(NEW_ID, port.clk, past_clk); - SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern); + SigSpec clock_edge_pattern; - SigSpec en_q = module->addWire(NEW_ID, GetSize(en)); - module->addFf(NEW_ID, en, en_q); + if (port.clk_polarity) { + clock_edge_pattern.append(State::S0); + clock_edge_pattern.append(State::S1); + } else { + clock_edge_pattern.append(State::S1); + clock_edge_pattern.append(State::S0); + } - SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr)); - module->addFf(NEW_ID, addr, addr_q); + SigSpec clock_edge = module->Eqx(NEW_ID, {port.clk, SigSpec(past_clk)}, clock_edge_pattern); - SigSpec data_q = module->addWire(NEW_ID, GetSize(data)); - module->addFf(NEW_ID, data, data_q); + SigSpec en_q = module->addWire(NEW_ID, GetSize(port.en)); + module->addFf(NEW_ID, port.en, en_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); + SigSpec addr_q = module->addWire(NEW_ID, GetSize(port.addr)); + module->addFf(NEW_ID, port.addr, addr_q); - wr_clk_en_param[wport] = State::S0; - wr_clk_pol_param[wport] = State::S0; - } + SigSpec data_q = module->addWire(NEW_ID, GetSize(port.data)); + module->addFf(NEW_ID, port.data, data_q); - cell->setParam(ID::WR_CLK_ENABLE, wr_clk_en_param); - cell->setParam(ID::WR_CLK_POLARITY, wr_clk_pol_param); + port.clk = State::S0; + port.en = module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge); + port.addr = addr_q; + port.data = data_q; - cell->setPort(ID::WR_CLK, wr_clk_port); - cell->setPort(ID::WR_EN, wr_en_port); - cell->setPort(ID::WR_ADDR, wr_addr_port); - cell->setPort(ID::WR_DATA, wr_data_port); + port.clk_enable = false; + port.clk_polarity = false; } + mem.emit(); + } + + for (auto cell : vector<Cell*>(module->selected_cells())) + { SigSpec qval; if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 3d2081a74..75f922dba 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" +#include "kernel/mem.h" #include <ctime> @@ -64,6 +65,7 @@ struct SimInstance pool<SigBit> dirty_bits; pool<Cell*> dirty_cells; + pool<IdString> dirty_memories; pool<SimInstance*, hash_ptr_ops> dirty_children; struct ff_state_t @@ -74,16 +76,20 @@ struct SimInstance struct mem_state_t { - Const past_wr_clk; - Const past_wr_en; - Const past_wr_addr; - Const past_wr_data; + Mem *mem; + std::vector<Const> past_wr_clk; + std::vector<Const> past_wr_en; + std::vector<Const> past_wr_addr; + std::vector<Const> past_wr_data; Const data; }; dict<Cell*, ff_state_t> ff_database; - dict<Cell*, mem_state_t> mem_database; + dict<IdString, mem_state_t> mem_database; pool<Cell*> formal_database; + dict<Cell*, IdString> mem_cells; + + std::vector<Mem> memories; dict<Wire*, pair<int, Const>> vcd_database; @@ -120,6 +126,19 @@ struct SimInstance } } + memories = Mem::get_all_memories(module); + for (auto &mem : memories) { + auto &mdb = mem_database[mem.memid]; + mdb.mem = &mem; + for (auto &port : mem.wr_ports) { + mdb.past_wr_clk.push_back(Const(State::Sx)); + mdb.past_wr_en.push_back(Const(State::Sx, GetSize(port.en))); + mdb.past_wr_addr.push_back(Const(State::Sx, GetSize(port.addr))); + mdb.past_wr_data.push_back(Const(State::Sx, GetSize(port.data))); + } + mdb.data = mem.get_init_data(); + } + for (auto cell : module->cells()) { Module *mod = module->design->module(cell->type); @@ -145,29 +164,9 @@ struct SimInstance ff_database[cell] = ff; } - if (cell->type == ID($mem)) + if (cell->type.in(ID($mem), ID($meminit), ID($memwr), ID($memrd))) { - mem_state_t mem; - - mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort(ID::WR_CLK))); - mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort(ID::WR_EN))); - mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort(ID::WR_ADDR))); - mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort(ID::WR_DATA))); - - mem.data = cell->getParam(ID::INIT); - int sz = cell->getParam(ID::SIZE).as_int() * cell->getParam(ID::WIDTH).as_int(); - - if (GetSize(mem.data) > sz) - mem.data.bits.resize(sz); - - while (GetSize(mem.data) < sz) - mem.data.bits.push_back(State::Sx); - - mem_database[cell] = mem; - } - if (cell->type.in(ID($memwr),ID($memrd))) - { - log_error("$memrd and $memwr cells have to be merged to stand-alone $mem cells (execute memory_collect pass)\n"); + mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string(); } if (cell->type.in(ID($assert), ID($cover), ID($assume))) { formal_database.insert(cell); @@ -190,7 +189,8 @@ struct SimInstance for (auto &it : mem_database) { mem_state_t &mem = it.second; - zinit(mem.past_wr_en); + for (auto &val : mem.past_wr_en) + zinit(val); zinit(mem.data); } } @@ -261,37 +261,9 @@ struct SimInstance if (formal_database.count(cell)) return; - if (mem_database.count(cell)) + if (mem_cells.count(cell)) { - mem_state_t &mem = mem_database.at(cell); - - int num_rd_ports = cell->getParam(ID::RD_PORTS).as_int(); - - int size = cell->getParam(ID::SIZE).as_int(); - int offset = cell->getParam(ID::OFFSET).as_int(); - int abits = cell->getParam(ID::ABITS).as_int(); - int width = cell->getParam(ID::WIDTH).as_int(); - - if (cell->getParam(ID::RD_CLK_ENABLE).as_bool()) - log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell)); - - SigSpec rd_addr_sig = cell->getPort(ID::RD_ADDR); - SigSpec rd_data_sig = cell->getPort(ID::RD_DATA); - - for (int port_idx = 0; port_idx < num_rd_ports; port_idx++) - { - Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits)); - Const data = Const(State::Sx, width); - - if (addr.is_fully_def()) { - int index = addr.as_int() - offset; - if (index >= 0 && index < size) - data = mem.data.extract(index*width, width); - } - - set_state(rd_data_sig.extract(port_idx*width, width), data); - } - + dirty_memories.insert(mem_cells[cell]); return; } @@ -354,6 +326,29 @@ struct SimInstance log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } + void update_memory(IdString id) { + auto &mdb = mem_database[id]; + auto &mem = *mdb.mem; + + for (int port_idx = 0; port_idx < GetSize(mem.rd_ports); port_idx++) + { + auto &port = mem.rd_ports[port_idx]; + Const addr = get_state(port.addr); + Const data = Const(State::Sx, mem.width); + + if (port.clk_enable) + log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid)); + + if (addr.is_fully_def()) { + int index = addr.as_int() - mem.start_offset; + if (index >= 0 && index < mem.size) + data = mdb.data.extract(index*mem.width, mem.width); + } + + set_state(port.data, data); + } + } + void update_ph1() { pool<Cell*> queue_cells; @@ -385,6 +380,10 @@ struct SimInstance continue; } + for (auto &memid : dirty_memories) + update_memory(memid); + dirty_memories.clear(); + for (auto wire : queue_outports) if (instance->hasPort(wire->name)) { Const value = get_state(wire); @@ -428,50 +427,40 @@ struct SimInstance for (auto &it : mem_database) { - Cell *cell = it.first; - mem_state_t &mem = it.second; - - int num_wr_ports = cell->getParam(ID::WR_PORTS).as_int(); - - int size = cell->getParam(ID::SIZE).as_int(); - int offset = cell->getParam(ID::OFFSET).as_int(); - int abits = cell->getParam(ID::ABITS).as_int(); - int width = cell->getParam(ID::WIDTH).as_int(); + mem_state_t &mdb = it.second; + auto &mem = *mdb.mem; - Const wr_clk_enable = cell->getParam(ID::WR_CLK_ENABLE); - Const wr_clk_polarity = cell->getParam(ID::WR_CLK_POLARITY); - Const current_wr_clk = get_state(cell->getPort(ID::WR_CLK)); - - for (int port_idx = 0; port_idx < num_wr_ports; port_idx++) + for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++) { + auto &port = mem.wr_ports[port_idx]; Const addr, data, enable; - if (wr_clk_enable[port_idx] == State::S0) + if (!port.clk_enable) { - addr = get_state(cell->getPort(ID::WR_ADDR).extract(port_idx*abits, abits)); - data = get_state(cell->getPort(ID::WR_DATA).extract(port_idx*width, width)); - enable = get_state(cell->getPort(ID::WR_EN).extract(port_idx*width, width)); + addr = get_state(port.addr); + data = get_state(port.data); + enable = get_state(port.en); } else { - if (wr_clk_polarity[port_idx] == State::S1 ? - (mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) : - (mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0)) + if (port.clk_polarity ? + (mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) : + (mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0)) continue; - addr = mem.past_wr_addr.extract(port_idx*abits, abits); - data = mem.past_wr_data.extract(port_idx*width, width); - enable = mem.past_wr_en.extract(port_idx*width, width); + addr = mdb.past_wr_addr[port_idx]; + data = mdb.past_wr_data[port_idx]; + enable = mdb.past_wr_en[port_idx]; } if (addr.is_fully_def()) { - int index = addr.as_int() - offset; - if (index >= 0 && index < size) - for (int i = 0; i < width; i++) - if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) { - mem.data.bits.at(index*width+i) = data[i]; - dirty_cells.insert(cell); + int index = addr.as_int() - mem.start_offset; + if (index >= 0 && index < mem.size) + for (int i = 0; i < mem.width; i++) + if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) { + mdb.data.bits.at(index*mem.width+i) = data[i]; + dirty_memories.insert(mem.memid); did_something = true; } } @@ -502,13 +491,15 @@ struct SimInstance for (auto &it : mem_database) { - Cell *cell = it.first; mem_state_t &mem = it.second; - mem.past_wr_clk = get_state(cell->getPort(ID::WR_CLK)); - mem.past_wr_en = get_state(cell->getPort(ID::WR_EN)); - mem.past_wr_addr = get_state(cell->getPort(ID::WR_ADDR)); - mem.past_wr_data = get_state(cell->getPort(ID::WR_DATA)); + for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) { + auto &port = mem.mem->wr_ports[i]; + mem.past_wr_clk[i] = get_state(port.clk); + mem.past_wr_en[i] = get_state(port.en); + mem.past_wr_addr[i] = get_state(port.addr); + mem.past_wr_data[i] = get_state(port.data); + } } for (auto cell : formal_database) @@ -563,17 +554,13 @@ struct SimInstance for (auto &it : mem_database) { - Cell *cell = it.first; mem_state_t &mem = it.second; - Const initval = mem.data; - - while (GetSize(initval) >= 2) { - if (initval[GetSize(initval)-1] != State::Sx) break; - if (initval[GetSize(initval)-2] != State::Sx) break; - initval.bits.pop_back(); - } - - cell->setParam(ID::INIT, initval); + mem.mem->clear_inits(); + MemInit minit; + minit.addr = mem.mem->start_offset; + minit.data = mem.data; + mem.mem->inits.push_back(minit); + mem.mem->emit(); } for (auto it : children) |