mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	ast: translate $display/$write tasks in always blocks to new $print cell.
This commit is contained in:
		
							parent
							
								
									9f8e039a4b
								
							
						
					
					
						commit
						d5c9953c09
					
				
					 5 changed files with 115 additions and 19 deletions
				
			
		|  | @ -278,6 +278,8 @@ namespace AST | ||||||
| 		bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed); | 		bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed); | ||||||
| 		AstNode *eval_const_function(AstNode *fcall, bool must_succeed); | 		AstNode *eval_const_function(AstNode *fcall, bool must_succeed); | ||||||
| 		bool is_simple_const_expr(); | 		bool is_simple_const_expr(); | ||||||
|  | 
 | ||||||
|  | 		// helper for parsing format strings
 | ||||||
| 		Fmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0); | 		Fmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0); | ||||||
| 
 | 
 | ||||||
| 		bool is_recursive_function() const; | 		bool is_recursive_function() const; | ||||||
|  |  | ||||||
|  | @ -693,8 +693,80 @@ struct AST_INTERNAL::ProcessGenerator | ||||||
| 			ast->input_error("Found parameter declaration in block without label!\n"); | 			ast->input_error("Found parameter declaration in block without label!\n"); | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		case AST_NONE: |  | ||||||
| 		case AST_TCALL: | 		case AST_TCALL: | ||||||
|  | 			if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || | ||||||
|  | 		  ast->str == "$write"   || ast->str == "$writeb"   || ast->str == "$writeh"   || ast->str == "$writeo") { | ||||||
|  | 				std::stringstream sstr; | ||||||
|  | 				sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); | ||||||
|  | 
 | ||||||
|  | 				RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($print)); | ||||||
|  | 				cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, ast->location.first_column, ast->location.last_line, ast->location.last_column); | ||||||
|  | 
 | ||||||
|  | 				RTLIL::SigSpec triggers; | ||||||
|  | 				RTLIL::Const polarity; | ||||||
|  | 				for (auto sync : proc->syncs) { | ||||||
|  | 					if (sync->type == RTLIL::STp) { | ||||||
|  | 						triggers.append(sync->signal); | ||||||
|  | 						polarity.bits.push_back(RTLIL::S1); | ||||||
|  | 					} else if (sync->type == RTLIL::STn) { | ||||||
|  | 						triggers.append(sync->signal); | ||||||
|  | 						polarity.bits.push_back(RTLIL::S0); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				cell->parameters[ID::TRG_WIDTH] = triggers.size(); | ||||||
|  | 				cell->parameters[ID::TRG_ENABLE] = !triggers.empty(); | ||||||
|  | 				cell->parameters[ID::TRG_POLARITY] = polarity; | ||||||
|  | 				cell->setPort(ID::TRG, triggers); | ||||||
|  | 
 | ||||||
|  | 				Wire *wire = current_module->addWire(sstr.str() + "_EN", 1); | ||||||
|  | 				wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, ast->location.first_column, ast->location.last_line, ast->location.last_column); | ||||||
|  | 				cell->setPort(ID::EN, wire); | ||||||
|  | 
 | ||||||
|  | 				proc->root_case.actions.push_back(SigSig(wire, false)); | ||||||
|  | 				current_case->actions.push_back(SigSig(wire, true)); | ||||||
|  | 
 | ||||||
|  | 				int default_base = 10; | ||||||
|  | 				if (ast->str.back() == 'b') | ||||||
|  | 					default_base = 2; | ||||||
|  | 				else if (ast->str.back() == 'o') | ||||||
|  | 					default_base = 8; | ||||||
|  | 				else if (ast->str.back() == 'h') | ||||||
|  | 					default_base = 16; | ||||||
|  | 
 | ||||||
|  | 				std::vector<VerilogFmtArg> args; | ||||||
|  | 				for (auto node : ast->children) { | ||||||
|  | 					int width; | ||||||
|  | 					bool is_signed; | ||||||
|  | 					node->detectSignWidth(width, is_signed, nullptr); | ||||||
|  | 
 | ||||||
|  | 					VerilogFmtArg arg = {}; | ||||||
|  | 					arg.filename = node->filename; | ||||||
|  | 					arg.first_line = node->location.first_line; | ||||||
|  | 					if (node->type == AST_CONSTANT && node->is_string) { | ||||||
|  | 						arg.type = VerilogFmtArg::STRING; | ||||||
|  | 						arg.str = node->bitsAsConst().decode_string(); | ||||||
|  | 						// and in case this will be used as an argument...
 | ||||||
|  | 						arg.sig = node->bitsAsConst(); | ||||||
|  | 						arg.signed_ = false; | ||||||
|  | 					} else { | ||||||
|  | 						arg.type = VerilogFmtArg::INTEGER; | ||||||
|  | 						arg.sig = node->genRTLIL(); | ||||||
|  | 						arg.signed_ = is_signed; | ||||||
|  | 					} | ||||||
|  | 					args.push_back(arg); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				Fmt fmt = {}; | ||||||
|  | 				fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name); | ||||||
|  | 				if (ast->str.substr(0, 8) == "$display") | ||||||
|  | 					fmt.append_string("\n"); | ||||||
|  | 				fmt.emit_rtlil(cell); | ||||||
|  | 			} else if (!ast->str.empty()) { | ||||||
|  | 				log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		case AST_NONE: | ||||||
| 		case AST_FOR: | 		case AST_FOR: | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -951,29 +951,33 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin | ||||||
| 		str = std::string(); | 		str = std::string(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ((type == AST_TCALL) && (str.substr(0, 8) == "$display" || str.substr(0, 6) == "$write") && (!current_always || current_always->type != AST_INITIAL)) { |  | ||||||
| 		log_file_warning(filename, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str()); |  | ||||||
| 		delete_children(); |  | ||||||
| 		str = std::string(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// print messages if this a call to $display() or $write() family of functions
 |  | ||||||
| 	if ((type == AST_TCALL) && | 	if ((type == AST_TCALL) && | ||||||
| 	    (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || | 	    (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || | ||||||
| 	     str == "$write"   || str == "$writeb"   || str == "$writeh"   || str == "$writeo")) | 	     str == "$write"   || str == "$writeb"   || str == "$writeh"   || str == "$writeo")) | ||||||
| 	{ | 	{ | ||||||
| 		int default_base = 10; | 		if (!current_always) { | ||||||
| 		if (str.back() == 'b') | 			log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); | ||||||
| 			default_base = 2; | 		} else if (current_always->type == AST_INITIAL) { | ||||||
| 		else if (str.back() == 'o') | 			int default_base = 10; | ||||||
| 			default_base = 8; | 			if (str.back() == 'b') | ||||||
| 		else if (str.back() == 'h') | 				default_base = 2; | ||||||
| 			default_base = 16; | 			else if (str.back() == 'o') | ||||||
|  | 				default_base = 8; | ||||||
|  | 			else if (str.back() == 'h') | ||||||
|  | 				default_base = 16; | ||||||
| 
 | 
 | ||||||
| 		Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base); | 			// when $display()/$write() functions are used in an initial block, print them during synthesis
 | ||||||
| 		if (str.substr(0, 8) == "$display") | 			Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base); | ||||||
| 			fmt.append_string("\n"); | 			if (str.substr(0, 8) == "$display") | ||||||
| 		log("%s", fmt.render().c_str()); | 				fmt.append_string("\n"); | ||||||
|  | 			log("%s", fmt.render().c_str()); | ||||||
|  | 		} else { | ||||||
|  | 			// when $display()/$write() functions are used in an always block, simplify the expressions and
 | ||||||
|  | 			// convert them to a special cell later in genrtlil
 | ||||||
|  | 			for (auto node : children) | ||||||
|  | 				while (node->simplify(true, false, stage, -1, false, false)) {} | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		delete_children(); | 		delete_children(); | ||||||
| 		str = std::string(); | 		str = std::string(); | ||||||
|  |  | ||||||
|  | @ -22,6 +22,8 @@ X(always_ff) | ||||||
| X(always_latch) | X(always_latch) | ||||||
| X(anyconst) | X(anyconst) | ||||||
| X(anyseq) | X(anyseq) | ||||||
|  | X(ARGS) | ||||||
|  | X(ARGS_WIDTH) | ||||||
| X(ARST) | X(ARST) | ||||||
| X(ARST_POLARITY) | X(ARST_POLARITY) | ||||||
| X(ARST_VALUE) | X(ARST_VALUE) | ||||||
|  | @ -86,6 +88,7 @@ X(equiv_merged) | ||||||
| X(equiv_region) | X(equiv_region) | ||||||
| X(extract_order) | X(extract_order) | ||||||
| X(F) | X(F) | ||||||
|  | X(FORMAT) | ||||||
| X(force_downto) | X(force_downto) | ||||||
| X(force_upto) | X(force_upto) | ||||||
| X(fsm_encoding) | X(fsm_encoding) | ||||||
|  | @ -233,6 +236,10 @@ X(TRANS_NUM) | ||||||
| X(TRANSPARENCY_MASK) | X(TRANSPARENCY_MASK) | ||||||
| X(TRANSPARENT) | X(TRANSPARENT) | ||||||
| X(TRANS_TABLE) | X(TRANS_TABLE) | ||||||
|  | X(TRG) | ||||||
|  | X(TRG_ENABLE) | ||||||
|  | X(TRG_POLARITY) | ||||||
|  | X(TRG_WIDTH) | ||||||
| X(T_RISE_MAX) | X(T_RISE_MAX) | ||||||
| X(T_RISE_MIN) | X(T_RISE_MIN) | ||||||
| X(T_RISE_TYP) | X(T_RISE_TYP) | ||||||
|  |  | ||||||
|  | @ -1720,6 +1720,17 @@ namespace { | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if (cell->type == ID($print)) { | ||||||
|  | 				param(ID(FORMAT)); | ||||||
|  | 				param_bool(ID::TRG_ENABLE); | ||||||
|  | 				param(ID::TRG_POLARITY); | ||||||
|  | 				port(ID::EN, 1); | ||||||
|  | 				port(ID::TRG, param(ID::TRG_WIDTH)); | ||||||
|  | 				port(ID::ARGS, param(ID::ARGS_WIDTH)); | ||||||
|  | 				check_expected(); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			if (cell->type == ID($_BUF_))    { port(ID::A,1); port(ID::Y,1); check_expected(); return; } | 			if (cell->type == ID($_BUF_))    { port(ID::A,1); port(ID::Y,1); check_expected(); return; } | ||||||
| 			if (cell->type == ID($_NOT_))    { port(ID::A,1); port(ID::Y,1); check_expected(); return; } | 			if (cell->type == ID($_NOT_))    { port(ID::A,1); port(ID::Y,1); check_expected(); return; } | ||||||
| 			if (cell->type == ID($_AND_))    { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } | 			if (cell->type == ID($_AND_))    { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue