mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	fix handling right shifts
This commit is contained in:
		
							parent
							
								
									2d6d6a8da1
								
							
						
					
					
						commit
						6c562c76bc
					
				
					 2 changed files with 53 additions and 12 deletions
				
			
		|  | @ -174,26 +174,67 @@ void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) | ||||||
| 
 | 
 | ||||||
| void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) | void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) | ||||||
| { | { | ||||||
|  | 	bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); | ||||||
| 	int a_width = GetSize(cell->getPort(ID::A)); | 	int a_width = GetSize(cell->getPort(ID::A)); | ||||||
| 	int b_width = GetSize(cell->getPort(ID::B)); | 	int b_width = GetSize(cell->getPort(ID::B)); | ||||||
| 	int y_width = GetSize(cell->getPort(ID::Y)); | 	int y_width = GetSize(cell->getPort(ID::Y)); | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < y_width; i++){ | 	// how far the maximum value of B is able to shift
 | ||||||
| 		for (int k = 0; k < b_width; k++) | 	int b_range = (1<<b_width) - 1; | ||||||
| 			db->add_edge(cell, ID::B, k, ID::Y, i, -1); | 	// highest position of Y that can change with the value of B
 | ||||||
|  | 	int b_range_upper; | ||||||
|  | 	// 1 + highest position of A that can be moved to Y[i]
 | ||||||
|  | 	int a_range_upper; | ||||||
|  | 	// lowest position of A that can be moved to Y[i]
 | ||||||
|  | 	int a_range_lower; | ||||||
| 
 | 
 | ||||||
|  | 	for (int i = 0; i < y_width; i++){ | ||||||
| 		if (cell->type.in(ID($shl), ID($sshl))) { | 		if (cell->type.in(ID($shl), ID($sshl))) { | ||||||
| 			for (int k = min(i, a_width); k >= 0; k--) | 			// << and <<<
 | ||||||
| 				db->add_edge(cell, ID::A, k, ID::Y, i, -1); | 			b_range_upper = a_width + b_range; | ||||||
|  | 			if (is_signed) b_range_upper -= 1; | ||||||
|  | 			a_range_lower = max(0, i - b_range); | ||||||
|  | 			a_range_upper = min(i+1, a_width); | ||||||
|  | 		} else if (cell->type.in(ID($shr), ID($sshr))){ | ||||||
|  | 			// >> and >>>
 | ||||||
|  | 			b_range_upper = a_width; | ||||||
|  | 			a_range_lower = min(i, a_width - 1); // technically the min is unneccessary as b_range_upper check already skips any i >= a_width, but let's leave the logic in since this is hard enough
 | ||||||
|  | 			a_range_upper = min(i+1 + b_range, a_width); | ||||||
|  | 		} else if (cell->type.in(ID($shift), ID($shiftx))) { | ||||||
|  | 			// can go both ways depending on sign of B
 | ||||||
|  | 			// 2's complement range is different depending on direction
 | ||||||
|  | 			int b_range_left = (1<<(b_width - 1)); | ||||||
|  | 			int b_range_right = (1<<(b_width - 1)) - 1; | ||||||
|  | 			b_range_upper = a_width + b_range_left; | ||||||
|  | 			a_range_lower = max(0, i - b_range_left); | ||||||
|  | 			a_range_upper = min(i+1 + b_range_right, a_width); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (cell->type.in(ID($shr), ID($sshr))) | 		if (i < b_range_upper) { | ||||||
| 			for (int k = i; k < a_width; k++) | 			for (int k = a_range_lower; k < a_range_upper; k++) | ||||||
| 				db->add_edge(cell, ID::A, k, ID::Y, i, -1); | 				db->add_edge(cell, ID::A, k, ID::Y, i, -1); | ||||||
|  | 		} else { | ||||||
|  | 			// the only possible influence value is sign extension
 | ||||||
|  | 			if (is_signed) | ||||||
|  | 				db->add_edge(cell, ID::A, a_width - 1, ID::Y, i, -1); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for (int k = 0; k < b_width; k++) { | ||||||
|  | 			if (cell->type.in(ID($shl), ID($sshl)) && a_width == 1 && is_signed) { | ||||||
|  | 				int skip = (1<<(k+1)); | ||||||
|  | 				int base = skip -1; | ||||||
|  | 				if (i % skip != base) | ||||||
|  | 					db->add_edge(cell, ID::B, k, ID::Y, i, -1); | ||||||
|  | 			} else if (cell->type.in(ID($shr), ID($sshr)) && is_signed) { | ||||||
|  | 				int skip = (1<<(k+1)); | ||||||
|  | 				int base = 0; | ||||||
|  | 				if (i % skip != base || i < a_width - 1) | ||||||
|  | 					db->add_edge(cell, ID::B, k, ID::Y, i, -1); | ||||||
|  | 			} else { | ||||||
|  | 				db->add_edge(cell, ID::B, k, ID::Y, i, -1); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if (cell->type.in(ID($shift), ID($shiftx))) |  | ||||||
| 			for (int k = 0; k < a_width; k++) |  | ||||||
| 				db->add_edge(cell, ID::A, k, ID::Y, i, -1); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -543,13 +543,13 @@ struct EvalPass : public Pass { | ||||||
| 
 | 
 | ||||||
| 				int pos = 0; | 				int pos = 0; | ||||||
| 				for (auto &c : tabsigs.chunks()) { | 				for (auto &c : tabsigs.chunks()) { | ||||||
| 					tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width))); | 					tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width), false)); | ||||||
| 					pos += c.width; | 					pos += c.width; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				pos = 0; | 				pos = 0; | ||||||
| 				for (auto &c : signal.chunks()) { | 				for (auto &c : signal.chunks()) { | ||||||
| 					tab_line.push_back(log_signal(value.extract(pos, c.width))); | 					tab_line.push_back(log_signal(value.extract(pos, c.width), false)); | ||||||
| 					pos += c.width; | 					pos += c.width; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue