mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Simplify and correct AST for array slice assignment
Corrects sign extension of the right hand side, and hopefully makes the code simpler to understand. Fixes #4064
This commit is contained in:
		
							parent
							
								
									a921f5968e
								
							
						
					
					
						commit
						23cd23efc5
					
				
					 1 changed files with 41 additions and 70 deletions
				
			
		|  | @ -2966,96 +2966,67 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			// mask and shift operations
 | 			// mask and shift operations
 | ||||||
| 
 | 			// dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb)
 | ||||||
| 			AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(wire_width-1, true), mkconst_int(0, true))); |  | ||||||
| 			wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); |  | ||||||
| 			wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); |  | ||||||
| 			wire_mask->is_logic = true; |  | ||||||
| 			while (wire_mask->simplify(true, 1, -1, false)) { } |  | ||||||
| 			current_ast_mod->children.push_back(wire_mask); |  | ||||||
| 
 |  | ||||||
| 			AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(wire_width-1, true), mkconst_int(0, true))); |  | ||||||
| 			wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); |  | ||||||
| 			wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); |  | ||||||
| 			wire_data->is_logic = true; |  | ||||||
| 			while (wire_data->simplify(true, 1, -1, false)) { } |  | ||||||
| 			current_ast_mod->children.push_back(wire_data); |  | ||||||
| 
 |  | ||||||
| 			int shamt_width_hint = -1; |  | ||||||
| 			bool shamt_sign_hint = true; |  | ||||||
| 			shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint); |  | ||||||
| 
 |  | ||||||
| 			AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); |  | ||||||
| 			wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); |  | ||||||
| 			wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); |  | ||||||
| 			wire_sel->is_logic = true; |  | ||||||
| 			wire_sel->is_signed = shamt_sign_hint; |  | ||||||
| 			while (wire_sel->simplify(true, 1, -1, false)) { } |  | ||||||
| 			current_ast_mod->children.push_back(wire_sel); |  | ||||||
| 
 |  | ||||||
| 			did_something = true; |  | ||||||
| 			newNode = new AstNode(AST_BLOCK); |  | ||||||
| 
 | 
 | ||||||
| 			AstNode *lvalue = children[0]->clone(); | 			AstNode *lvalue = children[0]->clone(); | ||||||
| 			lvalue->delete_children(); | 			lvalue->delete_children(); | ||||||
| 			if (member_node) | 			if (member_node) | ||||||
| 				lvalue->set_attribute(ID::wiretype, member_node->clone()); | 				lvalue->set_attribute(ID::wiretype, member_node->clone()); | ||||||
| 
 | 
 | ||||||
| 			AstNode *ref_mask = new AstNode(AST_IDENTIFIER); |  | ||||||
| 			ref_mask->str = wire_mask->str; |  | ||||||
| 			ref_mask->id2ast = wire_mask; |  | ||||||
| 			ref_mask->was_checked = true; |  | ||||||
| 
 |  | ||||||
| 			AstNode *ref_data = new AstNode(AST_IDENTIFIER); |  | ||||||
| 			ref_data->str = wire_data->str; |  | ||||||
| 			ref_data->id2ast = wire_data; |  | ||||||
| 			ref_data->was_checked = true; |  | ||||||
| 
 |  | ||||||
| 			AstNode *ref_sel = new AstNode(AST_IDENTIFIER); |  | ||||||
| 			ref_sel->str = wire_sel->str; |  | ||||||
| 			ref_sel->id2ast = wire_sel; |  | ||||||
| 			ref_sel->was_checked = true; |  | ||||||
| 
 |  | ||||||
| 			AstNode *old_data = lvalue->clone(); | 			AstNode *old_data = lvalue->clone(); | ||||||
| 			if (type == AST_ASSIGN_LE) | 			if (type == AST_ASSIGN_LE) | ||||||
| 				old_data->lookahead = true; | 				old_data->lookahead = true; | ||||||
| 
 | 
 | ||||||
| 			AstNode *s = new AstNode(AST_ASSIGN_EQ, ref_sel->clone(), shift_expr); | 			int shift_width_hint; | ||||||
| 			newNode->children.push_back(s); | 			bool shift_sign_hint; | ||||||
|  | 			shift_expr->detectSignWidth(shift_width_hint, shift_sign_hint); | ||||||
| 
 | 
 | ||||||
| 			AstNode *shamt = ref_sel; | 			// All operations are carried out in a new block.
 | ||||||
|  | 			newNode = new AstNode(AST_BLOCK); | ||||||
| 
 | 
 | ||||||
| 			// convert to signed while preserving the sign and value
 | 			// Temporary register holding the result of the bit- or part-select position expression.
 | ||||||
| 			shamt = new AstNode(AST_CAST_SIZE, mkconst_int(shamt_width_hint + 1, true), shamt); | 			AstNode *pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); | ||||||
| 			shamt = new AstNode(AST_TO_SIGNED, shamt); | 			newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, pos, shift_expr)); | ||||||
|  | 
 | ||||||
|  | 			// Calculate lsb from position.
 | ||||||
|  | 			AstNode *shift_val = pos->clone(); | ||||||
|  | 
 | ||||||
|  | 			// If the expression is signed, we must add an extra bit for possible negation of the most negative number.
 | ||||||
|  | 			// If the expression is unsigned, we must add an extra bit for sign.
 | ||||||
|  | 			shift_val = new AstNode(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), shift_val); | ||||||
|  | 			if (!shift_sign_hint) | ||||||
|  | 				shift_val = new AstNode(AST_TO_SIGNED, shift_val); | ||||||
| 
 | 
 | ||||||
| 			// offset the shift amount by the lower bound of the dimension
 | 			// offset the shift amount by the lower bound of the dimension
 | ||||||
| 			int start_bit = wire_offset; | 			if (wire_offset != 0) | ||||||
| 			shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); | 				shift_val = new AstNode(AST_SUB, shift_val, mkconst_int(wire_offset, true)); | ||||||
| 
 | 
 | ||||||
| 			// reflect the shift amount if the dimension is swapped
 | 			// reflect the shift amount if the dimension is swapped
 | ||||||
| 			if (children[0]->id2ast->range_swapped) | 			if (children[0]->id2ast->range_swapped) | ||||||
| 				shamt = new AstNode(AST_SUB, mkconst_int(wire_width - result_width, true), shamt); | 				shift_val = new AstNode(AST_SUB, mkconst_int(wire_width - result_width, true), shift_val); | ||||||
| 
 | 
 | ||||||
| 			// AST_SHIFT uses negative amounts for shifting left
 | 			// AST_SHIFT uses negative amounts for shifting left
 | ||||||
| 			shamt = new AstNode(AST_NEG, shamt); | 			shift_val = new AstNode(AST_NEG, shift_val); | ||||||
| 
 | 
 | ||||||
| 			AstNode *t; | 			// dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb)
 | ||||||
| 
 | 			did_something = true; | ||||||
| 			t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); | 			AstNode *bitmask = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); | ||||||
| 			t = new AstNode(AST_SHIFT, t, shamt->clone()); | 			newNode->children.push_back( | ||||||
| 			t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); | 				new AstNode(type, | ||||||
| 			newNode->children.push_back(t); | 					    lvalue, | ||||||
| 
 | 					    new AstNode(AST_BIT_OR, | ||||||
| 			t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()); | 							new AstNode(AST_BIT_AND, | ||||||
| 			t = new AstNode(AST_SHIFT, t, shamt); | 								    old_data, | ||||||
| 			t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); | 								    new AstNode(AST_BIT_NOT, | ||||||
| 			newNode->children.push_back(t); | 										new AstNode(AST_SHIFT, | ||||||
| 
 | 											    bitmask, | ||||||
| 			t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); | 											    shift_val->clone()))), | ||||||
| 			t = new AstNode(AST_BIT_OR, t, ref_data); | 							new AstNode(AST_SHIFT, | ||||||
| 			t = new AstNode(type, lvalue, t); | 								    new AstNode(AST_TO_UNSIGNED, | ||||||
| 			newNode->children.push_back(t); | 										new AstNode(AST_CAST_SIZE, | ||||||
|  | 											    mkconst_int(result_width, true), | ||||||
|  | 											    children[1]->clone())), | ||||||
|  | 								    shift_val)))); | ||||||
| 
 | 
 | ||||||
| 			newNode->fixup_hierarchy_flags(true); | 			newNode->fixup_hierarchy_flags(true); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue