summaryrefslogtreecommitdiff
path: root/rtl/core/decode/data.sv
blob: 89b9967d38ae1133791b55da1082b90621d29281 (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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
`include "core/isa.sv"
`include "core/uarch.sv"

module core_decode_data
(
	input  word       insn,

	output alu_decode decode,
	output logic      writeback,
	                  update_flags,
	                  restore_spsr,
	                  undefined
);

	alu_op op;
	reg_num rn, rd, r_snd, r_shift;
	logic snd_shift_by_reg, snd_is_imm, shl, shr, ror, put_carry, sign_extend;
	logic[7:0] imm;
	logic[5:0] shift_imm;

	assign decode.op = op;
	assign decode.rn = rn;
	assign decode.rd = rd;
	assign decode.r_snd = r_snd;
	assign decode.r_shift = r_shift;
	assign decode.snd_shift_by_reg = snd_shift_by_reg;
	assign decode.snd_is_imm = snd_is_imm;
	assign decode.shl = shl;
	assign decode.shr = shr;
	assign decode.ror = ror;
	assign decode.put_carry = put_carry;
	assign decode.sign_extend = sign_extend;

	assign rn = insn `FIELD_DATA_RN;
	assign rd = insn `FIELD_DATA_RD;
	assign op = insn `FIELD_DATA_OPCODE;
	assign r_snd = insn `FIELD_DATA_RM;
	assign r_shift = insn `FIELD_DATA_RS;
	assign imm = insn `FIELD_DATA_IMM8;
	assign snd_is_imm = insn `FIELD_DATA_IMM;
	assign snd_shift_by_reg = ~snd_is_imm & insn `FIELD_DATA_REGSHIFT;
	assign undefined = snd_shift_by_reg & insn `FIELD_DATA_ZEROIFREG;

	logic[1:0] shift_op;
	assign shift_op = insn `FIELD_DATA_SHIFT;

	always_comb begin
		unique case(op)
			`ALU_CMP, `ALU_CMN, `ALU_TST, `ALU_TEQ:
				writeback = 0;

			default:
				writeback = 1;
		endcase

		update_flags = insn `FIELD_DATA_S;
		restore_spsr = (rd == `R15) & update_flags;

		if(restore_spsr)
			update_flags = 0;

		ror = snd_is_imm;
		shr = ~snd_is_imm;
		put_carry = 0;
		sign_extend = 1'bx;

		if(snd_is_imm)
			shift_imm = {1'b0, insn `FIELD_DATA_ROR8, 1'b0};
		else begin
			shift_imm = {1'b0, insn `FIELD_DATA_SHIFTIMM};

			case(shift_op)
				`SHIFT_LSL: shr = 0;
				`SHIFT_LSR: sign_extend = 0;
				`SHIFT_ASR: sign_extend = 1;
				`SHIFT_ROR: ;
			endcase

			if(~snd_shift_by_reg & (shift_imm == 0))
				case(shift_op)
					`SHIFT_LSL: ;

					`SHIFT_LSR, `SHIFT_ASR:
						shift_imm = 6'd32;

					`SHIFT_ROR: begin
						// RRX
						shift_imm = 6'd1;
						put_carry = 1;
						sign_extend = 0;
					end
				endcase
			else if(shift_op == `SHIFT_ROR)
				ror = 1;
		end
	end

endmodule