2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/register.h"
21 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
29 struct MemoryMemxPass
: public Pass
{
30 MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
31 void help() YS_OVERRIDE
33 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
35 log(" memory_memx [selection]\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");
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
);
45 for (auto module
: design
->selected_modules())
47 vector
<Cell
*> mem_port_cells
;
49 for (auto cell
: module
->selected_cells())
50 if (cell
->type
.in("$memrd", "$memwr"))
51 mem_port_cells
.push_back(cell
);
53 for (auto cell
: mem_port_cells
)
55 IdString memid
= cell
->getParam("\\MEMID").decode_string();
56 RTLIL::Memory
*mem
= module
->memories
.at(memid
);
58 int lowest_addr
= mem
->start_offset
;
59 int highest_addr
= mem
->start_offset
+ mem
->size
- 1;
61 SigSpec addr
= cell
->getPort("\\ADDR");
64 SigSpec addr_ok
= module
->Nex(NEW_ID
, module
->ReduceXor(NEW_ID
, addr
), module
->ReduceXor(NEW_ID
, {addr
, State::S1
}));
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
));
69 if (cell
->type
== "$memrd")
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
));
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
);
81 if (cell
->type
== "$memwr")
83 SigSpec en
= cell
->getPort("\\EN");
84 en
= module
->And(NEW_ID
, en
, addr_ok
.repeat(GetSize(en
)));
85 cell
->setPort("\\EN", en
);