summaryrefslogtreecommitdiff
path: root/rtl/core/control/data.sv
blob: 5ba6b923444e2b42f8ecd053da4828a34af59f94 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
`include "core/uarch.sv"

module core_control_data
(
	input  logic           clk,
	                       rst_n,

	input  insn_decode     dec,
	input  word            rd_value_a,
	                       rd_value_b,
	input  logic           mem_ready,
	                       mem_write,
	input  word            mem_data_rd,
	                       q_alu,
	                       q_shifter,
	input  logic           c_shifter,

	input  ctrl_cycle      cycle,
	                       next_cycle,
	input  ptr             pc,
	input  logic           ldst_next,
	input  logic[1:0]      ldst_shift,
	input  word            mem_offset,
	input  psr_flags       flags,

	output alu_op          alu,
	output word            alu_a,
	                       alu_b,
	                       saved_base,
	output shifter_control shifter,
	output word            shifter_base,
	output logic[7:0]      shifter_shift,
	output logic           c_in,
	                       trivial_shift,
	                       data_snd_shift_by_reg
);

	logic data_snd_is_imm;
	logic[5:0] data_shift_imm;
	logic[11:0] data_imm;

	assign trivial_shift = shifter_shift == 0;

	always_comb begin
		if(cycle.rd_indirect_shift)
			shifter_shift = rd_value_b[7:0];
		else if(cycle.transfer)
			shifter_shift = {3'b000, ldst_shift, 3'b000};
		else
			shifter_shift = {2'b00, data_shift_imm};

		if(cycle.transfer)
			alu_a = saved_base;
		else if(cycle.exception)
			alu_a = {pc, 2'b00};
		else
			alu_a = rd_value_a;

		if(cycle.rd_indirect_shift || cycle.with_shift)
			alu_b = saved_base;
		else if(cycle.transfer)
			alu_b = mem_offset;
		else if(data_snd_is_imm)
			alu_b = {{20{1'b0}}, data_imm};
		else
			alu_b = rd_value_b;

		if(cycle.transfer)
			shifter_base = mem_write ? rd_value_b : mem_data_rd;
		else
			shifter_base = alu_b;
	end

	always_ff @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			alu <= {$bits(alu){1'b0}};
			c_in <= 0;
			shifter <= {$bits(shifter){1'b0}};
			data_imm <= {$bits(data_imm){1'b0}};
			saved_base <= 0;
			data_shift_imm <= {$bits(data_shift_imm){1'b0}};
			data_snd_is_imm <= 0;
			data_snd_shift_by_reg <= 0;
		end else if(next_cycle.issue) begin
			alu <= dec.data.op;
			c_in <= flags.c;

			data_imm <= dec.snd.imm;
			data_shift_imm <= dec.snd.shift_imm;
			data_snd_is_imm <= dec.snd.is_imm;
			data_snd_shift_by_reg <= dec.snd.shift_by_reg;

			shifter.shr <= dec.snd.shr;
			shifter.ror <= dec.snd.ror;
			shifter.put_carry <= dec.snd.put_carry;
			shifter.sign_extend <= dec.snd.sign_extend;
		end else if(next_cycle.rd_indirect_shift) begin
			saved_base <= rd_value_b;
			data_snd_shift_by_reg <= 0;
		end else if(next_cycle.with_shift) begin
			c_in <= c_shifter;
			saved_base <= q_shifter;
		end else if(next_cycle.transfer) begin
			if(ldst_next)
				saved_base <= q_alu;

			shifter.ror <= 0;
			shifter.shr <= !mem_write;
		end else if(next_cycle.exception) begin
			alu <= `ALU_ADD;
			data_imm <= 12'd4;
			data_snd_is_imm <= 1;
		end

endmodule