yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
memory_map.cc
Go to the documentation of this file.
1 /*
2  * yosys -- Yosys Open SYnthesis Suite
3  *
4  * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  */
19 
20 #include "kernel/register.h"
21 #include "kernel/log.h"
22 #include <sstream>
23 #include <set>
24 #include <stdlib.h>
25 
28 
30 {
33 
34  std::map<std::pair<RTLIL::SigSpec, RTLIL::SigSpec>, RTLIL::SigBit> decoder_cache;
35 
36  std::string genid(RTLIL::IdString name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
37  {
38  std::stringstream sstr;
39  sstr << "$memory" << name.str() << token1;
40 
41  if (i >= 0)
42  sstr << "[" << i << "]";
43 
44  sstr << token2;
45 
46  if (j >= 0)
47  sstr << "[" << j << "]";
48 
49  sstr << token3;
50 
51  if (k >= 0)
52  sstr << "[" << k << "]";
53 
54  sstr << token4 << "$" << (autoidx++);
55  return sstr.str();
56  }
57 
59  {
60  std::pair<RTLIL::SigSpec, RTLIL::SigSpec> key(addr_sig, addr_val);
61  log_assert(GetSize(addr_sig) == GetSize(addr_val));
62 
63  if (decoder_cache.count(key) == 0) {
64  if (GetSize(addr_sig) < 2) {
65  decoder_cache[key] = module->Eq(NEW_ID, addr_sig, addr_val);
66  } else {
67  int split_at = GetSize(addr_sig) / 2;
68  RTLIL::SigBit left_eq = addr_decode(addr_sig.extract(0, split_at), addr_val.extract(0, split_at));
69  RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, GetSize(addr_sig) - split_at), addr_val.extract(split_at, GetSize(addr_val) - split_at));
70  decoder_cache[key] = module->And(NEW_ID, left_eq, right_eq);
71  }
72  }
73 
74  RTLIL::SigBit bit = decoder_cache.at(key);
75  log_assert(bit.wire != nullptr && GetSize(bit.wire) == 1);
76  return bit.wire;
77  }
78 
80  {
81  std::set<int> static_ports;
82  std::map<int, RTLIL::SigSpec> static_cells_map;
83  int mem_size = cell->parameters["\\SIZE"].as_int();
84  int mem_width = cell->parameters["\\WIDTH"].as_int();
85  int mem_offset = cell->parameters["\\OFFSET"].as_int();
86  int mem_abits = cell->parameters["\\ABITS"].as_int();
87 
88  // delete unused memory cell
89  if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
90  module->remove(cell);
91  return;
92  }
93 
94  // all write ports must share the same clock
95  RTLIL::SigSpec clocks = cell->getPort("\\WR_CLK");
96  RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
97  RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
98  RTLIL::SigSpec refclock;
99  RTLIL::State refclock_pol = RTLIL::State::Sx;
100  for (int i = 0; i < clocks.size(); i++) {
101  RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(i * mem_width, mem_width);
102  if (wr_en.is_fully_const() && !wr_en.as_bool()) {
103  static_ports.insert(i);
104  continue;
105  }
106  if (clocks_en.bits[i] != RTLIL::State::S1) {
107  RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(i*mem_abits, mem_abits);
108  RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(i*mem_width, mem_width);
109  if (wr_addr.is_fully_const()) {
110  // FIXME: Actually we should check for wr_en.is_fully_const() also and
111  // create a $adff cell with this ports wr_en input as reset pin when wr_en
112  // is not a simple static 1.
113  static_cells_map[wr_addr.as_int()] = wr_data;
114  static_ports.insert(i);
115  continue;
116  }
117  log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
118  cell->name.c_str(), module->name.c_str(), i);
119  return;
120  }
121  if (refclock.size() == 0) {
122  refclock = clocks.extract(i, 1);
123  refclock_pol = clocks_pol.bits[i];
124  }
125  if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
126  log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
127  cell->name.c_str(), module->name.c_str(), i);
128  return;
129  }
130  }
131 
132  log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
133 
134  std::vector<RTLIL::SigSpec> data_reg_in;
135  std::vector<RTLIL::SigSpec> data_reg_out;
136 
137  int count_static = 0;
138 
139  for (int i = 0; i < mem_size; i++)
140  {
141  if (static_cells_map.count(i) > 0)
142  {
143  data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
144  data_reg_out.push_back(static_cells_map[i]);
145  count_static++;
146  }
147  else
148  {
149  RTLIL::Cell *c = module->addCell(genid(cell->name, "", i), "$dff");
150  c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
151  if (clocks_pol.bits.size() > 0) {
152  c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
153  c->setPort("\\CLK", clocks.extract(0, 1));
154  } else {
155  c->parameters["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1);
157  }
158 
159  RTLIL::Wire *w_in = module->addWire(genid(cell->name, "", i, "$d"), mem_width);
160  data_reg_in.push_back(RTLIL::SigSpec(w_in));
161  c->setPort("\\D", data_reg_in.back());
162 
163  std::string w_out_name = stringf("%s[%d]", cell->parameters["\\MEMID"].decode_string().c_str(), i);
164  if (module->wires_.count(w_out_name) > 0)
165  w_out_name = genid(cell->name, "", i, "$q");
166 
167  RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width);
168  w_out->start_offset = mem_offset;
169 
170  data_reg_out.push_back(RTLIL::SigSpec(w_out));
171  c->setPort("\\Q", data_reg_out.back());
172  }
173  }
174 
175  log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
176 
177  int count_dff = 0, count_mux = 0, count_wrmux = 0;
178 
179  for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
180  {
181  RTLIL::SigSpec rd_addr = cell->getPort("\\RD_ADDR").extract(i*mem_abits, mem_abits);
182 
183  std::vector<RTLIL::SigSpec> rd_signals;
184  rd_signals.push_back(cell->getPort("\\RD_DATA").extract(i*mem_width, mem_width));
185 
186  if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
187  {
188  if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
189  {
190  RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
191  c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
192  c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
193  c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
194  c->setPort("\\D", rd_addr);
195  count_dff++;
196 
197  RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
198 
199  c->setPort("\\Q", RTLIL::SigSpec(w));
200  rd_addr = RTLIL::SigSpec(w);
201  }
202  else
203  {
204  RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
205  c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
206  c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
207  c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
208  c->setPort("\\Q", rd_signals.back());
209  count_dff++;
210 
211  RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
212 
213  rd_signals.clear();
214  rd_signals.push_back(RTLIL::SigSpec(w));
215  c->setPort("\\D", rd_signals.back());
216  }
217  }
218 
219  for (int j = 0; j < mem_abits; j++)
220  {
221  std::vector<RTLIL::SigSpec> next_rd_signals;
222 
223  for (size_t k = 0; k < rd_signals.size(); k++)
224  {
225  RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdmux", i, "", j, "", k), "$mux");
226  c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
227  c->setPort("\\Y", rd_signals[k]);
228  c->setPort("\\S", rd_addr.extract(mem_abits-j-1, 1));
229  count_mux++;
230 
231  c->setPort("\\A", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$a"), mem_width));
232  c->setPort("\\B", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$b"), mem_width));
233 
234  next_rd_signals.push_back(c->getPort("\\A"));
235  next_rd_signals.push_back(c->getPort("\\B"));
236  }
237 
238  next_rd_signals.swap(rd_signals);
239  }
240 
241  for (int j = 0; j < mem_size; j++)
242  module->connect(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
243  }
244 
245  log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
246 
247  for (int i = 0; i < mem_size; i++)
248  {
249  if (static_cells_map.count(i) > 0)
250  continue;
251 
252  RTLIL::SigSpec sig = data_reg_out[i];
253 
254  for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
255  {
256  RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(j*mem_abits, mem_abits);
257  RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(j*mem_width, mem_width);
258  RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(j*mem_width, mem_width);
259  RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
260 
261  int wr_offset = 0;
262  while (wr_offset < wr_en.size())
263  {
264  int wr_width = 1;
265  RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
266 
267  while (wr_offset + wr_width < wr_en.size()) {
268  RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
269  if (next_wr_bit != wr_bit)
270  break;
271  wr_width++;
272  }
273 
274  RTLIL::Wire *w = w_seladdr;
275 
276  if (wr_bit != RTLIL::SigSpec(1, 1))
277  {
278  RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), "$and");
279  c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
280  c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
281  c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
282  c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
283  c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
284  c->setPort("\\A", w);
285  c->setPort("\\B", wr_bit);
286 
287  w = module->addWire(genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y"));
288  c->setPort("\\Y", RTLIL::SigSpec(w));
289  }
290 
291  RTLIL::Cell *c = module->addCell(genid(cell->name, "$wrmux", i, "", j, "", wr_offset), "$mux");
292  c->parameters["\\WIDTH"] = wr_width;
293  c->setPort("\\A", sig.extract(wr_offset, wr_width));
294  c->setPort("\\B", wr_data.extract(wr_offset, wr_width));
295  c->setPort("\\S", RTLIL::SigSpec(w));
296 
297  w = module->addWire(genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
298  c->setPort("\\Y", w);
299 
300  sig.replace(wr_offset, w);
301  wr_offset += wr_width;
302  count_wrmux++;
303  }
304  }
305 
306  module->connect(RTLIL::SigSig(data_reg_in[i], sig));
307  }
308 
309  log(" write interface: %d write mux blocks.\n", count_wrmux);
310 
311  module->remove(cell);
312  }
313 
314  MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
315  {
316  std::vector<RTLIL::Cell*> cells;
317  for (auto cell : module->selected_cells())
318  if (cell->type == "$mem" && design->selected(module, cell))
319  cells.push_back(cell);
320  for (auto cell : cells)
321  handle_cell(cell);
322  }
323 };
324 
325 struct MemoryMapPass : public Pass {
326  MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
327  virtual void help()
328  {
329  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
330  log("\n");
331  log(" memory_map [selection]\n");
332  log("\n");
333  log("This pass converts multiport memory cells as generated by the memory_collect\n");
334  log("pass to word-wide DFFs and address decoders.\n");
335  log("\n");
336  }
337  virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
338  log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
339  extra_args(args, 1, design);
340  for (auto mod : design->selected_modules())
341  MemoryMapWorker(design, mod);
342  }
343 } MemoryMapPass;
344 
const char * c_str() const
Definition: rtlil.h:178
bool selected(T1 *module) const
Definition: rtlil.h:551
RTLIL::Wire * wire
Definition: rtlil.h:907
std::string str() const
Definition: rtlil.h:182
std::string stringf(const char *fmt,...)
Definition: yosys.cc:58
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
Definition: rtlil.cc:1353
virtual void help()
Definition: memory_map.cc:327
void log_header(const char *format,...)
Definition: log.cc:188
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
Definition: rtlil.h:595
bool as_bool() const
Definition: rtlil.cc:2818
RTLIL::IdString name
Definition: rtlil.h:853
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
Definition: rtlil.cc:1789
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: memory_map.cc:337
std::map< RTLIL::IdString, RTLIL::Const > parameters
Definition: rtlil.h:856
int size() const
Definition: rtlil.h:1019
std::map< std::pair< RTLIL::SigSpec, RTLIL::SigSpec >, RTLIL::SigBit > decoder_cache
Definition: memory_map.cc:34
RTLIL::SigSpec Eq(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed=false)
void connect(const RTLIL::SigSig &conn)
Definition: rtlil.cc:1278
RTLIL::Module * module
Definition: memory_map.cc:32
RTLIL::Design * design
Definition: memory_map.cc:31
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1809
int GetSize(RTLIL::Wire *wire)
Definition: yosys.cc:334
#define log_assert(_assert_expr_)
Definition: log.h:85
bool is_fully_const() const
Definition: rtlil.cc:2763
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
Definition: rtlil.cc:1331
RTLIL::IdString name
Definition: rtlil.h:599
#define NEW_ID
Definition: yosys.h:166
std::vector< RTLIL::Cell * > selected_cells() const
Definition: rtlil.cc:1103
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
Definition: rtlil.cc:2297
int as_int(bool is_signed=false) const
Definition: rtlil.cc:2829
void remove(const std::set< RTLIL::Wire * > &wires)
Definition: rtlil.cc:1158
MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module)
Definition: memory_map.cc:314
void log(const char *format,...)
Definition: log.cc:180
void handle_cell(RTLIL::Cell *cell)
Definition: memory_map.cc:79
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
RTLIL::SigSpec And(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed=false)
std::vector< RTLIL::State > bits
Definition: rtlil.h:438
std::vector< RTLIL::Module * > selected_modules() const
Definition: rtlil.cc:416
State
Definition: rtlil.h:29
int start_offset
Definition: rtlil.h:826
RTLIL::Wire * addr_decode(RTLIL::SigSpec addr_sig, RTLIL::SigSpec addr_val)
Definition: memory_map.cc:58
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
std::string genid(RTLIL::IdString name, std::string token1="", int i=-1, std::string token2="", int j=-1, std::string token3="", int k=-1, std::string token4="")
Definition: memory_map.cc:36
std::pair< SigSpec, SigSpec > SigSig
Definition: rtlil.h:71
YOSYS_NAMESPACE_BEGIN int autoidx
Definition: yosys.cc:51
MemoryMapPass MemoryMapPass