mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge pull request #2005 from YosysHQ/claire/fix1990
Add "nowrshmsk" attribute, fix shift-and-mask bit slice write for signed offset
This commit is contained in:
		
						commit
						0610424940
					
				
					 9 changed files with 142 additions and 19 deletions
				
			
		|  | @ -281,6 +281,9 @@ Verilog Attributes and non-standard features | ||||||
|   temporary variable within an always block. This is mostly used internally |   temporary variable within an always block. This is mostly used internally | ||||||
|   by Yosys to synthesize Verilog functions and access arrays. |   by Yosys to synthesize Verilog functions and access arrays. | ||||||
| 
 | 
 | ||||||
|  | - The ``nowrshmsk`` attribute on a register prohibits the generation of | ||||||
|  |   shift-and-mask type circuits for writing to bit slices of that register. | ||||||
|  | 
 | ||||||
| - The ``onehot`` attribute on wires mark them as one-hot state register. This | - The ``onehot`` attribute on wires mark them as one-hot state register. This | ||||||
|   is used for example for memory port sharing and set by the fsm_map pass. |   is used for example for memory port sharing and set by the fsm_map pass. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -94,6 +94,7 @@ std::string AST::type2str(AstNodeType type) | ||||||
| 	X(AST_TO_BITS) | 	X(AST_TO_BITS) | ||||||
| 	X(AST_TO_SIGNED) | 	X(AST_TO_SIGNED) | ||||||
| 	X(AST_TO_UNSIGNED) | 	X(AST_TO_UNSIGNED) | ||||||
|  | 	X(AST_SELFSZ) | ||||||
| 	X(AST_CONCAT) | 	X(AST_CONCAT) | ||||||
| 	X(AST_REPLICATE) | 	X(AST_REPLICATE) | ||||||
| 	X(AST_BIT_NOT) | 	X(AST_BIT_NOT) | ||||||
|  | @ -110,6 +111,8 @@ std::string AST::type2str(AstNodeType type) | ||||||
| 	X(AST_SHIFT_RIGHT) | 	X(AST_SHIFT_RIGHT) | ||||||
| 	X(AST_SHIFT_SLEFT) | 	X(AST_SHIFT_SLEFT) | ||||||
| 	X(AST_SHIFT_SRIGHT) | 	X(AST_SHIFT_SRIGHT) | ||||||
|  | 	X(AST_SHIFTX) | ||||||
|  | 	X(AST_SHIFT) | ||||||
| 	X(AST_LT) | 	X(AST_LT) | ||||||
| 	X(AST_LE) | 	X(AST_LE) | ||||||
| 	X(AST_EQ) | 	X(AST_EQ) | ||||||
|  | @ -615,6 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const | ||||||
| 	if (0) { case AST_POS:         txt = "+";  } | 	if (0) { case AST_POS:         txt = "+";  } | ||||||
| 	if (0) { case AST_NEG:         txt = "-";  } | 	if (0) { case AST_NEG:         txt = "-";  } | ||||||
| 	if (0) { case AST_LOGIC_NOT:   txt = "!";  } | 	if (0) { case AST_LOGIC_NOT:   txt = "!";  } | ||||||
|  | 	if (0) { case AST_SELFSZ:      txt = "@selfsz@";  } | ||||||
| 		fprintf(f, "%s(", txt.c_str()); | 		fprintf(f, "%s(", txt.c_str()); | ||||||
| 		children[0]->dumpVlog(f, ""); | 		children[0]->dumpVlog(f, ""); | ||||||
| 		fprintf(f, ")"); | 		fprintf(f, ")"); | ||||||
|  | @ -628,6 +632,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const | ||||||
| 	if (0) { case AST_SHIFT_RIGHT:  txt = ">>";  } | 	if (0) { case AST_SHIFT_RIGHT:  txt = ">>";  } | ||||||
| 	if (0) { case AST_SHIFT_SLEFT:  txt = "<<<"; } | 	if (0) { case AST_SHIFT_SLEFT:  txt = "<<<"; } | ||||||
| 	if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } | 	if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } | ||||||
|  | 	if (0) { case AST_SHIFTX:       txt = "@shiftx@"; } | ||||||
|  | 	if (0) { case AST_SHIFT:        txt = "@shift@"; } | ||||||
| 	if (0) { case AST_LT:           txt = "<";   } | 	if (0) { case AST_LT:           txt = "<";   } | ||||||
| 	if (0) { case AST_LE:           txt = "<=";  } | 	if (0) { case AST_LE:           txt = "<=";  } | ||||||
| 	if (0) { case AST_EQ:           txt = "==";  } | 	if (0) { case AST_EQ:           txt = "==";  } | ||||||
|  |  | ||||||
|  | @ -75,6 +75,7 @@ namespace AST | ||||||
| 		AST_TO_BITS, | 		AST_TO_BITS, | ||||||
| 		AST_TO_SIGNED, | 		AST_TO_SIGNED, | ||||||
| 		AST_TO_UNSIGNED, | 		AST_TO_UNSIGNED, | ||||||
|  | 		AST_SELFSZ, | ||||||
| 		AST_CONCAT, | 		AST_CONCAT, | ||||||
| 		AST_REPLICATE, | 		AST_REPLICATE, | ||||||
| 		AST_BIT_NOT, | 		AST_BIT_NOT, | ||||||
|  | @ -91,6 +92,8 @@ namespace AST | ||||||
| 		AST_SHIFT_RIGHT, | 		AST_SHIFT_RIGHT, | ||||||
| 		AST_SHIFT_SLEFT, | 		AST_SHIFT_SLEFT, | ||||||
| 		AST_SHIFT_SRIGHT, | 		AST_SHIFT_SRIGHT, | ||||||
|  | 		AST_SHIFTX, | ||||||
|  | 		AST_SHIFT, | ||||||
| 		AST_LT, | 		AST_LT, | ||||||
| 		AST_LE, | 		AST_LE, | ||||||
| 		AST_EQ, | 		AST_EQ, | ||||||
|  |  | ||||||
|  | @ -809,6 +809,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun | ||||||
| 		sign_hint = false; | 		sign_hint = false; | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | 	case AST_SELFSZ: | ||||||
|  | 		sub_width_hint = 0; | ||||||
|  | 		children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
| 	case AST_CONCAT: | 	case AST_CONCAT: | ||||||
| 		for (auto child : children) { | 		for (auto child : children) { | ||||||
| 			sub_width_hint = 0; | 			sub_width_hint = 0; | ||||||
|  | @ -856,6 +861,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun | ||||||
| 	case AST_SHIFT_RIGHT: | 	case AST_SHIFT_RIGHT: | ||||||
| 	case AST_SHIFT_SLEFT: | 	case AST_SHIFT_SLEFT: | ||||||
| 	case AST_SHIFT_SRIGHT: | 	case AST_SHIFT_SRIGHT: | ||||||
|  | 	case AST_SHIFTX: | ||||||
|  | 	case AST_SHIFT: | ||||||
| 	case AST_POW: | 	case AST_POW: | ||||||
| 		children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); | 		children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); | ||||||
| 		break; | 		break; | ||||||
|  | @ -1205,13 +1212,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | ||||||
| 					AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? | 					AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? | ||||||
| 							children[0]->children[1]->clone() : children[0]->children[0]->clone()); | 							children[0]->children[1]->clone() : children[0]->children[0]->clone()); | ||||||
| 					fake_ast->children[0]->delete_children(); | 					fake_ast->children[0]->delete_children(); | ||||||
| 					RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(); | 
 | ||||||
|  | 					int fake_ast_width = 0; | ||||||
|  | 					bool fake_ast_sign = true; | ||||||
|  | 					fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign); | ||||||
|  | 					RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign); | ||||||
|  | 
 | ||||||
| 					if (id2ast->range_right != 0) { | 					if (id2ast->range_right != 0) { | ||||||
| 						shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed); | 						shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast_sign); | ||||||
| 						fake_ast->children[1]->is_signed = true; | 						fake_ast->children[1]->is_signed = true; | ||||||
| 					} | 					} | ||||||
| 					if (id2ast->range_swapped) { | 					if (id2ast->range_swapped) { | ||||||
| 						shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed); | 						shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast_sign); | ||||||
| 						fake_ast->children[1]->is_signed = true; | 						fake_ast->children[1]->is_signed = true; | ||||||
| 					} | 					} | ||||||
| 					if (GetSize(shift_val) >= 32) | 					if (GetSize(shift_val) >= 32) | ||||||
|  | @ -1265,7 +1277,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | ||||||
| 
 | 
 | ||||||
| 	// just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly
 | 	// just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly
 | ||||||
| 	case AST_TO_SIGNED: | 	case AST_TO_SIGNED: | ||||||
| 	case AST_TO_UNSIGNED: { | 	case AST_TO_UNSIGNED: | ||||||
|  | 	case AST_SELFSZ: { | ||||||
| 			RTLIL::SigSpec sig = children[0]->genRTLIL(); | 			RTLIL::SigSpec sig = children[0]->genRTLIL(); | ||||||
| 			if (sig.size() < width_hint) | 			if (sig.size() < width_hint) | ||||||
| 				sig.extend_u0(width_hint, sign_hint); | 				sig.extend_u0(width_hint, sign_hint); | ||||||
|  | @ -1356,6 +1369,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | ||||||
| 	if (0) { case AST_SHIFT_RIGHT:  type_name = ID($shr); } | 	if (0) { case AST_SHIFT_RIGHT:  type_name = ID($shr); } | ||||||
| 	if (0) { case AST_SHIFT_SLEFT:  type_name = ID($sshl); } | 	if (0) { case AST_SHIFT_SLEFT:  type_name = ID($sshl); } | ||||||
| 	if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } | 	if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } | ||||||
|  | 	if (0) { case AST_SHIFTX:       type_name = ID($shiftx); } | ||||||
|  | 	if (0) { case AST_SHIFT:        type_name = ID($shift); } | ||||||
| 		{ | 		{ | ||||||
| 			if (width_hint < 0) | 			if (width_hint < 0) | ||||||
| 				detectSignWidth(width_hint, sign_hint); | 				detectSignWidth(width_hint, sign_hint); | ||||||
|  |  | ||||||
|  | @ -608,6 +608,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 	case AST_TO_BITS: | 	case AST_TO_BITS: | ||||||
| 	case AST_TO_SIGNED: | 	case AST_TO_SIGNED: | ||||||
| 	case AST_TO_UNSIGNED: | 	case AST_TO_UNSIGNED: | ||||||
|  | 	case AST_SELFSZ: | ||||||
| 	case AST_CONCAT: | 	case AST_CONCAT: | ||||||
| 	case AST_REPLICATE: | 	case AST_REPLICATE: | ||||||
| 	case AST_REDUCE_AND: | 	case AST_REDUCE_AND: | ||||||
|  | @ -1788,7 +1789,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 			result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; | 			result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (0) | 		bool use_case_method = false; | ||||||
|  | 
 | ||||||
|  | 		if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { | ||||||
|  | 			AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); | ||||||
|  | 			while (node->simplify(true, false, false, stage, -1, false, false)) { } | ||||||
|  | 			if (node->type != AST_CONSTANT) | ||||||
|  | 				log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); | ||||||
|  | 			if (node->asAttrConst().as_bool()) | ||||||
|  | 				use_case_method = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (use_case_method) | ||||||
| 		{ | 		{ | ||||||
| 			// big case block
 | 			// big case block
 | ||||||
| 
 | 
 | ||||||
|  | @ -1796,10 +1808,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 			newNode = new AstNode(AST_CASE, shift_expr); | 			newNode = new AstNode(AST_CASE, shift_expr); | ||||||
| 			for (int i = 0; i < source_width; i++) { | 			for (int i = 0; i < source_width; i++) { | ||||||
| 				int start_bit = children[0]->id2ast->range_right + i; | 				int start_bit = children[0]->id2ast->range_right + i; | ||||||
|  | 				int end_bit = std::min(start_bit+result_width,source_width) - 1; | ||||||
| 				AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); | 				AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); | ||||||
| 				AstNode *lvalue = children[0]->clone(); | 				AstNode *lvalue = children[0]->clone(); | ||||||
| 				lvalue->delete_children(); | 				lvalue->delete_children(); | ||||||
| 				int end_bit = std::min(start_bit+result_width,source_width) - 1; |  | ||||||
| 				lvalue->children.push_back(new AstNode(AST_RANGE, | 				lvalue->children.push_back(new AstNode(AST_RANGE, | ||||||
| 						mkconst_int(end_bit, true), mkconst_int(start_bit, true))); | 						mkconst_int(end_bit, true), mkconst_int(start_bit, true))); | ||||||
| 				cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); | 				cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); | ||||||
|  | @ -1846,11 +1858,40 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 
 | 
 | ||||||
| 			AstNode *shamt = shift_expr; | 			AstNode *shamt = shift_expr; | ||||||
| 
 | 
 | ||||||
| 			newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), | 			int shamt_width_hint = 0; | ||||||
| 					new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); | 			bool shamt_sign_hint = true; | ||||||
| 			newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), | 			shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint); | ||||||
| 					new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); | 
 | ||||||
| 			newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); | 			int start_bit = children[0]->id2ast->range_right; | ||||||
|  | 			bool use_shift = shamt_sign_hint; | ||||||
|  | 
 | ||||||
|  | 			if (start_bit != 0) { | ||||||
|  | 				shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); | ||||||
|  | 				use_shift = true; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			AstNode *t; | ||||||
|  | 
 | ||||||
|  | 			t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); | ||||||
|  | 			if (use_shift) | ||||||
|  | 				t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone())); | ||||||
|  | 			else | ||||||
|  | 				t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone()); | ||||||
|  | 			t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); | ||||||
|  | 			newNode->children.push_back(t); | ||||||
|  | 
 | ||||||
|  | 			t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()); | ||||||
|  | 			if (use_shift) | ||||||
|  | 				t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt)); | ||||||
|  | 			else | ||||||
|  | 				t = new AstNode(AST_SHIFT_LEFT, t, shamt); | ||||||
|  | 			t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); | ||||||
|  | 			newNode->children.push_back(t); | ||||||
|  | 
 | ||||||
|  | 			t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); | ||||||
|  | 			t = new AstNode(AST_BIT_OR, t, ref_data); | ||||||
|  | 			t = new AstNode(type, lvalue, t); | ||||||
|  | 			newNode->children.push_back(t); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		goto apply_newNode; | 		goto apply_newNode; | ||||||
|  | @ -3026,6 +3067,7 @@ replace_fcall_later:; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
|  | 		if (0) { case AST_SELFSZ: const_func = RTLIL::const_pos; } | ||||||
| 		if (0) { case AST_POS: const_func = RTLIL::const_pos; } | 		if (0) { case AST_POS: const_func = RTLIL::const_pos; } | ||||||
| 		if (0) { case AST_NEG: const_func = RTLIL::const_neg; } | 		if (0) { case AST_NEG: const_func = RTLIL::const_neg; } | ||||||
| 			if (children[0]->type == AST_CONSTANT) { | 			if (children[0]->type == AST_CONSTANT) { | ||||||
|  | @ -3034,10 +3076,10 @@ replace_fcall_later:; | ||||||
| 			} else | 			} else | ||||||
| 			if (children[0]->isConst()) { | 			if (children[0]->isConst()) { | ||||||
| 				newNode = new AstNode(AST_REALVALUE); | 				newNode = new AstNode(AST_REALVALUE); | ||||||
| 				if (type == AST_POS) | 				if (type == AST_NEG) | ||||||
| 					newNode->realvalue = +children[0]->asReal(sign_hint); |  | ||||||
| 				else |  | ||||||
| 					newNode->realvalue = -children[0]->asReal(sign_hint); | 					newNode->realvalue = -children[0]->asReal(sign_hint); | ||||||
|  | 				else | ||||||
|  | 					newNode->realvalue = +children[0]->asReal(sign_hint); | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case AST_TERNARY: | 		case AST_TERNARY: | ||||||
|  |  | ||||||
|  | @ -645,13 +645,13 @@ non_opt_range: | ||||||
| 	} | | 	} | | ||||||
| 	'[' expr TOK_POS_INDEXED expr ']' { | 	'[' expr TOK_POS_INDEXED expr ']' { | ||||||
| 		$$ = new AstNode(AST_RANGE); | 		$$ = new AstNode(AST_RANGE); | ||||||
| 		AstNode *expr = new AstNode(AST_CONCAT, $2); | 		AstNode *expr = new AstNode(AST_SELFSZ, $2); | ||||||
| 		$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); | 		$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); | ||||||
| 		$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); | 		$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); | ||||||
| 	} | | 	} | | ||||||
| 	'[' expr TOK_NEG_INDEXED expr ']' { | 	'[' expr TOK_NEG_INDEXED expr ']' { | ||||||
| 		$$ = new AstNode(AST_RANGE); | 		$$ = new AstNode(AST_RANGE); | ||||||
| 		AstNode *expr = new AstNode(AST_CONCAT, $2); | 		AstNode *expr = new AstNode(AST_SELFSZ, $2); | ||||||
| 		$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); | 		$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); | ||||||
| 		$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); | 		$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); | ||||||
| 	} | | 	} | | ||||||
|  |  | ||||||
|  | @ -125,6 +125,7 @@ X(nomem2init) | ||||||
| X(nomem2reg) | X(nomem2reg) | ||||||
| X(nomeminit) | X(nomeminit) | ||||||
| X(nosync) | X(nosync) | ||||||
|  | X(nowrshmsk) | ||||||
| X(O) | X(O) | ||||||
| X(OFFSET) | X(OFFSET) | ||||||
| X(onehot) | X(onehot) | ||||||
|  |  | ||||||
|  | @ -81,6 +81,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s | ||||||
| 
 | 
 | ||||||
| 	f << stringf("integer i;\n"); | 	f << stringf("integer i;\n"); | ||||||
| 	f << stringf("integer file;\n\n"); | 	f << stringf("integer file;\n\n"); | ||||||
|  | 	f << stringf("reg [1023:0] filename;\n\n"); | ||||||
| 
 | 
 | ||||||
| 	f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); | 	f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); | ||||||
| 	f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); | 	f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); | ||||||
|  | @ -305,9 +306,15 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	f << stringf("initial begin\n"); | 	f << stringf("initial begin\n"); | ||||||
| 	f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); | 	f << stringf("\tif ($value$plusargs(\"VCD=%%s\", filename)) begin\n"); | ||||||
| 	f << stringf("\t// $dumpvars(0, testbench);\n"); | 	f << stringf("\t\t$dumpfile(filename);\n"); | ||||||
| 	f << stringf("\tfile = $fopen(`outfile);\n"); | 	f << stringf("\t\t$dumpvars(0, testbench);\n"); | ||||||
|  | 	f << stringf("\tend\n"); | ||||||
|  | 	f << stringf("\tif ($value$plusargs(\"OUT=%%s\", filename)) begin\n"); | ||||||
|  | 	f << stringf("\t\tfile = $fopen(filename);\n"); | ||||||
|  | 	f << stringf("\tend else begin\n"); | ||||||
|  | 	f << stringf("\t\tfile = $fopen(`outfile);\n"); | ||||||
|  | 	f << stringf("\tend\n"); | ||||||
| 	for (auto module : design->modules()) | 	for (auto module : design->modules()) | ||||||
| 		if (!module->get_bool_attribute(ID::gentb_skip)) | 		if (!module->get_bool_attribute(ID::gentb_skip)) | ||||||
| 			f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str()); | 			f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str()); | ||||||
|  |  | ||||||
|  | @ -64,3 +64,49 @@ endmodule | ||||||
| module partsel_test003(input [2:0] a, b, input [31:0] din, output [3:0] dout); | module partsel_test003(input [2:0] a, b, input [31:0] din, output [3:0] dout); | ||||||
| assign dout = din[a*b +: 2]; | assign dout = din[a*b +: 2]; | ||||||
| endmodule | endmodule | ||||||
|  | 
 | ||||||
|  | module partsel_test004 ( | ||||||
|  | 	input [31:0] din, | ||||||
|  | 	input signed [4:0] n, | ||||||
|  | 	output reg [31:0] dout | ||||||
|  | ); | ||||||
|  | 	always @(*) begin | ||||||
|  | 		dout = 0; | ||||||
|  | 		dout[n+1 +: 2] = din[n +: 2]; | ||||||
|  | 	end | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | module partsel_test005 ( | ||||||
|  | 	input [31:0] din, | ||||||
|  | 	input signed [4:0] n, | ||||||
|  | 	output reg [31:0] dout | ||||||
|  | ); | ||||||
|  | 	always @(*) begin | ||||||
|  | 		dout = 0; | ||||||
|  | 		dout[n+1] = din[n]; | ||||||
|  | 	end | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module partsel_test006 ( | ||||||
|  | 	input [31:-32] din, | ||||||
|  | 	input signed [4:0] n, | ||||||
|  | 	output reg [31:-32] dout | ||||||
|  | ); | ||||||
|  | 	always @(*) begin | ||||||
|  | 		dout = 0; | ||||||
|  | 		dout[n+1 +: 2] = din[n +: 2]; | ||||||
|  | 	end | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | module partsel_test007 ( | ||||||
|  | 	input [31:-32] din, | ||||||
|  | 	input signed [4:0] n, | ||||||
|  | 	output reg [31:-32] dout | ||||||
|  | ); | ||||||
|  | 	always @(*) begin | ||||||
|  | 		dout = 0; | ||||||
|  | 		dout[n+1] = din[n]; | ||||||
|  | 	end | ||||||
|  | endmodule | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue