mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Add support for memory writes in processes.
This commit is contained in:
		
							parent
							
								
									c00a29296c
								
							
						
					
					
						commit
						4e03865d5b
					
				
					 16 changed files with 246 additions and 44 deletions
				
			
		| 
						 | 
					@ -242,11 +242,28 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
 | 
				
			||||||
	case RTLIL::STi: f << stringf("init\n"); break;
 | 
						case RTLIL::STi: f << stringf("init\n"); break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
 | 
						for (auto &it: sy->actions) {
 | 
				
			||||||
		f << stringf("%s  update ", indent.c_str());
 | 
							f << stringf("%s  update ", indent.c_str());
 | 
				
			||||||
		dump_sigspec(f, it->first);
 | 
							dump_sigspec(f, it.first);
 | 
				
			||||||
		f << stringf(" ");
 | 
							f << stringf(" ");
 | 
				
			||||||
		dump_sigspec(f, it->second);
 | 
							dump_sigspec(f, it.second);
 | 
				
			||||||
 | 
							f << stringf("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &it: sy->mem_write_actions) {
 | 
				
			||||||
 | 
							for (auto it2 = it.attributes.begin(); it2 != it.attributes.end(); ++it2) {
 | 
				
			||||||
 | 
								f << stringf("%s  attribute %s ", indent.c_str(), it2->first.c_str());
 | 
				
			||||||
 | 
								dump_const(f, it2->second);
 | 
				
			||||||
 | 
								f << stringf("\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							f << stringf("%s  memwr %s ", indent.c_str(), it.memid.c_str());
 | 
				
			||||||
 | 
							dump_sigspec(f, it.address);
 | 
				
			||||||
 | 
							f << stringf(" ");
 | 
				
			||||||
 | 
							dump_sigspec(f, it.data);
 | 
				
			||||||
 | 
							f << stringf(" ");
 | 
				
			||||||
 | 
							dump_sigspec(f, it.enable);
 | 
				
			||||||
 | 
							f << stringf(" ");
 | 
				
			||||||
 | 
							dump_sigspec(f, it.priority_mask);
 | 
				
			||||||
		f << stringf("\n");
 | 
							f << stringf("\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,7 @@ USING_YOSYS_NAMESPACE
 | 
				
			||||||
"global"	{ return TOK_GLOBAL; }
 | 
					"global"	{ return TOK_GLOBAL; }
 | 
				
			||||||
"init"		{ return TOK_INIT; }
 | 
					"init"		{ return TOK_INIT; }
 | 
				
			||||||
"update"	{ return TOK_UPDATE; }
 | 
					"update"	{ return TOK_UPDATE; }
 | 
				
			||||||
 | 
					"memwr"		{ return TOK_MEMWR; }
 | 
				
			||||||
"process"	{ return TOK_PROCESS; }
 | 
					"process"	{ return TOK_PROCESS; }
 | 
				
			||||||
"end"		{ return TOK_END; }
 | 
					"end"		{ return TOK_END; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,7 @@ USING_YOSYS_NAMESPACE
 | 
				
			||||||
%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
 | 
					%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
 | 
				
			||||||
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
 | 
					%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
 | 
				
			||||||
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
 | 
					%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
 | 
				
			||||||
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
 | 
					%token TOK_UPDATE TOK_MEMWR TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
 | 
				
			||||||
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
 | 
					%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%type <rsigspec> sigspec_list_reversed
 | 
					%type <rsigspec> sigspec_list_reversed
 | 
				
			||||||
| 
						 | 
					@ -155,6 +155,7 @@ param_defval_stmt:
 | 
				
			||||||
	TOK_PARAMETER TOK_ID constant EOL {
 | 
						TOK_PARAMETER TOK_ID constant EOL {
 | 
				
			||||||
		current_module->avail_parameters($2);
 | 
							current_module->avail_parameters($2);
 | 
				
			||||||
		current_module->parameter_default_values[$2] = *$3;
 | 
							current_module->parameter_default_values[$2] = *$3;
 | 
				
			||||||
 | 
							delete $3;
 | 
				
			||||||
		free($2);
 | 
							free($2);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -389,6 +390,22 @@ update_list:
 | 
				
			||||||
		delete $3;
 | 
							delete $3;
 | 
				
			||||||
		delete $4;
 | 
							delete $4;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
 | 
						update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL {
 | 
				
			||||||
 | 
							RTLIL::MemWriteAction act;
 | 
				
			||||||
 | 
							act.attributes = attrbuf;
 | 
				
			||||||
 | 
							act.memid = $4;
 | 
				
			||||||
 | 
							act.address = *$5;
 | 
				
			||||||
 | 
							act.data = *$6;
 | 
				
			||||||
 | 
							act.enable = *$7;
 | 
				
			||||||
 | 
							act.priority_mask = *$8;
 | 
				
			||||||
 | 
							current_process->syncs.back()->mem_write_actions.push_back(std::move(act));
 | 
				
			||||||
 | 
							attrbuf.clear();
 | 
				
			||||||
 | 
							free($4);
 | 
				
			||||||
 | 
							delete $5;
 | 
				
			||||||
 | 
							delete $6;
 | 
				
			||||||
 | 
							delete $7;
 | 
				
			||||||
 | 
							delete $8;
 | 
				
			||||||
 | 
						} |
 | 
				
			||||||
	/* empty */;
 | 
						/* empty */;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constant:
 | 
					constant:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4538,6 +4538,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
 | 
				
			||||||
	new_syncrule->type = type;
 | 
						new_syncrule->type = type;
 | 
				
			||||||
	new_syncrule->signal = signal;
 | 
						new_syncrule->signal = signal;
 | 
				
			||||||
	new_syncrule->actions = actions;
 | 
						new_syncrule->actions = actions;
 | 
				
			||||||
 | 
						new_syncrule->mem_write_actions = mem_write_actions;
 | 
				
			||||||
	return new_syncrule;
 | 
						return new_syncrule;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +69,7 @@ namespace RTLIL
 | 
				
			||||||
	struct SigSpec;
 | 
						struct SigSpec;
 | 
				
			||||||
	struct CaseRule;
 | 
						struct CaseRule;
 | 
				
			||||||
	struct SwitchRule;
 | 
						struct SwitchRule;
 | 
				
			||||||
 | 
						struct MemWriteAction;
 | 
				
			||||||
	struct SyncRule;
 | 
						struct SyncRule;
 | 
				
			||||||
	struct Process;
 | 
						struct Process;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1541,11 +1542,21 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
 | 
				
			||||||
	RTLIL::SwitchRule *clone() const;
 | 
						RTLIL::SwitchRule *clone() const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct RTLIL::MemWriteAction : RTLIL::AttrObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RTLIL::IdString memid;
 | 
				
			||||||
 | 
						RTLIL::SigSpec address;
 | 
				
			||||||
 | 
						RTLIL::SigSpec data;
 | 
				
			||||||
 | 
						RTLIL::SigSpec enable;
 | 
				
			||||||
 | 
						RTLIL::Const priority_mask;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::SyncRule
 | 
					struct RTLIL::SyncRule
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RTLIL::SyncType type;
 | 
						RTLIL::SyncType type;
 | 
				
			||||||
	RTLIL::SigSpec signal;
 | 
						RTLIL::SigSpec signal;
 | 
				
			||||||
	std::vector<RTLIL::SigSig> actions;
 | 
						std::vector<RTLIL::SigSig> actions;
 | 
				
			||||||
 | 
						std::vector<RTLIL::MemWriteAction> mem_write_actions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename T> void rewrite_sigspecs(T &functor);
 | 
						template<typename T> void rewrite_sigspecs(T &functor);
 | 
				
			||||||
	template<typename T> void rewrite_sigspecs2(T &functor);
 | 
						template<typename T> void rewrite_sigspecs2(T &functor);
 | 
				
			||||||
| 
						 | 
					@ -1693,6 +1704,11 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
 | 
				
			||||||
		functor(it.first);
 | 
							functor(it.first);
 | 
				
			||||||
		functor(it.second);
 | 
							functor(it.second);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for (auto &it : mem_write_actions) {
 | 
				
			||||||
 | 
							functor(it.address);
 | 
				
			||||||
 | 
							functor(it.data);
 | 
				
			||||||
 | 
							functor(it.enable);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
| 
						 | 
					@ -1702,6 +1718,11 @@ void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
 | 
				
			||||||
	for (auto &it : actions) {
 | 
						for (auto &it : actions) {
 | 
				
			||||||
		functor(it.first, it.second);
 | 
							functor(it.first, it.second);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for (auto &it : mem_write_actions) {
 | 
				
			||||||
 | 
							functor(it.address);
 | 
				
			||||||
 | 
							functor(it.data);
 | 
				
			||||||
 | 
							functor(it.enable);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,8 +350,9 @@ to update {\tt \textbackslash{}q}.
 | 
				
			||||||
An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and
 | 
					An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and
 | 
				
			||||||
exactly one RTLIL::CaseRule object, which is called the {\it root case}.
 | 
					exactly one RTLIL::CaseRule object, which is called the {\it root case}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or
 | 
					An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type), zero or
 | 
				
			||||||
more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial
 | 
					more assignments (RTLIL::SigSig), and zero or more memory writes (RTLIL::MemWriteAction).
 | 
				
			||||||
 | 
					The {\tt always} synchronization condition is used to break combinatorial
 | 
				
			||||||
loops when a latch should be inferred instead.
 | 
					loops when a latch should be inferred instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig)
 | 
					An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,6 +339,23 @@ struct BugpointPass : public Pass {
 | 
				
			||||||
								return design_copy;
 | 
													return design_copy;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											int i = 0;
 | 
				
			||||||
 | 
											for (auto it = sy->mem_write_actions.begin(); it != sy->mem_write_actions.end(); ++it, ++i)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (index++ == seed)
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													log_header(design, "Trying to remove sync %s memwr %s %s %s %s in %s.%s.\n", log_signal(sy->signal), log_id(it->memid), log_signal(it->address), log_signal(it->data), log_signal(it->enable), log_id(mod), log_id(pr.first));
 | 
				
			||||||
 | 
													sy->mem_write_actions.erase(it);
 | 
				
			||||||
 | 
													// Remove the bit for removed action from other actions' priority masks.
 | 
				
			||||||
 | 
													for (auto it2 = sy->mem_write_actions.begin(); it2 != sy->mem_write_actions.end(); ++it2) {
 | 
				
			||||||
 | 
														auto &mask = it2->priority_mask;
 | 
				
			||||||
 | 
														if (GetSize(mask) > i) {
 | 
				
			||||||
 | 
															mask.bits.erase(mask.bits.begin() + i);
 | 
				
			||||||
 | 
														}
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													return design_copy;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,6 +141,14 @@ struct CheckPass : public Pass {
 | 
				
			||||||
						for (auto bit : sigmap(action.second))
 | 
											for (auto bit : sigmap(action.second))
 | 
				
			||||||
							if (bit.wire) used_wires.insert(bit);
 | 
												if (bit.wire) used_wires.insert(bit);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										for (auto memwr : sync->mem_write_actions) {
 | 
				
			||||||
 | 
											for (auto bit : sigmap(memwr.address))
 | 
				
			||||||
 | 
												if (bit.wire) used_wires.insert(bit);
 | 
				
			||||||
 | 
											for (auto bit : sigmap(memwr.data))
 | 
				
			||||||
 | 
												if (bit.wire) used_wires.insert(bit);
 | 
				
			||||||
 | 
											for (auto bit : sigmap(memwr.enable))
 | 
				
			||||||
 | 
												if (bit.wire) used_wires.insert(bit);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,6 +339,11 @@ struct ShowWorker
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		input_signals.insert(obj->signal);
 | 
							input_signals.insert(obj->signal);
 | 
				
			||||||
		collect_proc_signals(obj->actions, input_signals, output_signals);
 | 
							collect_proc_signals(obj->actions, input_signals, output_signals);
 | 
				
			||||||
 | 
							for (auto it : obj->mem_write_actions) {
 | 
				
			||||||
 | 
								input_signals.insert(it.address);
 | 
				
			||||||
 | 
								input_signals.insert(it.data);
 | 
				
			||||||
 | 
								input_signals.insert(it.enable);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void collect_proc_signals(RTLIL::Process *obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
 | 
						void collect_proc_signals(RTLIL::Process *obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,3 +8,4 @@ OBJS += passes/proc/proc_arst.o
 | 
				
			||||||
OBJS += passes/proc/proc_mux.o
 | 
					OBJS += passes/proc/proc_mux.o
 | 
				
			||||||
OBJS += passes/proc/proc_dlatch.o
 | 
					OBJS += passes/proc/proc_dlatch.o
 | 
				
			||||||
OBJS += passes/proc/proc_dff.o
 | 
					OBJS += passes/proc/proc_dff.o
 | 
				
			||||||
 | 
					OBJS += passes/proc/proc_memwr.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ struct ProcPass : public Pass {
 | 
				
			||||||
		log("    proc_mux\n");
 | 
							log("    proc_mux\n");
 | 
				
			||||||
		log("    proc_dlatch\n");
 | 
							log("    proc_dlatch\n");
 | 
				
			||||||
		log("    proc_dff\n");
 | 
							log("    proc_dff\n");
 | 
				
			||||||
 | 
							log("    proc_memwr\n");
 | 
				
			||||||
		log("    proc_clean\n");
 | 
							log("    proc_clean\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
		log("This replaces the processes in the design with multiplexers,\n");
 | 
							log("This replaces the processes in the design with multiplexers,\n");
 | 
				
			||||||
| 
						 | 
					@ -102,6 +103,7 @@ struct ProcPass : public Pass {
 | 
				
			||||||
			Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
 | 
								Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
 | 
				
			||||||
		Pass::call(design, "proc_dlatch");
 | 
							Pass::call(design, "proc_dlatch");
 | 
				
			||||||
		Pass::call(design, "proc_dff");
 | 
							Pass::call(design, "proc_dff");
 | 
				
			||||||
 | 
							Pass::call(design, "proc_memwr");
 | 
				
			||||||
		Pass::call(design, "proc_clean");
 | 
							Pass::call(design, "proc_clean");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log_pop();
 | 
							log_pop();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,6 +153,30 @@ void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec con
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RTLIL::SigSpec apply_reset(RTLIL::Module *mod, RTLIL::Process *proc, RTLIL::SyncRule *sync, SigMap &assign_map, RTLIL::SigSpec root_sig, bool polarity, RTLIL::SigSpec sig, RTLIL::SigSpec log_sig) {
 | 
				
			||||||
 | 
						RTLIL::SigSpec rspec = assign_map(sig);
 | 
				
			||||||
 | 
						RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
 | 
				
			||||||
 | 
						for (int i = 0; i < GetSize(rspec); i++)
 | 
				
			||||||
 | 
							if (rspec[i].wire == NULL)
 | 
				
			||||||
 | 
								rval[i] = rspec[i];
 | 
				
			||||||
 | 
						RTLIL::SigSpec last_rval;
 | 
				
			||||||
 | 
						for (int count = 0; rval != last_rval; count++) {
 | 
				
			||||||
 | 
							last_rval = rval;
 | 
				
			||||||
 | 
							apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
 | 
				
			||||||
 | 
							assign_map.apply(rval);
 | 
				
			||||||
 | 
							if (rval.is_fully_const())
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (count > 100)
 | 
				
			||||||
 | 
								log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
 | 
				
			||||||
 | 
										log_signal(sync->signal), log_signal(rval), log_signal(log_sig));
 | 
				
			||||||
 | 
							rspec = rval;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rval.has_marked_bits())
 | 
				
			||||||
 | 
							log_error("Async reset %s yields non-constant value %s for signal %s.\n",
 | 
				
			||||||
 | 
									log_signal(sync->signal), log_signal(rval), log_signal(log_sig));
 | 
				
			||||||
 | 
						return rval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
 | 
					void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
restart_proc_arst:
 | 
					restart_proc_arst:
 | 
				
			||||||
| 
						 | 
					@ -172,28 +196,18 @@ restart_proc_arst:
 | 
				
			||||||
					sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
 | 
										sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				for (auto &action : sync->actions) {
 | 
									for (auto &action : sync->actions) {
 | 
				
			||||||
					RTLIL::SigSpec rspec = assign_map(action.second);
 | 
										action.second = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, action.second, action.first);
 | 
				
			||||||
					RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
 | 
					 | 
				
			||||||
					for (int i = 0; i < GetSize(rspec); i++)
 | 
					 | 
				
			||||||
						if (rspec[i].wire == NULL)
 | 
					 | 
				
			||||||
							rval[i] = rspec[i];
 | 
					 | 
				
			||||||
					RTLIL::SigSpec last_rval;
 | 
					 | 
				
			||||||
					for (int count = 0; rval != last_rval; count++) {
 | 
					 | 
				
			||||||
						last_rval = rval;
 | 
					 | 
				
			||||||
						apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
 | 
					 | 
				
			||||||
						assign_map.apply(rval);
 | 
					 | 
				
			||||||
						if (rval.is_fully_const())
 | 
					 | 
				
			||||||
							break;
 | 
					 | 
				
			||||||
						if (count > 100)
 | 
					 | 
				
			||||||
							log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
 | 
					 | 
				
			||||||
									log_signal(sync->signal), log_signal(rval), log_signal(action.first));
 | 
					 | 
				
			||||||
						rspec = rval;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if (rval.has_marked_bits())
 | 
					 | 
				
			||||||
						log_error("Async reset %s yields non-constant value %s for signal %s.\n",
 | 
					 | 
				
			||||||
								log_signal(sync->signal), log_signal(rval), log_signal(action.first));
 | 
					 | 
				
			||||||
					action.second = rval;
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									for (auto &memwr : sync->mem_write_actions) {
 | 
				
			||||||
 | 
										RTLIL::SigSpec en = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.enable, memwr.enable);
 | 
				
			||||||
 | 
										if (!en.is_fully_zero()) {
 | 
				
			||||||
 | 
											log_error("Async reset %s causes memory write to %s.\n",
 | 
				
			||||||
 | 
													log_signal(sync->signal), log_id(memwr.memid));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.address, memwr.address);
 | 
				
			||||||
 | 
										apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.data, memwr.data);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									sync->mem_write_actions.clear();
 | 
				
			||||||
				eliminate_const(mod, &proc->root_case, root_sig, polarity);
 | 
									eliminate_const(mod, &proc->root_case, root_sig, polarity);
 | 
				
			||||||
				goto restart_proc_arst;
 | 
									goto restart_proc_arst;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool
 | 
				
			||||||
		for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
 | 
							for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
 | 
				
			||||||
			if (proc->syncs[i]->actions[j].first.size() == 0)
 | 
								if (proc->syncs[i]->actions[j].first.size() == 0)
 | 
				
			||||||
				proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
 | 
									proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
 | 
				
			||||||
		if (proc->syncs[i]->actions.size() == 0) {
 | 
							if (proc->syncs[i]->actions.size() == 0 && proc->syncs[i]->mem_write_actions.size() == 0) {
 | 
				
			||||||
			delete proc->syncs[i];
 | 
								delete proc->syncs[i];
 | 
				
			||||||
			proc->syncs.erase(proc->syncs.begin() + (i--));
 | 
								proc->syncs.erase(proc->syncs.begin() + (i--));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -342,7 +342,6 @@ struct proc_dlatch_db_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
					void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::vector<RTLIL::SyncRule*> new_syncs;
 | 
					 | 
				
			||||||
	RTLIL::SigSig latches_bits, nolatches_bits;
 | 
						RTLIL::SigSig latches_bits, nolatches_bits;
 | 
				
			||||||
	dict<SigBit, SigBit> latches_out_in;
 | 
						dict<SigBit, SigBit> latches_out_in;
 | 
				
			||||||
	dict<SigBit, int> latches_hold;
 | 
						dict<SigBit, int> latches_hold;
 | 
				
			||||||
| 
						 | 
					@ -351,7 +350,6 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
				
			||||||
	for (auto sr : proc->syncs)
 | 
						for (auto sr : proc->syncs)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (sr->type != RTLIL::SyncType::STa) {
 | 
							if (sr->type != RTLIL::SyncType::STa) {
 | 
				
			||||||
			new_syncs.push_back(sr);
 | 
					 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -373,8 +371,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
				
			||||||
			for (int i = 0; i < GetSize(ss.first); i++)
 | 
								for (int i = 0; i < GetSize(ss.first); i++)
 | 
				
			||||||
				latches_out_in[ss.first[i]] = ss.second[i];
 | 
									latches_out_in[ss.first[i]] = ss.second[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							sr->actions.clear();
 | 
				
			||||||
		delete sr;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	latches_out_in.sort();
 | 
						latches_out_in.sort();
 | 
				
			||||||
| 
						 | 
					@ -441,8 +438,6 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		offset += width;
 | 
							offset += width;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	new_syncs.swap(proc->syncs);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ProcDlatchPass : public Pass {
 | 
					struct ProcDlatchPass : public Pass {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,17 +71,8 @@ void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
 | 
				
			||||||
					offset += lhs_c.width;
 | 
										offset += lhs_c.width;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								sync->actions.clear();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (found_init) {
 | 
					 | 
				
			||||||
		std::vector<RTLIL::SyncRule*> new_syncs;
 | 
					 | 
				
			||||||
		for (auto &sync : proc->syncs)
 | 
					 | 
				
			||||||
			if (sync->type == RTLIL::SyncType::STi)
 | 
					 | 
				
			||||||
				delete sync;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				new_syncs.push_back(sync);
 | 
					 | 
				
			||||||
		proc->syncs.swap(new_syncs);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ProcInitPass : public Pass {
 | 
					struct ProcInitPass : public Pass {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										111
									
								
								passes/proc/proc_memwr.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								passes/proc/proc_memwr.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2021  Marcelina Kościelnicka <mwk@0x04.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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/sigtools.h"
 | 
				
			||||||
 | 
					#include "kernel/ffinit.h"
 | 
				
			||||||
 | 
					#include "kernel/consteval.h"
 | 
				
			||||||
 | 
					#include "kernel/log.h"
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void proc_memwr(RTLIL::Module *mod, RTLIL::Process *proc, dict<IdString, int> &next_priority)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for (auto sr : proc->syncs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (auto memwr : sr->mem_write_actions) {
 | 
				
			||||||
 | 
								RTLIL::Cell *cell = mod->addCell(NEW_ID, ID($memwr));
 | 
				
			||||||
 | 
								cell->attributes = memwr.attributes;
 | 
				
			||||||
 | 
								cell->setParam(ID::MEMID, Const(memwr.memid.str()));
 | 
				
			||||||
 | 
								cell->setParam(ID::ABITS, GetSize(memwr.address));
 | 
				
			||||||
 | 
								cell->setParam(ID::WIDTH, GetSize(memwr.data));
 | 
				
			||||||
 | 
								cell->setParam(ID::PRIORITY, next_priority[memwr.memid]++);
 | 
				
			||||||
 | 
								cell->setPort(ID::ADDR, memwr.address);
 | 
				
			||||||
 | 
								cell->setPort(ID::DATA, memwr.data);
 | 
				
			||||||
 | 
								SigSpec enable = memwr.enable;
 | 
				
			||||||
 | 
								for (auto sr2 : proc->syncs) {
 | 
				
			||||||
 | 
									if (sr2->type == RTLIL::SyncType::ST0) {
 | 
				
			||||||
 | 
										log_assert(sr2->mem_write_actions.empty());
 | 
				
			||||||
 | 
										enable = mod->Mux(NEW_ID, Const(State::S0, GetSize(enable)), enable, sr2->signal);
 | 
				
			||||||
 | 
									} else if (sr2->type == RTLIL::SyncType::ST1) {
 | 
				
			||||||
 | 
										log_assert(sr2->mem_write_actions.empty());
 | 
				
			||||||
 | 
										enable = mod->Mux(NEW_ID, enable, Const(State::S0, GetSize(enable)), sr2->signal);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								cell->setPort(ID::EN, enable);
 | 
				
			||||||
 | 
								if (sr->type == RTLIL::SyncType::STa) {
 | 
				
			||||||
 | 
									cell->setPort(ID::CLK, State::Sx);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_ENABLE, State::S0);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_POLARITY, State::Sx);
 | 
				
			||||||
 | 
								} else if (sr->type == RTLIL::SyncType::STp) {
 | 
				
			||||||
 | 
									cell->setPort(ID::CLK, sr->signal);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_ENABLE, State::S1);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_POLARITY, State::S1);
 | 
				
			||||||
 | 
								} else if (sr->type == RTLIL::SyncType::STn) {
 | 
				
			||||||
 | 
									cell->setPort(ID::CLK, sr->signal);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_ENABLE, State::S1);
 | 
				
			||||||
 | 
									cell->setParam(ID::CLK_POLARITY, State::S0);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									log_error("process memory write with unsupported sync type in %s.%s", log_id(mod), log_id(proc));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sr->mem_write_actions.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ProcMemWrPass : public Pass {
 | 
				
			||||||
 | 
						ProcMemWrPass() : Pass("proc_memwr", "extract memory writes from processes") { }
 | 
				
			||||||
 | 
						void help() override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    proc_memwr [selection]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("This pass converts memory writes in processes into $memwr cells.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_header(design, "Executing PROC_MEMWR pass (convert process memory writes to cells).\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							extra_args(args, 1, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto module : design->selected_modules()) {
 | 
				
			||||||
 | 
								dict<IdString, int> next_priority;
 | 
				
			||||||
 | 
								for (auto cell : module->cells()) {
 | 
				
			||||||
 | 
									if (cell->type == ID($memwr)) {
 | 
				
			||||||
 | 
										IdString memid = cell->parameters.at(ID::MEMID).decode_string();
 | 
				
			||||||
 | 
										int priority = cell->parameters.at(ID::PRIORITY).as_int();
 | 
				
			||||||
 | 
										if (priority >= next_priority[memid])
 | 
				
			||||||
 | 
											next_priority[memid] = priority + 1;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (auto &proc_it : module->processes)
 | 
				
			||||||
 | 
									if (design->selected(module, proc_it.second))
 | 
				
			||||||
 | 
										proc_memwr(module, proc_it.second, next_priority);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} ProcMemWrPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue