mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +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: | ||||
|   - Fix corner cases with contextual name lookup | ||||
|   - Part select on memory read | ||||
|   - Indexed part selects | ||||
| 
 | ||||
| - 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]; | ||||
| 	} | ||||
| 
 | ||||
| 	// 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
 | ||||
| 	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))); | ||||
| 		wire_addr->str = id_addr; | ||||
| 		wire_addr->is_reg = true; | ||||
| 		if (block) | ||||
| 			wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
| 		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))); | ||||
| 		wire_data->str = id_data; | ||||
| 		wire_data->is_reg = true; | ||||
| 		if (block) | ||||
| 			wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
| 		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()); | ||||
| 			block->children.insert(block->children.begin()+assign_idx, case_node); | ||||
| 			block->children.insert(block->children.begin()+assign_idx, assign_addr); | ||||
| 			wire_addr->is_reg = true; | ||||
| 			wire_data->is_reg = true; | ||||
| 		} | ||||
| 		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_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 <boolean> opt_signed | ||||
| %type <al> attr | ||||
|  | @ -330,7 +330,7 @@ wire_type_token: | |||
| 		astbuf3->is_signed = true; | ||||
| 	}; | ||||
| 
 | ||||
| range: | ||||
| non_opt_range: | ||||
| 	'[' expr ':' expr ']' { | ||||
| 		$$ = new AstNode(AST_RANGE); | ||||
| 		$$->children.push_back($2); | ||||
|  | @ -339,6 +339,11 @@ range: | |||
| 	'[' expr ']' { | ||||
| 		$$ = new AstNode(AST_RANGE); | ||||
| 		$$->children.push_back($2); | ||||
| 	}; | ||||
| 
 | ||||
| range: | ||||
| 	non_opt_range { | ||||
| 		$$ = $1; | ||||
| 	} | | ||||
| 	/* empty */ { | ||||
| 		$$ = NULL; | ||||
|  | @ -893,6 +898,11 @@ rvalue: | |||
| 		$$ = new AstNode(AST_IDENTIFIER, $2); | ||||
| 		$$->str = *$1; | ||||
| 		delete $1; | ||||
| 	} | | ||||
| 	hierarchical_id non_opt_range non_opt_range { | ||||
| 		$$ = new AstNode(AST_IDENTIFIER, $2, $3); | ||||
| 		$$->str = *$1; | ||||
| 		delete $1; | ||||
| 	}; | ||||
| 
 | ||||
| lvalue: | ||||
|  |  | |||
|  | @ -17,3 +17,44 @@ always @(posedge clk) | |||
| 
 | ||||
| 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