mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	cxxrtl: preserve interior memory pointers across reset.
Before this commit, values, wires, and memories with an initializer were value-initialized in emitted C++ code. After this commit, all values, wires, and memories are default-initialized, and the default constructor of generated modules calls the reset() method, which assigns the members that have an initializer.
This commit is contained in:
		
							parent
							
								
									7c9e498662
								
							
						
					
					
						commit
						55c9fb3b18
					
				
					 2 changed files with 67 additions and 95 deletions
				
			
		|  | @ -738,24 +738,6 @@ struct memory { | |||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	// The only way to get the compiler to put the initializer in .rodata and do not copy it on stack is to stuff it
 | ||||
| 	// into a plain array. You'd think an std::initializer_list would work here, but it doesn't, because you can't
 | ||||
| 	// construct an initializer_list in a constexpr (or something) and so if you try to do that the whole thing is
 | ||||
| 	// first copied on the stack (probably overflowing it) and then again into `data`.
 | ||||
| 	template<size_t Size> | ||||
| 	struct init { | ||||
| 		size_t offset; | ||||
| 		value<Width> data[Size]; | ||||
| 	}; | ||||
| 
 | ||||
| 	template<size_t... InitSize> | ||||
| 	explicit memory(size_t depth, const init<InitSize> &...init) : depth(depth), data(new value<Width>[depth]) { | ||||
| 		// This utterly reprehensible construct is the most reasonable way to apply a function to every element
 | ||||
| 		// of a parameter pack, if the elements all have different types and so cannot be cast to an initializer list.
 | ||||
| 		auto _ = {std::move(std::begin(init.data), std::end(init.data), &data[init.offset])...}; | ||||
| 		(void)_; | ||||
| 	} | ||||
| 
 | ||||
| 	// An operator for direct memory reads. May be used at any time during the simulation.
 | ||||
| 	const value<Width> &operator [](size_t index) const { | ||||
| 		assert(index < depth); | ||||
|  | @ -1051,9 +1033,9 @@ struct debug_items { | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| // Tag class to disambiguate module move constructor and module constructor that takes black boxes
 | ||||
| // out of another instance of the module.
 | ||||
| struct adopt {}; | ||||
| // Tag class to disambiguate the default constructor used by the toplevel module that calls reset(),
 | ||||
| // and the constructor of interior modules that should not call it.
 | ||||
| struct interior {}; | ||||
| 
 | ||||
| struct module { | ||||
| 	module() {} | ||||
|  |  | |||
|  | @ -934,11 +934,6 @@ struct CxxrtlWorker { | |||
| 		f << "}"; | ||||
| 	} | ||||
| 
 | ||||
| 	void dump_const_init(const RTLIL::Const &data) | ||||
| 	{ | ||||
| 		dump_const_init(data, data.size()); | ||||
| 	} | ||||
| 
 | ||||
| 	void dump_const(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false) | ||||
| 	{ | ||||
| 		f << "value<" << width << ">"; | ||||
|  | @ -1785,20 +1780,10 @@ struct CxxrtlWorker { | |||
| 		} else { | ||||
| 			f << "<" << wire->width << ">"; | ||||
| 		} | ||||
| 		f << " " << mangle(wire); | ||||
| 		if (wire_init.count(wire)) { | ||||
| 			f << " "; | ||||
| 			dump_const_init(wire_init.at(wire)); | ||||
| 		} | ||||
| 		f << ";\n"; | ||||
| 		f << " " << mangle(wire) << ";\n"; | ||||
| 		if (edge_wires[wire]) { | ||||
| 			if (!wire_type.is_buffered()) { | ||||
| 				f << indent << "value<" << wire->width << "> prev_" << mangle(wire); | ||||
| 				if (wire_init.count(wire)) { | ||||
| 					f << " "; | ||||
| 					dump_const_init(wire_init.at(wire)); | ||||
| 				} | ||||
| 				f << ";\n"; | ||||
| 				f << indent << "value<" << wire->width << "> prev_" << mangle(wire) << ";\n"; | ||||
| 			} | ||||
| 			for (auto edge_type : edge_types) { | ||||
| 				if (edge_type.first.wire == wire) { | ||||
|  | @ -1848,38 +1833,65 @@ struct CxxrtlWorker { | |||
| 		f << "value<" << wire->width << "> " << mangle(wire) << ";\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	void dump_memory(Mem *mem) | ||||
| 	void dump_reset_method(RTLIL::Module *module) | ||||
| 	{ | ||||
| 		dump_attrs(mem); | ||||
| 		f << indent << "memory<" << mem->width << "> " << mangle(mem) | ||||
| 		            << " { " << mem->size << "u"; | ||||
| 		if (!GetSize(mem->inits)) { | ||||
| 			f << " };\n"; | ||||
| 		} else { | ||||
| 			f << ",\n"; | ||||
| 			inc_indent(); | ||||
| 				for (auto &init : mem->inits) { | ||||
| 		int mem_init_idx = 0; | ||||
| 		inc_indent(); | ||||
| 			for (auto wire : module->wires()) { | ||||
| 				if (!wire_init.count(wire)) continue; | ||||
| 
 | ||||
| 				f << indent << mangle(wire) << " = "; | ||||
| 				if (wire_types[wire].is_buffered()) { | ||||
| 					f << "wire<" << wire->width << ">"; | ||||
| 				} else { | ||||
| 					f << "value<" << wire->width << ">"; | ||||
| 				} | ||||
| 				dump_const_init(wire_init.at(wire), wire->width); | ||||
| 				f << ";\n"; | ||||
| 
 | ||||
| 				if (edge_wires[wire] && !wire_types[wire].is_buffered()) { | ||||
| 					f << indent << "prev_" << mangle(wire) << " = "; | ||||
| 					dump_const(wire_init.at(wire), wire->width); | ||||
| 					f << ";\n"; | ||||
| 				} | ||||
| 			} | ||||
| 			for (auto &mem : mod_memories[module]) { | ||||
| 				for (auto &init : mem.inits) { | ||||
| 					if (init.removed) | ||||
| 						continue; | ||||
| 					dump_attrs(&init); | ||||
| 					int words = GetSize(init.data) / mem->width; | ||||
| 					f << indent << "memory<" << mem->width << ">::init<" << words << "> { " | ||||
| 						    << stringf("%#x", init.addr.as_int()) << ", {"; | ||||
| 					int words = GetSize(init.data) / mem.width; | ||||
| 					f << indent << "static const value<" << mem.width << "> "; | ||||
| 					f << "mem_init_" << ++mem_init_idx << "[" << words << "] {"; | ||||
| 					inc_indent(); | ||||
| 						for (int n = 0; n < words; n++) { | ||||
| 							if (n % 4 == 0) | ||||
| 								f << "\n" << indent; | ||||
| 							else | ||||
| 								f << " "; | ||||
| 							dump_const(init.data, mem->width, n * mem->width, /*fixed_width=*/true); | ||||
| 							dump_const(init.data, mem.width, n * mem.width, /*fixed_width=*/true); | ||||
| 							f << ","; | ||||
| 						} | ||||
| 					dec_indent(); | ||||
| 					f << "\n" << indent << "}},\n"; | ||||
| 					f << "\n"; | ||||
| 					f << indent << "};\n"; | ||||
| 					f << indent << "std::copy(std::begin(mem_init_" << mem_init_idx << "), "; | ||||
| 					f << "std::end(mem_init_" << mem_init_idx << "), "; | ||||
| 					f << "&" << mangle(&mem) << ".data[" << stringf("%#x", init.addr.as_int()) << "]);\n"; | ||||
| 				} | ||||
| 			dec_indent(); | ||||
| 			f << indent << "};\n"; | ||||
| 		} | ||||
| 			} | ||||
| 			for (auto cell : module->cells()) { | ||||
| 				if (is_internal_cell(cell->type)) | ||||
| 					continue; | ||||
| 				f << indent << mangle(cell); | ||||
| 				RTLIL::Module *cell_module = module->design->module(cell->type); | ||||
| 				if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { | ||||
| 					f << "->reset();\n"; | ||||
| 				} else { | ||||
| 					f << ".reset();\n"; | ||||
| 				} | ||||
| 			} | ||||
| 		dec_indent(); | ||||
| 	} | ||||
| 
 | ||||
| 	void dump_eval_method(RTLIL::Module *module) | ||||
|  | @ -2200,6 +2212,10 @@ struct CxxrtlWorker { | |||
| 						dump_wire(wire, /*is_local=*/false); | ||||
| 				} | ||||
| 				f << "\n"; | ||||
| 				f << indent << "void reset() override {\n"; | ||||
| 				dump_reset_method(module); | ||||
| 				f << indent << "}\n"; | ||||
| 				f << "\n"; | ||||
| 				f << indent << "bool eval() override {\n"; | ||||
| 				dump_eval_method(module); | ||||
| 				f << indent << "}\n"; | ||||
|  | @ -2248,7 +2264,9 @@ struct CxxrtlWorker { | |||
| 					dump_debug_wire(wire, /*is_local=*/false); | ||||
| 				bool has_memories = false; | ||||
| 				for (auto &mem : mod_memories[module]) { | ||||
| 					dump_memory(&mem); | ||||
| 					dump_attrs(&mem); | ||||
| 					f << indent << "memory<" << mem.width << "> " << mangle(&mem) | ||||
| 					            << " { " << mem.size << "u };\n"; | ||||
| 					has_memories = true; | ||||
| 				} | ||||
| 				if (has_memories) | ||||
|  | @ -2269,52 +2287,20 @@ struct CxxrtlWorker { | |||
| 						dump_metadata_map(cell->attributes); | ||||
| 						f << ");\n"; | ||||
| 					} else { | ||||
| 						f << indent << mangle(cell_module) << " " << mangle(cell) << ";\n"; | ||||
| 						f << indent << mangle(cell_module) << " " << mangle(cell) << " {interior()};\n"; | ||||
| 					} | ||||
| 					has_cells = true; | ||||
| 				} | ||||
| 				if (has_cells) | ||||
| 					f << "\n"; | ||||
| 				f << indent << mangle(module) << "() {}\n"; | ||||
| 				if (has_cells) { | ||||
| 					f << indent << mangle(module) << "(adopt, " << mangle(module) << " other) :\n"; | ||||
| 					bool first = true; | ||||
| 					for (auto cell : module->cells()) { | ||||
| 						if (is_internal_cell(cell->type)) | ||||
| 							continue; | ||||
| 						if (first) { | ||||
| 							first = false; | ||||
| 						} else { | ||||
| 							f << ",\n"; | ||||
| 						} | ||||
| 						RTLIL::Module *cell_module = module->design->module(cell->type); | ||||
| 						if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { | ||||
| 							f << indent << "  " << mangle(cell) << "(std::move(other." << mangle(cell) << "))"; | ||||
| 						} else { | ||||
| 							f << indent << "  " << mangle(cell) << "(adopt {}, std::move(other." << mangle(cell) << "))"; | ||||
| 						} | ||||
| 					} | ||||
| 					f << " {\n"; | ||||
| 					inc_indent(); | ||||
| 						for (auto cell : module->cells()) { | ||||
| 							if (is_internal_cell(cell->type)) | ||||
| 								continue; | ||||
| 							RTLIL::Module *cell_module = module->design->module(cell->type); | ||||
| 							if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) | ||||
| 								f << indent << mangle(cell) << "->reset();\n"; | ||||
| 						} | ||||
| 					dec_indent(); | ||||
| 					f << indent << "}\n"; | ||||
| 				} else { | ||||
| 					f << indent << mangle(module) << "(adopt, " << mangle(module) << " other) {}\n"; | ||||
| 				} | ||||
| 				f << "\n"; | ||||
| 				f << indent << "void reset() override {\n"; | ||||
| 				f << indent << mangle(module) << "(interior) {}\n"; | ||||
| 				f << indent << mangle(module) << "() {\n"; | ||||
| 				inc_indent(); | ||||
| 					f << indent << "*this = " << mangle(module) << "(adopt {}, std::move(*this));\n"; | ||||
| 					f << indent << "reset();\n"; | ||||
| 				dec_indent(); | ||||
| 				f << indent << "}\n"; | ||||
| 				f << indent << "};\n"; | ||||
| 				f << "\n"; | ||||
| 				f << indent << "void reset() override;\n"; | ||||
| 				f << indent << "bool eval() override;\n"; | ||||
| 				f << indent << "bool commit() override;\n"; | ||||
| 				if (debug_info) { | ||||
|  | @ -2341,6 +2327,10 @@ struct CxxrtlWorker { | |||
| 	{ | ||||
| 		if (module->get_bool_attribute(ID(cxxrtl_blackbox))) | ||||
| 			return; | ||||
| 		f << indent << "void " << mangle(module) << "::reset() {\n"; | ||||
| 		dump_reset_method(module); | ||||
| 		f << indent << "}\n"; | ||||
| 		f << "\n"; | ||||
| 		f << indent << "bool " << mangle(module) << "::eval() {\n"; | ||||
| 		dump_eval_method(module); | ||||
| 		f << indent << "}\n"; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue