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

module core_control_writeback
(
	input  logic       clk,
	                   rst_n,

	input  insn_decode dec,
	input  psr_flags   alu_flags,
	input  word        q_alu,
	                   ldst_read,
	input  logic       mem_ready,
	                   mem_write,
	input  word        mul_q_hi,
	                   mul_q_lo,

	input  ctrl_cycle  cycle,
	                   next_cycle,
	input  word        saved_base,
	                   vector,
	input  reg_num     ra,
	                   popped,
	                   mul_r_add_hi,
	input  logic       issue,
	                   pop_valid,
	                   ldst_next,

	output reg_num     rd,
	                   final_rd,
	output logic       writeback,
	                   final_writeback,
	                   update_flags,
	                   final_update_flags,
	output word        wr_value,
	output psr_flags   wb_alu_flags
);

	reg_num last_rd;

	always_comb begin
		rd = last_rd;
		if(next_cycle.transfer) begin
			if(mem_ready)
				rd = final_rd;
		end else if(next_cycle.issue || next_cycle.base_writeback)
			rd = final_rd;
		else if(next_cycle.exception)
			rd = `R15;
		else if(next_cycle.mul_hi_wb)
			rd = mul_r_add_hi;

		if(next_cycle.issue)
			writeback = final_writeback;
		else if(next_cycle.transfer)
			writeback = mem_ready && !mem_write;
		else if(next_cycle.base_writeback)
			writeback = !mem_write;
		else if(next_cycle.exception || next_cycle.mul_hi_wb)
			writeback = 1;
		else
			writeback = 0;

		if(cycle.transfer)
			wr_value = ldst_read;
		else if(cycle.base_writeback)
			wr_value = saved_base;
		else if(cycle.mul || cycle.mul_hi_wb)
			wr_value = mul_q_lo;
		else
			// Ruta combinacional larga
			wr_value = q_alu;

		if(next_cycle.transfer) begin
			if(mem_ready)
				wr_value = ldst_read;
		end else if(next_cycle.base_writeback)
			wr_value = ldst_read;
		else if(next_cycle.exception)
			wr_value = vector;
		else if(next_cycle.mul_hi_wb)
			wr_value = mul_q_hi;
	end

	always_ff @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			last_rd <= 0;
			final_rd <= 0;
			final_writeback <= 0;

			update_flags <= 0;
			final_update_flags <= 0;

			wb_alu_flags <= {$bits(wb_alu_flags){1'b0}};
		end else begin
			last_rd <= rd;
			wb_alu_flags <= alu_flags;

			if(next_cycle.issue)
				final_rd <= dec.data.rd;
			else if(next_cycle.transfer) begin
				if(ldst_next && pop_valid)
					final_rd <= popped;
			end else if(next_cycle.base_writeback)
				final_rd <= ra;
			else if(next_cycle.exception)
				final_rd <= `R14;

			if(next_cycle.issue)
				final_writeback <= issue && dec.ctrl.writeback;
			else
				final_writeback <= 1;

			update_flags <= 0;
			if(next_cycle.issue)
				update_flags <= final_update_flags;
			else if(next_cycle.exception)
				update_flags <= 0;

			if(next_cycle.issue)
				final_update_flags <= issue && dec.psr.update_flags;
			else if(next_cycle.exception)
				final_update_flags <= 0;
		end

endmodule