summaryrefslogtreecommitdiff
path: root/rtl/core/control/cycles.sv
blob: ca47f1076ae7678d66211290c328a9da3a19fdd1 (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
`include "core/uarch.sv"

module core_control_cycles
(
	input  logic      clk,
	                  rst_n,
	                  halt,
	                  mul,
	                  ldst,
	                  bubble,
	                  exception,
	                  mem_ready,
	                  mul_add,
	                  mul_long,
	                  mul_ready,
	                  pop_valid,
	                  trivial_shift,
	                  ldst_writeback,
	                  data_snd_shift_by_reg,

	output ctrl_cycle cycle,
	                  next_cycle
);

	/* qts-qii51007-recommended-hdl.pdf, p. 66
	 * In Quartus II integrated synthesis, the enumerated type that defines the states for the
	 * state machine must be of an unsigned integer type as in Example 13–52. If you do not
	 * specify the enumerated type as int unsigned, a signed int type is used by default. In
	 * this case, the Quartus II integrated synthesis synthesizes the design, but does not infer
	 * or optimize the logic as a state machine.
	 */
	enum int unsigned
	{
		ISSUE,
		RD_INDIRECT_SHIFT,
		WITH_SHIFT,
		TRANSFER,
		BASE_WRITEBACK,
		EXCEPTION,
		MUL,
		MUL_ACC_LD,
		MUL_HI_WB
	} state, next_state;

	// TODO: debe estar escrito de tal forma que Quartus infiera una FSM

	assign cycle.issue = state == ISSUE;
	assign cycle.rd_indirect_shift = state == RD_INDIRECT_SHIFT;
	assign cycle.with_shift = state == WITH_SHIFT;
	assign cycle.transfer = state == TRANSFER;
	assign cycle.base_writeback = state == BASE_WRITEBACK;
	assign cycle.exception = state == EXCEPTION;
	assign cycle.mul = state == MUL;
	assign cycle.mul_acc_ld = state == MUL_ACC_LD;
	assign cycle.mul_hi_wb = state == MUL_HI_WB;

	assign next_cycle.issue = next_state == ISSUE;
	assign next_cycle.rd_indirect_shift = next_state == RD_INDIRECT_SHIFT;
	assign next_cycle.with_shift = next_state == WITH_SHIFT;
	assign next_cycle.transfer = next_state == TRANSFER;
	assign next_cycle.base_writeback = next_state == BASE_WRITEBACK;
	assign next_cycle.exception = next_state == EXCEPTION;
	assign next_cycle.mul = next_state == MUL;
	assign next_cycle.mul_acc_ld = next_state == MUL_ACC_LD;
	assign next_cycle.mul_hi_wb = next_state == MUL_HI_WB;

	always_comb begin
		next_state = ISSUE;

		unique case(state)
			ISSUE:
				if(exception)
					next_state = EXCEPTION;
				else if(halt)
					next_state = ISSUE;
				else if(mul)
					next_state = mul_add ? MUL_ACC_LD : MUL;
				else if(data_snd_shift_by_reg)
					next_state = RD_INDIRECT_SHIFT;
				else if(!trivial_shift)
					next_state = WITH_SHIFT;

			RD_INDIRECT_SHIFT:
				if(!trivial_shift)
					next_state = WITH_SHIFT;

			TRANSFER:
				if(!mem_ready || pop_valid)
					next_state = TRANSFER;
				else if(ldst_writeback)
					next_state = BASE_WRITEBACK;

			MUL:
				if(!mul_ready)
					next_state = MUL;
				else if(mul_long)
					next_state = MUL_HI_WB;

			MUL_ACC_LD:
				next_state = MUL;

			/* Este default evita problemas de sintetizado, ya que Quartus
			 * asume que los casos mencionados son exhaustivos, provocando
			 * bugs muy difíciles de depurar. No es lo mismo que si se quita
			 * default.
			 */
			default: ;
		endcase

		if(bubble)
			next_state = ISSUE;
		else if(next_state == ISSUE && ldst) begin
			next_state = TRANSFER;
		end
	end

	always_ff @(posedge clk or negedge rst_n)
		state <= !rst_n ? ISSUE : next_state;

endmodule