mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Added support for $readmemh/$readmemb
This commit is contained in:
		
							parent
							
								
									26cbe4a4e5
								
							
						
					
					
						commit
						70b2efdb05
					
				
					 4 changed files with 114 additions and 2 deletions
				
			
		
							
								
								
									
										1
									
								
								README
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								README
									
										
									
									
									
								
							|  | @ -384,7 +384,6 @@ Other Unsorted TODOs | ||||||
| - Implement missing Verilog 2005 features: | - Implement missing Verilog 2005 features: | ||||||
| 
 | 
 | ||||||
|   - Support for real (float) const. expressions and parameters |   - Support for real (float) const. expressions and parameters | ||||||
|   - ROM modeling using $readmemh/$readmemb in "initial" blocks |  | ||||||
|   - Ignore what needs to be ignored (e.g. drive and charge strengths) |   - Ignore what needs to be ignored (e.g. drive and charge strengths) | ||||||
|   - Check standard vs. implementation to identify missing features |   - Check standard vs. implementation to identify missing features | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -204,6 +204,7 @@ namespace AST | ||||||
| 		// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
 | 		// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
 | ||||||
| 		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
 | 		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
 | ||||||
| 		bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); | 		bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); | ||||||
|  | 		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr); | ||||||
| 		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map); | 		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map); | ||||||
| 		void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules); | 		void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules); | ||||||
| 		void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places, | 		void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places, | ||||||
|  |  | ||||||
|  | @ -28,10 +28,12 @@ | ||||||
| 
 | 
 | ||||||
| #include "kernel/log.h" | #include "kernel/log.h" | ||||||
| #include "libs/sha1/sha1.h" | #include "libs/sha1/sha1.h" | ||||||
|  | #include "frontends/verilog/verilog_frontend.h" | ||||||
| #include "ast.h" | #include "ast.h" | ||||||
| 
 | 
 | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
|  | #include <stdlib.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
| 
 | 
 | ||||||
| YOSYS_NAMESPACE_BEGIN | YOSYS_NAMESPACE_BEGIN | ||||||
|  | @ -1480,6 +1482,44 @@ skip_dynamic_range_lvalue_expansion:; | ||||||
| 				log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | 				log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
| 		} | 		} | ||||||
| 		if (type == AST_TCALL) { | 		if (type == AST_TCALL) { | ||||||
|  | 			if (str == "\\$readmemh" || str == "\\$readmemb") | ||||||
|  | 			{ | ||||||
|  | 				if (GetSize(children) < 2 || GetSize(children) > 4) | ||||||
|  | 					log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n", | ||||||
|  | 							RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); | ||||||
|  | 
 | ||||||
|  | 				AstNode *node_filename = children[0]->clone(); | ||||||
|  | 				while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||||
|  | 				if (node_filename->type != AST_CONSTANT) | ||||||
|  | 					log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
|  | 
 | ||||||
|  | 				AstNode *node_memory = children[1]->clone(); | ||||||
|  | 				while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||||
|  | 				if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) | ||||||
|  | 					log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
|  | 
 | ||||||
|  | 				int start_addr = -1, finish_addr = -1; | ||||||
|  | 
 | ||||||
|  | 				if (GetSize(children) > 2) { | ||||||
|  | 					AstNode *node_addr = children[2]->clone(); | ||||||
|  | 					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||||
|  | 					if (node_addr->type != AST_CONSTANT) | ||||||
|  | 						log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
|  | 					start_addr = node_addr->asInt(false); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (GetSize(children) > 3) { | ||||||
|  | 					AstNode *node_addr = children[3]->clone(); | ||||||
|  | 					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||||
|  | 					if (node_addr->type != AST_CONSTANT) | ||||||
|  | 						log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
|  | 					finish_addr = node_addr->asInt(false); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr); | ||||||
|  | 				goto apply_newNode; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) | 			if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) | ||||||
| 				log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | 				log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); | ||||||
| 		} | 		} | ||||||
|  | @ -1988,6 +2028,78 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro | ||||||
| 		node->str = to; | 		node->str = to; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // replace a readmem[bh] TCALL ast node with a block of memory assignments
 | ||||||
|  | AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr) | ||||||
|  | { | ||||||
|  | 	AstNode *block = new AstNode(AST_BLOCK); | ||||||
|  | 
 | ||||||
|  | 	std::ifstream f; | ||||||
|  | 	f.open(mem_filename.c_str()); | ||||||
|  | 
 | ||||||
|  | 	if (f.fail()) | ||||||
|  | 		log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum); | ||||||
|  | 
 | ||||||
|  | 	// log_assert(GetSize(memory->children) == 2 && memory->children[0]->type == AST_RANGE && memory->children[0]->range_valid);
 | ||||||
|  | 	// int wordsize_left =  memory->children[0]->range_left, wordsize_right =  memory->children[0]->range_right;
 | ||||||
|  | 	// int wordsize = std::max(wordsize_left, wordsize_right) - std::min(wordsize_left, wordsize_right) + 1;
 | ||||||
|  | 
 | ||||||
|  | 	bool in_comment = false; | ||||||
|  | 	int increment = (start_addr < finish_addr) || (start_addr < 0) || (finish_addr < 0) ? +1 : -1; | ||||||
|  | 	int cursor = start_addr < 0 ? 0 : start_addr; | ||||||
|  | 
 | ||||||
|  | 	while (!f.eof()) | ||||||
|  | 	{ | ||||||
|  | 		std::string line, token; | ||||||
|  | 		std::getline(f, line); | ||||||
|  | 
 | ||||||
|  | 		for (int i = 0; i < GetSize(line); i++) { | ||||||
|  | 			if (in_comment && line.substr(i, 2) == "*/") { | ||||||
|  | 				line[i] = ' '; | ||||||
|  | 				line[i+1] = ' '; | ||||||
|  | 				in_comment = false; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (!in_comment && line.substr(i, 2) == "/*") | ||||||
|  | 				in_comment = true; | ||||||
|  | 			if (in_comment) | ||||||
|  | 				line[i] = ' '; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		while (1) | ||||||
|  | 		{ | ||||||
|  | 			token = next_token(line, " \t\r\n"); | ||||||
|  | 			if (token.empty() || token.substr(0, 2) == "//") | ||||||
|  | 				break; | ||||||
|  | 
 | ||||||
|  | 			if (token[0] == '@') { | ||||||
|  | 				token = token.substr(1); | ||||||
|  | 				const char *nptr = token.c_str(); | ||||||
|  | 				char *endptr; | ||||||
|  | 				cursor = strtol(nptr, &endptr, 16); | ||||||
|  | 				if (!*nptr || *endptr) | ||||||
|  | 					log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token); | ||||||
|  | 
 | ||||||
|  | 			block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); | ||||||
|  | 			block->children.back()->children[0]->str = memory->str; | ||||||
|  | 			block->children.back()->children[0]->id2ast = memory; | ||||||
|  | 
 | ||||||
|  | 			if (cursor == finish_addr) | ||||||
|  | 				break; | ||||||
|  | 			cursor += increment; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (cursor == finish_addr) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// fixme
 | ||||||
|  | 	return block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // annotate the names of all wires and other named objects in a generate block
 | // annotate the names of all wires and other named objects in a generate block
 | ||||||
| void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) | void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -2935,7 +2935,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri | ||||||
| 		if (netname.size() == 0) | 		if (netname.size() == 0) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if ('0' <= netname[0] && netname[0] <= '9') { | 		if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { | ||||||
| 			cover("kernel.rtlil.sigspec.parse.const"); | 			cover("kernel.rtlil.sigspec.parse.const"); | ||||||
| 			AST::get_line_num = sigspec_parse_get_dummy_line_num; | 			AST::get_line_num = sigspec_parse_get_dummy_line_num; | ||||||
| 			AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); | 			AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue