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
127
128
129
|
`include "core/uarch.sv"
module core_control_ldst
(
input logic clk,
rst_n,
input insn_decode dec,
input logic issue,
mem_ready,
mem_ex_fail,
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,
mem_ex_lock,
mem_user,
pop_valid,
ldst,
ldst_next,
ldst_reject,
ldst_writeback,
output logic[1:0] ldst_shift,
output word ldst_read,
strex_ok,
output reg_num popped
);
word base;
logic block_strex, increment, pre, 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 = mem_ex_lock ? alu_b : q_shifter;
assign strex_ok = {31'd0, mem_ex_fail || block_strex};
assign ldst_reject = mem_ex_lock && mem_write && block_strex;
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;
block_strex <= 1;
sign_extend <= 0;
ldst_writeback <= 0;
base <= {$bits(base){1'b0}};
mem_regs <= {$bits(mem_regs){1'b0}};
mem_user <= 0;
mem_write <= 0;
mem_start <= 0;
mem_offset <= 0;
mem_ex_lock <= 0;
end else begin
if (mem_start)
mem_start <= 0;
if (next_cycle.issue) begin
if (issue) begin
ldst <= dec.ctrl.ldst;
mem_user <= dec.ldst.unprivileged;
end
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;
mem_ex_lock <= dec.ldst.exclusive;
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)) && !ldst_reject;
if (block_strex)
block_strex <= !mem_ex_lock || mem_write;
end else if (cycle.escalate) begin
ldst <= 0;
block_strex <= 1;
end
end
endmodule
|