From: Clifford Wolf Date: Fri, 19 Aug 2016 17:48:26 +0000 (+0200) Subject: Added memory_memx pass, "memory -memx", and "prep -memx" X-Git-Tag: yosys-0.7~127 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=15ef6084533809894dd0b5200a65497047c2ccf8;p=yosys.git Added memory_memx pass, "memory -memx", and "prep -memx" --- diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc index aeff225d8..ad359c01b 100644 --- a/passes/memory/Makefile.inc +++ b/passes/memory/Makefile.inc @@ -6,4 +6,5 @@ OBJS += passes/memory/memory_collect.o OBJS += passes/memory/memory_unpack.o OBJS += passes/memory/memory_bram.o OBJS += passes/memory/memory_map.o +OBJS += passes/memory/memory_memx.o diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc index e3c627607..947d598be 100644 --- a/passes/memory/memory.cc +++ b/passes/memory/memory.cc @@ -31,14 +31,15 @@ struct MemoryPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" memory [-nomap] [-nordff] [-bram ] [selection]\n"); + log(" memory [-nomap] [-nordff] [-memx] [-bram ] [selection]\n"); log("\n"); log("This pass calls all the other memory_* passes in a useful order:\n"); log("\n"); - log(" memory_dff [-nordff]\n"); + log(" memory_dff [-nordff] (-memx implies -nordff)\n"); log(" opt_clean\n"); log(" memory_share\n"); log(" opt_clean\n"); + log(" memory_memx (when called with -memx)\n"); log(" memory_collect\n"); log(" memory_bram -rules (when called with -bram)\n"); log(" memory_map (skipped if called with -nomap)\n"); @@ -51,6 +52,7 @@ struct MemoryPass : public Pass { { bool flag_nomap = false; bool flag_nordff = false; + bool flag_memx = false; string memory_bram_opts; log_header(design, "Executing MEMORY pass.\n"); @@ -66,6 +68,11 @@ struct MemoryPass : public Pass { flag_nordff = true; continue; } + if (args[argidx] == "-memx") { + flag_nordff = true; + flag_memx = true; + continue; + } if (argidx+1 < args.size() && args[argidx] == "-bram") { memory_bram_opts += " -rules " + args[++argidx]; continue; @@ -77,6 +84,8 @@ struct MemoryPass : public Pass { Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff"); Pass::call(design, "opt_clean"); Pass::call(design, "memory_share"); + if (flag_memx) + Pass::call(design, "memory_memx"); Pass::call(design, "opt_clean"); Pass::call(design, "memory_collect"); diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc new file mode 100644 index 000000000..2b02e2490 --- /dev/null +++ b/passes/memory/memory_memx.cc @@ -0,0 +1,92 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/log.h" +#include +#include +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MemoryMemxPass : public Pass { + MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" memory_memx [selection]\n"); + log("\n"); + log("This pass adds additional circuitry that emulates the Verilog simulation\n"); + log("behavior for out-of-bounds memory reads and writes.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) { + log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n"); + extra_args(args, 1, design); + + for (auto module : design->selected_modules()) + { + vector mem_port_cells; + + for (auto cell : module->selected_cells()) + if (cell->type.in("$memrd", "$memwr")) + mem_port_cells.push_back(cell); + + for (auto cell : mem_port_cells) + { + IdString memid = cell->getParam("\\MEMID").decode_string(); + RTLIL::Memory *mem = module->memories.at(memid); + + int lowest_addr = mem->start_offset; + int highest_addr = mem->start_offset + mem->size - 1; + + SigSpec addr = cell->getPort("\\ADDR"); + addr.extend_u0(32); + + SigSpec addr_ok = module->Nex(NEW_ID, module->ReduceXor(NEW_ID, addr), module->ReduceXor(NEW_ID, {addr, State::S1})); + if (lowest_addr != 0) + addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Ge(NEW_ID, addr, lowest_addr)); + addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Le(NEW_ID, addr, highest_addr)); + + if (cell->type == "$memrd") + { + if (cell->getParam("\\CLK_ENABLE").as_bool()) + log_error("Cell %s.%s (%s) has an enabled clock. Clocked $memrd cells are not supported by memory_memx!\n", + log_id(module), log_id(cell), log_id(cell->type)); + + SigSpec rdata = cell->getPort("\\DATA"); + Wire *raw_rdata = module->addWire(NEW_ID, GetSize(rdata)); + module->addMux(NEW_ID, SigSpec(State::Sx, GetSize(rdata)), raw_rdata, addr_ok, rdata); + cell->setPort("\\DATA", raw_rdata); + } + + if (cell->type == "$memwr") + { + SigSpec en = cell->getPort("\\EN"); + en = module->And(NEW_ID, en, addr_ok.repeat(GetSize(en))); + cell->setPort("\\EN", en); + } + } + } + } +} MemoryMemxPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index ac1d98fde..8accb7e28 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -53,6 +53,10 @@ struct PrepPass : public ScriptPass log(" passed to 'proc'. uses verilog simulation behavior for verilog if/case\n"); log(" undef handling. this also prevents 'wreduce' from being run.\n"); log("\n"); + log(" -memx\n"); + log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n"); + log(" using the 'memory_memx' pass. This option implies -nordff.\n"); + log("\n"); log(" -nordff\n"); log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n"); log("\n"); @@ -68,7 +72,7 @@ struct PrepPass : public ScriptPass } string top_module, fsm_opts, memory_opts; - bool autotop, flatten, ifxmode; + bool autotop, flatten, ifxmode, memxmode; virtual void clear_flags() YS_OVERRIDE { @@ -78,6 +82,7 @@ struct PrepPass : public ScriptPass autotop = false; flatten = false; ifxmode = false; + memxmode = false; } virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -114,6 +119,11 @@ struct PrepPass : public ScriptPass ifxmode = true; continue; } + if (args[argidx] == "-memx") { + memxmode = true; + memory_opts += " -nordff"; + continue; + } if (args[argidx] == "-nordff") { memory_opts += " -nordff"; continue; @@ -153,7 +163,10 @@ struct PrepPass : public ScriptPass if (check_label("coarse")) { - run(ifxmode ? "proc -ifx" : "proc"); + if (help_mode) + run("proc [-ifx]"); + else + run(ifxmode ? "proc -ifx" : "proc"); if (help_mode || flatten) run("flatten", "(if -flatten)"); run("opt_expr -keepdc"); @@ -163,6 +176,8 @@ struct PrepPass : public ScriptPass if (!ifxmode) run("wreduce"); run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts)); + if (help_mode || memxmode) + run("memory_memx", "(if -memx)"); run("opt_clean"); run("memory_collect"); run("opt -keepdc -fast");