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

module core_control_ldst
(
	input  logic       clk,
	                   rst_n,

	input  insn_decode dec,
	input  logic       issue,
	                   mem_ready,
	input  word        rd_value_b,
	                   q_alu,
	                   q_shifter,

	input  ctrl_cycle  cycle,
	                   next_cycle,
	input  word        alu_a,
	                   alu_b,

	output ptr         mem_addr,
	output logic[3:0]  mem_data_be,
	output word        mem_data_wr,
	                   mem_offset,
	output logic       mem_start,
	                   mem_write,
	                   pop_valid,
	                   ldst,
	                   ldst_next,
	                   ldst_writeback,
	output logic[1:0]  ldst_shift,
	output word        ldst_read,
	output reg_num     popped
);

	word base;
	logic pre, increment, sign_extend;
	reg_num popped_upper, popped_lower;
	reg_list mem_regs, next_regs_upper, next_regs_lower;
	ldst_size size;

	assign popped = increment ? popped_lower : popped_upper;
	assign ldst_next = !cycle.transfer || mem_ready;
	assign mem_data_wr = q_shifter;

	core_control_ldst_pop pop
	(
		.regs(mem_regs),
		.valid(pop_valid),
		.next_upper(next_regs_upper),
		.next_lower(next_regs_lower),
		.pop_upper(popped_upper),
		.pop_lower(popped_lower)
	);

	core_control_ldst_sizes sizes
	(
		.addr(mem_addr),
		.read(ldst_read),
		.shift(ldst_shift),
		.fault(), //TODO: alignment check
		.byteenable(mem_data_be),
		.*
	);

	always_ff @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			pre <= 0;
			ldst <= 0;
			size <= LDST_WORD;
			increment <= 0;
			sign_extend <= 0;
			ldst_writeback <= 0;

			base <= {$bits(base){1'b0}};
			mem_regs <= {$bits(mem_regs){1'b0}};
			mem_write <= 0;
			mem_start <= 0;
			mem_offset <= 0;
		end else begin
			if(mem_start)
				mem_start <= 0;

			if(next_cycle.issue) begin
				// TODO: dec.ldst.unprivileged
				if(issue)
					ldst <= dec.ctrl.ldst;

				pre <= dec.ldst.pre_indexed;
				size <= dec.ldst.size;
				increment <= dec.ldst.increment;
				sign_extend <= dec.ldst.sign_extend;
				ldst_writeback <= dec.ldst.writeback;

				mem_regs <= dec.ldst.regs;
				mem_write <= !dec.ldst.load;
			end else if(next_cycle.transfer) begin
				if(!cycle.transfer) begin
					ldst <= 0;
					mem_offset <= alu_b;
				end

				if(ldst_next) begin
					base <= pre ? q_alu : alu_a;
					mem_regs <= increment ? next_regs_lower : next_regs_upper;
				end

				mem_start <= !cycle.transfer || (mem_ready && pop_valid);
			end else if(cycle.escalate)
				ldst <= 0;
		end
endmodule