-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreservation_station.v
More file actions
217 lines (187 loc) · 9.14 KB
/
reservation_station.v
File metadata and controls
217 lines (187 loc) · 9.14 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
`timescale 1ps/1ps
module ReservationStation(input clk,
input wen, input flush,
input [3:0]instr_index, input [3:0]instr_opcode, input [7:0]instr_i, input [3:0]in_op1, input [3:0]in_op2, input [15:0]in_val1, input [15:0]in_val2, input is_val_op1, input is_val_op2,
output [3:0]out_instr_index, output [3:0]out_opcode, output [7:0]out_i, output out_valid,
output [15:0]out_val1, output [15:0]out_val2, output is_full,
// common data bus input
input [3:0]cdb_valid_flat, input [15:0]cdb_rob_index_flat, input [63:0]cdb_result_flat
);
// if the instruction only has one operand, pass in a value for the second one and set is_val_op2 to true
genvar n;
wire cdb_valid[0:3];
wire [3:0]cdb_rob_index[0:3];
wire [15:0]cdb_result[0:3];
generate
for (n=0;n<4;n=n+1) assign cdb_valid[3-n] = cdb_valid_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign cdb_rob_index[3-n] = cdb_rob_index_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign cdb_result[3-n] = cdb_result_flat[16*n+15:16*n];
endgenerate
reg [15:0]instruction_indices[0:3]; // holds instruction address in ROB
reg [3:0]instr_opcodes[0:3]; // holds 4-bit instruction opcodes
reg [7:0]instr_i_values[0:3]; // holds immediate value for
reg instruction_valid[0:3]; // does this row actually represent an instruction or is it empty?
initial begin
instruction_valid[0] = 0;
instruction_valid[1] = 0;
instruction_valid[2] = 0;
instruction_valid[3] = 0;
end
reg [3:0]op1[0:3]; // store owner of operand 1 register
reg op1_valid[0:3]; // set to true once op1 resolves to a value
reg [15:0]val1[0:3]; // store resolved value of operand 1
reg [3:0]op2[0:3]; // store owner of operand 2 register
reg op2_valid[0:3]; // set to true once op2 resolves to a value
reg [15:0]val2[0:3]; // store resolved value of operand 2
// output an instruction that is ready if stage 1 of the functional unit isn't busy (which it never is because it's pipelined)
reg [3:0] out_instr_index_reg; // instruction address in ROB
reg [3:0] out_opcode_reg; // the instruction itself
reg [7:0] out_i_reg; // immediate value if needed
reg out_valid_reg = 0; // is this an actual output
reg [15:0]out_val1_reg; // resolved value of operand 1
reg [15:0]out_val2_reg; // resolved value of operand 2
// is reservation station full when trying to write versus in general
reg is_full_reg = 0;
assign out_instr_index = out_instr_index_reg;
assign out_opcode = out_opcode_reg;
assign out_i = out_i_reg;
assign out_valid = out_valid_reg;
assign out_val1 = out_val1_reg;
assign out_val2 = out_val2_reg;
assign is_full = is_full_reg;
integer i;
wire i0_valid = instruction_valid[2'b00];
wire [3:0] i0_opcode = instr_opcodes[0];
wire i0_op1_valid = op1_valid[0];
wire i0_op2_valid = op2_valid[0];
always @(posedge clk) begin
// flushing is this simple?
if (~flush) begin
// write an instruction to a free spot in the reservation station
if (wen & ~instruction_valid[2'b00]) begin
instruction_valid[2'b00] <= 1;
instr_opcodes[2'b00] <= instr_opcode;
instr_i_values[2'b00] <= instr_i;
instruction_indices[2'b00] <= instr_index;
op1[2'b00] <= in_op1;
op2[2'b00] <= in_op2;
val1[2'b00] <= in_val1;
val2[2'b00] <= in_val2;
op1_valid[2'b00] <= is_val_op1;
op2_valid[2'b00] <= is_val_op2;
end
else if (wen & ~instruction_valid[2'b01]) begin
instruction_valid[2'b01] <= 1;
instr_opcodes[2'b01] <= instr_opcode;
instr_i_values[2'b01] <= instr_i;
instruction_indices[2'b01] <= instr_index;
op1[2'b01] <= in_op1;
op2[2'b01] <= in_op2;
val1[2'b01] <= in_val1;
val2[2'b01] <= in_val2;
op1_valid[2'b01] <= is_val_op1;
op2_valid[2'b01] <= is_val_op2;
end
else if (wen & ~instruction_valid[2'b10]) begin
instruction_valid[2'b10] <= 1;
instr_opcodes[2'b10] <= instr_opcode;
instr_i_values[2'b10] <= instr_i;
instruction_indices[2'b10] <= instr_index;
op1[2'b10] <= in_op1;
op2[2'b10] <= in_op2;
val1[2'b10] <= in_val1;
val2[2'b10] <= in_val2;
op1_valid[2'b10] <= is_val_op1;
op2_valid[2'b10] <= is_val_op2;
end
else if (wen & ~instruction_valid[2'b11]) begin
instruction_valid[2'b11] <= 1;
instr_opcodes[2'b11] <= instr_opcode;
instr_i_values[2'b11] <= instr_i;
instruction_indices[2'b11] <= instr_index;
op1[2'b11] <= in_op1;
op2[2'b11] <= in_op2;
val1[2'b11] <= in_val1;
val2[2'b11] <= in_val2;
op1_valid[2'b11] <= is_val_op1;
op2_valid[2'b11] <= is_val_op2;
end
is_full_reg <= instruction_valid[0] & instruction_valid[1] & instruction_valid[2] & instruction_valid[3];
// update any operands which aren't ready if common data bus has value
for(i = 0; i < 4; i = i + 1) begin
if (instruction_valid[i] & ~op1_valid[i] & cdb_valid[0] & (cdb_rob_index[0] == op1[i])) begin
val1[i] <= cdb_result[0];
op1_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op1_valid[i] & cdb_valid[1] & (cdb_rob_index[1] == op1[i])) begin
val1[i] <= cdb_result[1];
op1_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op1_valid[i] & cdb_valid[2] & (cdb_rob_index[2] == op1[i])) begin
val1[i] <= cdb_result[2];
op1_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op1_valid[i] & cdb_valid[3] & (cdb_rob_index[3] == op1[i])) begin
val1[i] <= cdb_result[3];
op1_valid[i] <= 1;
end
if (instruction_valid[i] & ~op2_valid[i] & cdb_valid[0] & (cdb_rob_index[0] == op2[i])) begin
val2[i] <= cdb_result[0];
op2_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op2_valid[i] & cdb_valid[1] & (cdb_rob_index[1] == op2[i])) begin
val2[i] <= cdb_result[1];
op2_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op2_valid[i] & cdb_valid[2] & (cdb_rob_index[2] == op2[i])) begin
val2[i] <= cdb_result[2];
op2_valid[i] <= 1;
end
else if (instruction_valid[i] & ~op2_valid[i] & cdb_valid[3] & (cdb_rob_index[3] == op2[i])) begin
val2[i] <= cdb_result[3];
op2_valid[i] <= 1;
end
end
// output next ready instruction
if (instruction_valid[2'b00] & op1_valid[2'b00] & op2_valid[2'b00]) begin
instruction_valid[2'b00] <= 0;
out_instr_index_reg <= instruction_indices[2'b00];
out_opcode_reg <= instr_opcodes[2'b00];
out_i_reg <= instr_i_values[2'b00];
out_valid_reg <= 1;
out_val1_reg <= val1[2'b00];
out_val2_reg <= val2[2'b00];
end
else if (instruction_valid[2'b01] & op1_valid[2'b01] & op2_valid[2'b01]) begin
instruction_valid[2'b01] <= 0;
out_instr_index_reg <= instruction_indices[2'b01];
out_opcode_reg <= instr_opcodes[2'b01];
out_i_reg <= instr_i_values[2'b01];
out_valid_reg <= 1;
out_val1_reg <= val1[2'b01];
out_val2_reg <= val2[2'b01];
end
else if (instruction_valid[2'b10] & op1_valid[2'b10] & op2_valid[2'b10]) begin
instruction_valid[2'b10] <= 0;
out_instr_index_reg <= instruction_indices[2'b10];
out_opcode_reg <= instr_opcodes[2'b10];
out_i_reg <= instr_i_values[2'b10];
out_valid_reg <= 1;
out_val1_reg <= val1[2'b10];
out_val2_reg <= val2[2'b10];
end
else if (instruction_valid[2'b11] & op1_valid[2'b11] & op2_valid[2'b11]) begin
instruction_valid[2'b11] <= 0;
out_instr_index_reg <= instruction_indices[2'b11];
out_opcode_reg <= instr_opcodes[2'b11];
out_i_reg <= instr_i_values[2'b11];
out_valid_reg <= 1;
out_val1_reg <= val1[2'b11];
out_val2_reg <= val2[2'b11];
end
else begin
out_valid_reg <= 0;
end
end
end
endmodule