mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Implemented part/bit select on memory read
This commit is contained in:
		
							parent
							
								
									d248419fe0
								
							
						
					
					
						commit
						19dba2561e
					
				
					 4 changed files with 104 additions and 5 deletions
				
			
		
							
								
								
									
										1
									
								
								README
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								README
									
										
									
									
									
								
							|  | @ -293,7 +293,6 @@ Roadmap / Large-scale TODOs | ||||||
| 
 | 
 | ||||||
| - Missing Verilog-2005 features to be implemented soon: | - Missing Verilog-2005 features to be implemented soon: | ||||||
|   - Fix corner cases with contextual name lookup |   - Fix corner cases with contextual name lookup | ||||||
|   - Part select on memory read |  | ||||||
|   - Indexed part selects |   - Indexed part selects | ||||||
| 
 | 
 | ||||||
| - Technology mapping for real-world applications | - Technology mapping for real-world applications | ||||||
|  |  | ||||||
|  | @ -470,6 +470,55 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 		id2ast = current_scope[str]; | 		id2ast = current_scope[str]; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// split memory access with bit select to individual statements
 | ||||||
|  | 	if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE) | ||||||
|  | 	{ | ||||||
|  | 		if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) | ||||||
|  | 			log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum); | ||||||
|  | 
 | ||||||
|  | 		int mem_width, mem_size, addr_bits; | ||||||
|  | 		id2ast->meminfo(mem_width, mem_size, addr_bits); | ||||||
|  | 
 | ||||||
|  | 		std::stringstream sstr; | ||||||
|  | 		sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); | ||||||
|  | 		std::string wire_id = sstr.str(); | ||||||
|  | 
 | ||||||
|  | 		AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||||
|  | 		wire->str = wire_id; | ||||||
|  | 		if (current_block) | ||||||
|  | 			wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||||
|  | 		current_ast_mod->children.push_back(wire); | ||||||
|  | 		while (wire->simplify(true, false, false, 1, -1, false)) { } | ||||||
|  | 
 | ||||||
|  | 		AstNode *data = clone(); | ||||||
|  | 		delete data->children[1]; | ||||||
|  | 		data->children.pop_back(); | ||||||
|  | 
 | ||||||
|  | 		AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); | ||||||
|  | 		assign->children[0]->str = wire_id; | ||||||
|  | 
 | ||||||
|  | 		if (current_block) | ||||||
|  | 		{ | ||||||
|  | 			size_t assign_idx = 0; | ||||||
|  | 			while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child) | ||||||
|  | 				assign_idx++; | ||||||
|  | 			log_assert(assign_idx < current_block->children.size()); | ||||||
|  | 			current_block->children.insert(current_block->children.begin()+assign_idx, assign); | ||||||
|  | 			wire->is_reg = true; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); | ||||||
|  | 			proc->children[0]->children.push_back(assign); | ||||||
|  | 			current_ast_mod->children.push_back(proc); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		newNode = new AstNode(AST_IDENTIFIER, children[1]->clone()); | ||||||
|  | 		newNode->str = wire_id; | ||||||
|  | 		newNode->id2ast = wire; | ||||||
|  | 		goto apply_newNode; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// unroll for loops and generate-for blocks
 | 	// unroll for loops and generate-for blocks
 | ||||||
| 	if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) | 	if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) | ||||||
| 	{ | 	{ | ||||||
|  | @ -1281,6 +1330,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode * | ||||||
| 
 | 
 | ||||||
| 		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); | 		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); | ||||||
| 		wire_addr->str = id_addr; | 		wire_addr->str = id_addr; | ||||||
|  | 		wire_addr->is_reg = true; | ||||||
| 		if (block) | 		if (block) | ||||||
| 			wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | 			wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||||
| 		mod->children.push_back(wire_addr); | 		mod->children.push_back(wire_addr); | ||||||
|  | @ -1288,6 +1338,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode * | ||||||
| 
 | 
 | ||||||
| 		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | 		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||||
| 		wire_data->str = id_data; | 		wire_data->str = id_data; | ||||||
|  | 		wire_data->is_reg = true; | ||||||
| 		if (block) | 		if (block) | ||||||
| 			wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | 			wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||||
| 		mod->children.push_back(wire_data); | 		mod->children.push_back(wire_data); | ||||||
|  | @ -1328,8 +1379,6 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode * | ||||||
| 			assert(assign_idx < block->children.size()); | 			assert(assign_idx < block->children.size()); | ||||||
| 			block->children.insert(block->children.begin()+assign_idx, case_node); | 			block->children.insert(block->children.begin()+assign_idx, case_node); | ||||||
| 			block->children.insert(block->children.begin()+assign_idx, assign_addr); | 			block->children.insert(block->children.begin()+assign_idx, assign_addr); | ||||||
| 			wire_addr->is_reg = true; |  | ||||||
| 			wire_data->is_reg = true; |  | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
|  | @ -105,7 +105,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) | ||||||
| %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE | %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE | ||||||
| %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED | %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED | ||||||
| 
 | 
 | ||||||
| %type <ast> wire_type range expr basic_expr concat_list rvalue lvalue lvalue_concat_list | %type <ast> wire_type range non_opt_range expr basic_expr concat_list rvalue lvalue lvalue_concat_list | ||||||
| %type <string> opt_label tok_prim_wrapper hierarchical_id | %type <string> opt_label tok_prim_wrapper hierarchical_id | ||||||
| %type <boolean> opt_signed | %type <boolean> opt_signed | ||||||
| %type <al> attr | %type <al> attr | ||||||
|  | @ -330,7 +330,7 @@ wire_type_token: | ||||||
| 		astbuf3->is_signed = true; | 		astbuf3->is_signed = true; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| range: | non_opt_range: | ||||||
| 	'[' expr ':' expr ']' { | 	'[' expr ':' expr ']' { | ||||||
| 		$$ = new AstNode(AST_RANGE); | 		$$ = new AstNode(AST_RANGE); | ||||||
| 		$$->children.push_back($2); | 		$$->children.push_back($2); | ||||||
|  | @ -339,6 +339,11 @@ range: | ||||||
| 	'[' expr ']' { | 	'[' expr ']' { | ||||||
| 		$$ = new AstNode(AST_RANGE); | 		$$ = new AstNode(AST_RANGE); | ||||||
| 		$$->children.push_back($2); | 		$$->children.push_back($2); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | range: | ||||||
|  | 	non_opt_range { | ||||||
|  | 		$$ = $1; | ||||||
| 	} | | 	} | | ||||||
| 	/* empty */ { | 	/* empty */ { | ||||||
| 		$$ = NULL; | 		$$ = NULL; | ||||||
|  | @ -893,6 +898,11 @@ rvalue: | ||||||
| 		$$ = new AstNode(AST_IDENTIFIER, $2); | 		$$ = new AstNode(AST_IDENTIFIER, $2); | ||||||
| 		$$->str = *$1; | 		$$->str = *$1; | ||||||
| 		delete $1; | 		delete $1; | ||||||
|  | 	} | | ||||||
|  | 	hierarchical_id non_opt_range non_opt_range { | ||||||
|  | 		$$ = new AstNode(AST_IDENTIFIER, $2, $3); | ||||||
|  | 		$$->str = *$1; | ||||||
|  | 		delete $1; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| lvalue: | lvalue: | ||||||
|  |  | ||||||
|  | @ -17,3 +17,44 @@ always @(posedge clk) | ||||||
| 
 | 
 | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | // ---------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | module test02(clk, setA, setB, addr, bit, y1, y2, y3, y4); | ||||||
|  | 
 | ||||||
|  | input clk, setA, setB; | ||||||
|  | input [1:0] addr; | ||||||
|  | input [2:0] bit; | ||||||
|  | output reg y1, y2; | ||||||
|  | output y3, y4; | ||||||
|  | 
 | ||||||
|  | reg [7:0] mem1 [3:0]; | ||||||
|  | 
 | ||||||
|  | (* mem2reg *) | ||||||
|  | reg [7:0] mem2 [3:0]; | ||||||
|  | 
 | ||||||
|  | always @(posedge clk) begin | ||||||
|  | 	if (setA) begin | ||||||
|  | 		mem1[0] <= 10; | ||||||
|  | 		mem1[1] <= 20; | ||||||
|  | 		mem1[2] <= 30; | ||||||
|  | 		mem2[0] <= 17; | ||||||
|  | 		mem2[1] <= 27; | ||||||
|  | 		mem2[2] <= 37; | ||||||
|  | 	end | ||||||
|  | 	if (setB) begin | ||||||
|  | 		mem1[0] <=  1; | ||||||
|  | 		mem1[1] <=  2; | ||||||
|  | 		mem1[2] <=  3; | ||||||
|  | 		mem2[0] <= 71; | ||||||
|  | 		mem2[1] <= 72; | ||||||
|  | 		mem2[2] <= 73; | ||||||
|  | 	end | ||||||
|  | 	y1 <= mem1[addr][bit]; | ||||||
|  | 	y2 <= mem2[addr][bit]; | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | assign y3 = mem1[addr][bit]; | ||||||
|  | assign y4 = mem2[addr][bit]; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue