summaryrefslogtreecommitdiff
path: root/rtl/core/cycles.sv
blob: 15248838e8d0f5fb738d0ed9478be901902e8757 (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
116
117
118
119
120
121
122
123
124
125
126
`include "core/uarch.sv"

module core_cycles
(
	input  logic       clk,
	                   dec_execute,
	                   dec_branch,
	                   dec_writeback,
	                   dec_update_flags,
	input  ptr         dec_branch_offset,
	input  alu_decode  dec_alu,
	input  ptr         fetch_insn_pc,
	input  word        rd_value_b,

	output logic       stall,
	                   branch,
	                   writeback,
	                   update_flags,
	output reg_num     rd,
	                   ra,
	                   rb,
	output ptr         branch_target,
	                   pc,
	                   pc_visible,
	output psr_mode    reg_mode,
	output alu_control alu,
	output word        alu_base,
	output logic[7:0]  alu_shift
);

	enum
	{
		EXECUTE,
		RD_SHIFT
	} cycle, next_cycle;

	logic final_writeback, data_snd_is_imm, data_snd_shift_by_reg;
	logic[5:0] data_shift_imm;
	logic[7:0] data_imm;
	word saved_base;
	reg_num r_shift;

	assign stall = next_cycle != EXECUTE;
	assign pc_visible = pc + 2;
	assign reg_mode = `MODE_SVC; //TODO

	always_comb begin
		next_cycle = EXECUTE;
		if((cycle == EXECUTE) & data_snd_shift_by_reg)
			next_cycle = RD_SHIFT;

		unique case(cycle)
			RD_SHIFT:
				alu_base = saved_base;

			default:
				if(data_snd_is_imm)
					alu_base = {{24{1'b0}}, data_imm};
				else
					alu_base = rd_value_b;
		endcase

		unique case(cycle)
			RD_SHIFT: alu_shift = rd_value_b[7:0];
			default:  alu_shift = {2'b00, data_shift_imm};
		endcase
	end

	always_ff @(posedge clk) begin
		cycle <= next_cycle;

		unique case(next_cycle)
			EXECUTE: begin
				branch <= 0;
				update_flags <= 0;
				branch_target <= 30'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
				final_writeback <= 0;

				if(dec_execute) begin
					branch <= dec_branch;
					final_writeback <= dec_writeback;
					update_flags <= dec_update_flags;
					branch_target <= pc_visible + dec_branch_offset;

					data_snd_is_imm <= dec_alu.snd_is_imm;
					data_snd_shift_by_reg <= dec_alu.snd_shift_by_reg;
					data_imm <= dec_alu.imm;
					data_shift_imm <= dec_alu.shift_imm;

					alu.op <= dec_alu.op;
					alu.shl <= dec_alu.shl;
					alu.shr <= dec_alu.shr;
					alu.ror <= dec_alu.ror;
					alu.put_carry <= dec_alu.put_carry;
					alu.sign_extend <= dec_alu.sign_extend;

					rd <= dec_alu.rd;
					ra <= dec_alu.rn;
					rb <= dec_alu.r_snd;
					r_shift <= dec_alu.r_shift;
				end

				writeback <= final_writeback;
				pc <= fetch_insn_pc;
			end

			RD_SHIFT: begin
				rb <= r_shift;
				data_snd_shift_by_reg <= 0;
				saved_base <= rd_value_b;
				writeback <= 0;
			end
		endcase
	end

	initial begin
		cycle = EXECUTE;

		branch = 1;
		writeback = 0;
		data_snd_shift_by_reg = 0;
		branch_target = 30'd0;
		pc = 0;
	end

endmodule