summaryrefslogtreecommitdiff
path: root/rtl/core/core_shifter.sv
blob: 96b88662deaecc9bea74b49b1d5a319100c376d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
`include "core/uarch.sv"

module core_shifter
#(parameter W=16)
(
	input  shifter_control ctrl,
	input  logic[W - 1:0]  base,
	input  logic[7:0]      shift,
	input  logic           c_in,

	output logic[W - 1:0]  q,
	output logic           c
);

	localparam LOG = $clog2(W);

	logic[W - 1:0] q_no_c, q_shl, q_shr, q_ror;
	logic[W:0] sign_mask;
	logic c_shl, c_shr, c_ror;

	assign sign_mask = {(W + 1){ctrl.sign_extend & base[W - 1]}};
	assign {c_shl, q_shl} = {c_in, base} << shift;
	assign {q_shr, c_shr} = {base, c_in} >> shift | (sign_mask & ~(sign_mask >> shift));

	logic ror_cycle;
	logic[LOG - 1:0] ror_shift;
	logic[2 * W:0] ror_out;

	assign ror_shift = shift[LOG - 1:0];
	assign ror_cycle = |shift[7:LOG] & ~|ror_shift;
	assign ror_out = {base, base, c_in} >> {ror_cycle, ror_shift};
	assign {q_ror, c_ror} = ror_out[W:0];

	always_comb
		if(ctrl.ror)
			{c, q} = {c_ror, q_ror};
		else if(ctrl.shr)
			{c, q} = {c_shr, q_shr[W - 1] | (ctrl.put_carry && c_in && shift != 0), q_shr[W - 2:0]};
		else
			{c, q} = {c_shl, q_shl};

endmodule