mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	cxxrtl: Support memory writes in processes.
This commit is contained in:
		
							parent
							
								
									af7fa62251
								
							
						
					
					
						commit
						37506d737c
					
				
					 1 changed files with 55 additions and 6 deletions
				
			
		|  | @ -226,6 +226,14 @@ bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell) | ||||||
| 	return cell_module->get_bool_attribute(ID(cxxrtl_blackbox)); | 	return cell_module->get_bool_attribute(ID(cxxrtl_blackbox)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool is_memwr_process(const RTLIL::Process *process) | ||||||
|  | { | ||||||
|  | 	for (auto sync : process->syncs) | ||||||
|  | 		if (!sync->mem_write_actions.empty()) | ||||||
|  | 			return true; | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| enum class CxxrtlPortType { | enum class CxxrtlPortType { | ||||||
| 	UNKNOWN = 0, // or mixed comb/sync
 | 	UNKNOWN = 0, // or mixed comb/sync
 | ||||||
| 	COMB = 1, | 	COMB = 1, | ||||||
|  | @ -481,14 +489,20 @@ struct FlowGraph { | ||||||
| 
 | 
 | ||||||
| 	void add_sync_rules_defs_uses(Node *node, const RTLIL::Process *process) | 	void add_sync_rules_defs_uses(Node *node, const RTLIL::Process *process) | ||||||
| 	{ | 	{ | ||||||
| 		for (auto sync : process->syncs) | 		for (auto sync : process->syncs) { | ||||||
| 			for (auto action : sync->actions) { | 			for (auto &action : sync->actions) { | ||||||
| 				if (sync->type == RTLIL::STp || sync->type == RTLIL::STn || sync->type == RTLIL::STe) | 				if (sync->type == RTLIL::STp || sync->type == RTLIL::STn || sync->type == RTLIL::STe) | ||||||
| 				  add_defs(node, action.first, /*is_ff=*/true,  /*inlinable=*/false); | 					add_defs(node, action.first, /*is_ff=*/true,  /*inlinable=*/false); | ||||||
| 				else | 				else | ||||||
| 					add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false); | 					add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false); | ||||||
| 				add_uses(node, action.second); | 				add_uses(node, action.second); | ||||||
| 			} | 			} | ||||||
|  | 			for (auto &memwr : sync->mem_write_actions) { | ||||||
|  | 				add_uses(node, memwr.address); | ||||||
|  | 				add_uses(node, memwr.data); | ||||||
|  | 				add_uses(node, memwr.enable); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Node *add_node(const RTLIL::Process *process) | 	Node *add_node(const RTLIL::Process *process) | ||||||
|  | @ -685,6 +699,7 @@ struct CxxrtlWorker { | ||||||
| 
 | 
 | ||||||
| 	dict<const RTLIL::Module*, SigMap> sigmaps; | 	dict<const RTLIL::Module*, SigMap> sigmaps; | ||||||
| 	dict<const RTLIL::Module*, std::vector<Mem>> mod_memories; | 	dict<const RTLIL::Module*, std::vector<Mem>> mod_memories; | ||||||
|  | 	pool<std::pair<const RTLIL::Module*, RTLIL::IdString>> writable_memories; | ||||||
| 	pool<const RTLIL::Wire*> edge_wires; | 	pool<const RTLIL::Wire*> edge_wires; | ||||||
| 	dict<const RTLIL::Wire*, RTLIL::Const> wire_init; | 	dict<const RTLIL::Wire*, RTLIL::Const> wire_init; | ||||||
| 	dict<RTLIL::SigBit, RTLIL::SyncType> edge_types; | 	dict<RTLIL::SigBit, RTLIL::SyncType> edge_types; | ||||||
|  | @ -776,6 +791,11 @@ struct CxxrtlWorker { | ||||||
| 		return mangle_memory_name(mem->memid); | 		return mangle_memory_name(mem->memid); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	std::string mangle(const RTLIL::Memory *memory) | ||||||
|  | 	{ | ||||||
|  | 		return mangle_memory_name(memory->name); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	std::string mangle(const RTLIL::Cell *cell) | 	std::string mangle(const RTLIL::Cell *cell) | ||||||
| 	{ | 	{ | ||||||
| 		return mangle_cell_name(cell->name); | 		return mangle_cell_name(cell->name); | ||||||
|  | @ -1498,8 +1518,28 @@ struct CxxrtlWorker { | ||||||
| 				} | 				} | ||||||
| 				f << ") {\n"; | 				f << ") {\n"; | ||||||
| 				inc_indent(); | 				inc_indent(); | ||||||
| 					for (auto action : sync->actions) | 					for (auto &action : sync->actions) | ||||||
| 						dump_assign(action, for_debug); | 						dump_assign(action, for_debug); | ||||||
|  | 					for (auto &memwr : sync->mem_write_actions) { | ||||||
|  | 						RTLIL::Memory *memory = proc->module->memories.at(memwr.memid); | ||||||
|  | 						std::string valid_index_temp = fresh_temporary(); | ||||||
|  | 						f << indent << "auto " << valid_index_temp << " = memory_index("; | ||||||
|  | 						dump_sigspec_rhs(memwr.address); | ||||||
|  | 						f << ", " << memory->start_offset << ", " << memory->size << ");\n"; | ||||||
|  | 						// See below for rationale of having both the assert and the condition.
 | ||||||
|  | 						//
 | ||||||
|  | 						// If assertions are disabled, out of bounds writes are defined to do nothing.
 | ||||||
|  | 						f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds write\");\n"; | ||||||
|  | 						f << indent << "if (" << valid_index_temp << ".valid) {\n"; | ||||||
|  | 						inc_indent(); | ||||||
|  | 							f << indent << mangle(memory) << ".update(" << valid_index_temp << ".index, "; | ||||||
|  | 							dump_sigspec_rhs(memwr.data); | ||||||
|  | 							f << ", "; | ||||||
|  | 							dump_sigspec_rhs(memwr.enable); | ||||||
|  | 							f << ");\n"; | ||||||
|  | 						dec_indent(); | ||||||
|  | 						f << indent << "}\n"; | ||||||
|  | 					} | ||||||
| 				dec_indent(); | 				dec_indent(); | ||||||
| 				f << indent << "}\n"; | 				f << indent << "}\n"; | ||||||
| 			} | 			} | ||||||
|  | @ -1917,7 +1957,7 @@ struct CxxrtlWorker { | ||||||
| 			} | 			} | ||||||
| 			if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { | 			if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { | ||||||
| 				for (auto &mem : mod_memories[module]) { | 				for (auto &mem : mod_memories[module]) { | ||||||
| 					if (!GetSize(mem.wr_ports)) | 					if (!writable_memories.count({module, mem.memid})) | ||||||
| 						continue; | 						continue; | ||||||
| 					f << indent << "if (" << mangle(&mem) << ".commit()) changed = true;\n"; | 					f << indent << "if (" << mangle(&mem) << ".commit()) changed = true;\n"; | ||||||
| 				} | 				} | ||||||
|  | @ -2556,12 +2596,15 @@ struct CxxrtlWorker { | ||||||
| 							register_edge_signal(sigmap, port.clk, | 							register_edge_signal(sigmap, port.clk, | ||||||
| 								port.clk_polarity ? RTLIL::STp : RTLIL::STn); | 								port.clk_polarity ? RTLIL::STp : RTLIL::STn); | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				if (!mem.wr_ports.empty()) | ||||||
|  | 					writable_memories.insert({module, mem.memid}); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			for (auto proc : module->processes) { | 			for (auto proc : module->processes) { | ||||||
| 				flow.add_node(proc.second); | 				flow.add_node(proc.second); | ||||||
| 
 | 
 | ||||||
| 				for (auto sync : proc.second->syncs) | 				for (auto sync : proc.second->syncs) { | ||||||
| 					switch (sync->type) { | 					switch (sync->type) { | ||||||
| 						// Edge-type sync rules require pre-registration.
 | 						// Edge-type sync rules require pre-registration.
 | ||||||
| 						case RTLIL::STp: | 						case RTLIL::STp: | ||||||
|  | @ -2584,6 +2627,10 @@ struct CxxrtlWorker { | ||||||
| 						case RTLIL::STi: | 						case RTLIL::STi: | ||||||
| 							log_assert(false); | 							log_assert(false); | ||||||
| 					} | 					} | ||||||
|  | 					for (auto &memwr : sync->mem_write_actions) { | ||||||
|  | 						writable_memories.insert({module, memwr.memid}); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// Construct a linear order of the flow graph that minimizes the amount of feedback arcs. A flow graph
 | 			// Construct a linear order of the flow graph that minimizes the amount of feedback arcs. A flow graph
 | ||||||
|  | @ -2655,6 +2702,8 @@ struct CxxrtlWorker { | ||||||
| 					worklist.insert(node); // node has effects
 | 					worklist.insert(node); // node has effects
 | ||||||
| 				else if (node->type == FlowGraph::Node::Type::MEM_WRPORTS) | 				else if (node->type == FlowGraph::Node::Type::MEM_WRPORTS) | ||||||
| 					worklist.insert(node); // node is memory write
 | 					worklist.insert(node); // node is memory write
 | ||||||
|  | 				else if (node->type == FlowGraph::Node::Type::PROCESS_SYNC && is_memwr_process(node->process)) | ||||||
|  | 					worklist.insert(node); // node is memory write
 | ||||||
| 				else if (flow.node_sync_defs.count(node)) | 				else if (flow.node_sync_defs.count(node)) | ||||||
| 					worklist.insert(node); // node is a flip-flop
 | 					worklist.insert(node); // node is a flip-flop
 | ||||||
| 				else if (flow.node_comb_defs.count(node)) { | 				else if (flow.node_comb_defs.count(node)) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue