Merge pull request #1085 from YosysHQ/eddie/shregmap_improve
[yosys.git] / passes / memory / memory_memx.cc
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
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct MemoryMemxPass : public Pass {
30 MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
31 void help() YS_OVERRIDE
32 {
33 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
34 log("\n");
35 log(" memory_memx [selection]\n");
36 log("\n");
37 log("This pass adds additional circuitry that emulates the Verilog simulation\n");
38 log("behavior for out-of-bounds memory reads and writes.\n");
39 log("\n");
40 }
41 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
42 log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
43 extra_args(args, 1, design);
44
45 for (auto module : design->selected_modules())
46 {
47 vector<Cell*> mem_port_cells;
48
49 for (auto cell : module->selected_cells())
50 if (cell->type.in("$memrd", "$memwr"))
51 mem_port_cells.push_back(cell);
52
53 for (auto cell : mem_port_cells)
54 {
55 IdString memid = cell->getParam("\\MEMID").decode_string();
56 RTLIL::Memory *mem = module->memories.at(memid);
57
58 int lowest_addr = mem->start_offset;
59 int highest_addr = mem->start_offset + mem->size - 1;
60
61 SigSpec addr = cell->getPort("\\ADDR");
62 addr.extend_u0(32);
63
64 SigSpec addr_ok = module->Nex(NEW_ID, module->ReduceXor(NEW_ID, addr), module->ReduceXor(NEW_ID, {addr, State::S1}));
65 if (lowest_addr != 0)
66 addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Ge(NEW_ID, addr, lowest_addr));
67 addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Le(NEW_ID, addr, highest_addr));
68
69 if (cell->type == "$memrd")
70 {
71 if (cell->getParam("\\CLK_ENABLE").as_bool())
72 log_error("Cell %s.%s (%s) has an enabled clock. Clocked $memrd cells are not supported by memory_memx!\n",
73 log_id(module), log_id(cell), log_id(cell->type));
74
75 SigSpec rdata = cell->getPort("\\DATA");
76 Wire *raw_rdata = module->addWire(NEW_ID, GetSize(rdata));
77 module->addMux(NEW_ID, SigSpec(State::Sx, GetSize(rdata)), raw_rdata, addr_ok, rdata);
78 cell->setPort("\\DATA", raw_rdata);
79 }
80
81 if (cell->type == "$memwr")
82 {
83 SigSpec en = cell->getPort("\\EN");
84 en = module->And(NEW_ID, en, addr_ok.repeat(GetSize(en)));
85 cell->setPort("\\EN", en);
86 }
87 }
88 }
89 }
90 } MemoryMemxPass;
91
92 PRIVATE_NAMESPACE_END