mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Added memory_memx pass, "memory -memx", and "prep -memx"
This commit is contained in:
		
							parent
							
								
									f6629b9c29
								
							
						
					
					
						commit
						15ef608453
					
				
					 4 changed files with 121 additions and 4 deletions
				
			
		|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 <bram_rules>] [selection]\n"); | ||||
| 		log("    memory [-nomap] [-nordff] [-memx] [-bram <bram_rules>] [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 <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"); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										92
									
								
								passes/memory/memory_memx.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								passes/memory/memory_memx.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  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 <sstream> | ||||
| #include <set> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| 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<std::string> 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<Cell*> 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 | ||||
|  | @ -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<std::string> 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,6 +163,9 @@ struct PrepPass : public ScriptPass | |||
| 
 | ||||
| 		if (check_label("coarse")) | ||||
| 		{ | ||||
| 			if (help_mode) | ||||
| 				run("proc [-ifx]"); | ||||
| 			else | ||||
| 				run(ifxmode ? "proc -ifx" : "proc"); | ||||
| 			if (help_mode || flatten) | ||||
| 				run("flatten", "(if -flatten)"); | ||||
|  | @ -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"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue