-
Notifications
You must be signed in to change notification settings - Fork 0
/
instruction_buffer.v
390 lines (296 loc) · 16.7 KB
/
instruction_buffer.v
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
`timescale 1ps/1ps
`define NULL 7
module InstructionBuffer
(input clk,
// from instruction fetch unit
input if_valid, // instruction fetch valid
input flush, // will flush for 2 cycles if true
input [15:0] opcode_flat, input [31:0] immediate_flat,
input [3:0]op_a_local_dep_flat, input [15:0] op_a_owner_flat,
input [3:0]op_b_local_dep_flat, input [15:0] op_b_owner_flat,
input [15:0] rt_flat,
input [3:0]uses_rb_flat,
input [3:0]is_ld_str_flat,
input [3:0]is_fxu_flat,
input [3:0]is_branch_flat,
input [3:0]is_halt_flat,
// from regsiter file
input [63:0]ra_value_flat, input [3:0]ra_busy_flat, input [15:0] ra_owner_flat,
input [63:0]rb_value_flat, input [3:0]rb_busy_flat, input [15:0] rb_owner_flat,
// rob input
input [3:0]rob_head_idx, input [15:0]rob_output_valid_flat, input [255:0]rob_output_values_flat,
// functional unit status'
input fxu_0_full, input fxu_1_full, input lsu_full, input branch_full,
// outputs
output [2:0] num_fetch,
// fxu 0
output out_fxu_0_instr_valid, output [3:0] out_fxu_0_rob_idx, output out_fxu_0_a_valid, output [15:0] out_fxu_0_a_value, output [3:0] out_fxu_0_a_owner,
output out_fxu_0_b_valid, output [15:0] out_fxu_0_b_value, output [3:0] out_fxu_0_b_owner, output [3:0] out_fxu_0_opcode, output [7:0] out_fxu_0_i,
// fxu 1
output out_fxu_1_instr_valid, output [3:0] out_fxu_1_rob_idx, output out_fxu_1_a_valid, output [15:0] out_fxu_1_a_value, output [3:0] out_fxu_1_a_owner,
output out_fxu_1_b_valid, output [15:0] out_fxu_1_b_value, output [3:0] out_fxu_1_b_owner, output [3:0] out_fxu_1_opcode, output [7:0] out_fxu_1_i,
// lsu
output out_lsu_instr_valid, output [3:0] out_lsu_rob_idx,output out_lsu_a_valid, output [15:0] out_lsu_a_value, output [3:0] out_lsu_a_owner,
output out_lsu_b_valid, output [15:0] out_lsu_b_value, output [3:0] out_lsu_b_owner, output [3:0] out_lsu_opcode,
// branch unit
output out_branch_instr_valid, output [3:0] out_branch_rob_idx, output out_branch_a_valid, output [15:0] out_branch_a_value, output [3:0] out_branch_a_owner,
output out_branch_b_valid, output [15:0] out_branch_b_value, output [3:0] out_branch_b_owner, output [3:0] out_branch_opcode,
output [3:0] out_rob_valid_flat, output [15:0] out_rob_rt_flat, output [3:0] out_rob_halt_flat,
output [3:0] rt_update_enable_flat, output [15:0] rt_target_reg_flat, output [15:0] rt_owner_flat
);
genvar n;
reg first_time = 1;
reg last_flush = 0;
wire [3:0] opcode[0:3];
wire [7:0] w_immediate[0:3];
wire w_op_a_local_dep[0:3];
wire [3:0] w_op_a_owner[0:3];
wire w_op_b_local_dep[0:3];
wire [3:0] w_op_b_owner[0:3];
wire [3:0] w_rt[0:3];
wire w_uses_rb[0:3];
wire w_is_ld_str[0:3];
wire w_is_fxu[0:3];
wire w_is_branch[0:3];
wire w_is_halt[0:3];
wire w_rob_output_valid[0:15];
wire [15:0] w_rob_output_values[0:15];
// unflatten input wires
generate
for (n=0;n<4;n=n+1) assign opcode[3-n] = opcode_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign w_immediate[3-n] = immediate_flat[8*n+7:8*n];
for (n=0;n<4;n=n+1) assign w_op_a_local_dep[3-n] = op_a_local_dep_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_op_a_owner[3-n] = op_a_owner_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign w_op_b_local_dep[3-n] = op_b_local_dep_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_op_b_owner[3-n] = op_b_owner_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign w_rt[3-n] = rt_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign w_uses_rb[3-n] = uses_rb_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_is_ld_str[3-n] = is_ld_str_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_is_fxu[3-n] = is_fxu_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_is_branch[3-n] = is_branch_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign w_is_halt[3-n] = is_halt_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign ra_value[3-n] = ra_value_flat[16*n+15:16*n];
for (n=0;n<4;n=n+1) assign ra_busy[3-n] = ra_busy_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign ra_owner[3-n] = ra_owner_flat[4*n+3:4*n];
for (n=0;n<4;n=n+1) assign rb_value[3-n] = rb_value_flat[16*n+15:16*n];
for (n=0;n<4;n=n+1) assign rb_busy[3-n] = rb_busy_flat[1*n+0:1*n];
for (n=0;n<4;n=n+1) assign rb_owner[3-n] = rb_owner_flat[4*n+3:4*n];
for (n=0;n<16;n=n+1) assign w_rob_output_valid[15-n] = rob_output_valid_flat[1*n+0:1*n];
for (n=0;n<16;n=n+1) assign w_rob_output_values[15-n] = rob_output_values_flat[16*n+15:16*n];
endgenerate
// flatten into output wires from all output regs
generate
for (n=0; n<4; n=n+1) assign out_rob_valid_flat [1*n+0:1*n] = rob_valid[3-n];
for (n=0; n<4; n=n+1) assign out_rob_rt_flat [4*n+3:4*n] = m_out_rt[3-n];
for (n=0; n<4; n=n+1) assign out_rob_halt_flat [1*n+0:1*n] = rob_halt[3-n];
for (n=0; n<4; n=n+1) assign rt_update_enable_flat[1*n+0:1*n] = rt_update_enable[3-n];
for (n=0; n<4; n=n+1) assign rt_target_reg_flat[4*n+3:4*n] = rt_target_reg[3-n];
for (n=0; n<4; n=n+1) assign rt_owner_flat[4*n+3:4*n] = rt_owner[3-n];
endgenerate
reg [7:0] immediate[0:3];
reg op_a_local_dep[0:3];
reg op_b_local_dep[0:3];
reg [3:0] rt[0:3];
reg uses_rb[0:3];
reg is_ld_str[0:3];
reg is_fxu[0:3];
reg is_branch[0:3];
reg is_halt[0:3];
reg [15:0]ra_value[0:3];
reg ra_busy[0:3];
reg [3:0] ra_owner[0:3];
reg [15:0]rb_value[0:3];
reg rb_busy[0:3];
reg [3:0] rb_owner[0:3];
reg rob_output_valid[0:15];
reg [15:0]rob_output_values[0:15];
reg [3:0] ib_a_owner[0:3];
reg [3:0] ib_b_owner[0:3];
reg [3:0] ib_opcode[0:3];
wire [15:0] ib_a_value[0:3];
wire [15:0] ib_b_value[0:3];
wire ib_a_valid[0:3];
wire ib_b_valid[0:3];
reg [2:0] m_num_fetch = 0;
reg ib_valid = 0;
reg [1:0] head = 0;
wire [7:0]imm_0 = immediate[0];
wire [7:0]imm_1 = immediate[1];
wire [7:0]imm_2 = immediate[2];
wire [7:0]imm_3 = immediate[3];
wire [7:0] wimm0 = w_immediate[0];
wire [7:0] wimm1 = w_immediate[1];
wire [7:0] wimm2 = w_immediate[2];
wire [7:0] wimm3 = w_immediate[3];
wire [3:0]ib_a_owner_1 = ib_a_owner[1];
always @(posedge clk) begin
integer i;
integer idx;
for (i = 0; i < 4; i++) begin
// $write("cur itr %d\n", i);
if (~(ib_valid & stall_array[i])) begin
// $write("THIS IS VALID: %d\n",i);
idx =
i == 0 ? head :
i == 1 ? head_overflow_1 :
i == 2 ? head_overflow_2 :
i == 3 ? head_overflow_3 : 0;
ib_a_owner[idx] <= w_op_a_local_dep[i] ? w_op_a_owner[i] : (ra_busy[i] ? ra_owner[i] : rob_head_idx + i);
ib_b_owner[idx] <= w_op_b_local_dep[i] ? w_op_b_owner[i] : (rb_busy[i] ? rb_owner[i] : rob_head_idx + i);
ib_opcode[idx] <= opcode[i];
immediate[idx] <= w_immediate[i];
op_a_local_dep[idx] <= w_op_a_local_dep[i];
op_b_local_dep[idx] <= w_op_b_local_dep[i];
rt[idx] <= w_rt[i];
uses_rb[idx] <= w_uses_rb[i];
is_ld_str[idx] <= w_is_ld_str[i];
is_fxu[idx] <= w_is_fxu[i];
is_branch[idx] <= w_is_branch[i];
is_halt[idx] <= w_is_halt[i];
end
end
for (i = 0; i < 15; i++) begin
rob_output_valid[i] <= w_rob_output_valid[i];
rob_output_values[i] <= w_rob_output_values[i];
end
ib_valid <= if_valid;
m_num_fetch <= m_num_fetch_wire;
head <= ~ib_valid ? 0 : head + (m_num_fetch_wire);
first_time <= ib_valid;
last_flush <= flush;
end
wire [3:0]m_out_rt [0:3];
assign m_out_rt[0] = rt[head];
assign m_out_rt[1] = rt[head_overflow_1];
assign m_out_rt[2] = rt[head_overflow_2];
assign m_out_rt[3] = rt[head_overflow_3];
wire stall_array[0:3];
assign stall_array[0] = stall_0;
assign stall_array[1] = stall_1;
assign stall_array[2] = stall_2;
assign stall_array[3] = stall_3;
wire is_mov_imm_0 = ib_opcode[0] == 5 | ib_opcode[0] == 5;
wire is_mov_imm_1 = ib_opcode[1] == 5 | ib_opcode[1] == 6;
wire is_mov_imm_2 = ib_opcode[2] == 5 | ib_opcode[2] == 6;
wire is_mov_imm_3 = ib_opcode[3] == 5 | ib_opcode[3] == 6;
assign ib_a_valid[0] = (~op_a_local_dep[0] & (rob_output_valid[ib_a_owner[0]] | ~ra_busy[0])) | is_mov_imm_0;
assign ib_a_valid[1] = (~op_a_local_dep[1] & (rob_output_valid[ib_a_owner[1]] | ~ra_busy[1])) | is_mov_imm_1;
assign ib_a_valid[2] = (~op_a_local_dep[2] & (rob_output_valid[ib_a_owner[2]] | ~ra_busy[2])) | is_mov_imm_2;
assign ib_a_valid[3] = (~op_a_local_dep[3] & (rob_output_valid[ib_a_owner[3]] | ~ra_busy[3])) | is_mov_imm_3;
assign ib_a_value[0] = ra_busy[0] ? rob_output_values[ib_a_owner[0]] : ra_value[0];
assign ib_a_value[1] = ra_busy[1] ? rob_output_values[ib_a_owner[1]] : ra_value[1];
assign ib_a_value[2] = ra_busy[2] ? rob_output_values[ib_a_owner[2]] : ra_value[2];
assign ib_a_value[3] = ra_busy[3] ? rob_output_values[ib_a_owner[3]] : ra_value[3];
assign ib_b_valid[0] = (~uses_rb[0] | (~op_b_local_dep[0] & (rob_output_valid[ib_b_owner[0]] | ~rb_busy[0]))) | is_mov_imm_0;
assign ib_b_valid[1] = (~uses_rb[1] | (~op_b_local_dep[1] & (rob_output_valid[ib_b_owner[1]] | ~rb_busy[1]))) | is_mov_imm_1;
assign ib_b_valid[2] = (~uses_rb[2] | (~op_b_local_dep[2] & (rob_output_valid[ib_b_owner[2]] | ~rb_busy[2]))) | is_mov_imm_2;
assign ib_b_valid[3] = (~uses_rb[3] | (~op_b_local_dep[3] & (rob_output_valid[ib_b_owner[3]] | ~rb_busy[3]))) | is_mov_imm_3;
assign ib_b_value[0] = rb_busy[0] ? rob_output_values[ib_b_owner[0]] : rb_value[0];
assign ib_b_value[1] = rb_busy[1] ? rob_output_values[ib_b_owner[1]] : rb_value[1];
assign ib_b_value[2] = rb_busy[2] ? rob_output_values[ib_b_owner[2]] : rb_value[2];
assign ib_b_value[3] = rb_busy[3] ? rob_output_values[ib_b_owner[3]] : rb_value[3];
wire is_fxu_0_w = is_fxu[head];
wire is_fxu_1_w = is_fxu[head_overflow_1];
wire is_fxu_2_w = is_fxu[head_overflow_2];
wire is_fxu_3_w = is_fxu[head_overflow_3];
wire i0_fxu_0 = is_fxu[head] & ~fxu_0_full;
wire i0_fxu_1 = is_fxu[head] & ~i0_fxu_0 & ~fxu_1_full;
wire is_fxu_0 = is_fxu[head];
wire is_fxu_1 = is_fxu[head];
wire i1_fxu_0 = is_fxu[head_overflow_1] & ~fxu_0_full & ~i0_fxu_0;
wire i1_fxu_1 = is_fxu[head_overflow_1] & ~i1_fxu_0 & ~fxu_1_full & ~i0_fxu_1;
wire i2_fxu_0 = is_fxu[head_overflow_2] & ~fxu_0_full & ~i0_fxu_0 & ~i1_fxu_0;
wire i2_fxu_1 = is_fxu[head_overflow_2] & ~i2_fxu_0 & ~fxu_1_full & ~i0_fxu_1 & ~i1_fxu_1;
wire i3_fxu_0 = is_fxu[head_overflow_3] & ~fxu_0_full & ~i0_fxu_0 & ~i1_fxu_0 & ~i2_fxu_0;
wire i3_fxu_1 = is_fxu[head_overflow_3] & ~i3_fxu_0 & ~fxu_1_full & ~i0_fxu_1 & ~i1_fxu_1 & ~i2_fxu_1;
wire i0_branch = is_branch[head] & ~branch_full;
wire i1_branch = is_branch[head_overflow_1] & ~branch_full & ~i0_branch;
wire i2_branch = is_branch[head_overflow_2] & ~branch_full & ~i0_branch & ~i1_branch;
wire i3_branch = is_branch[head_overflow_3] & ~branch_full & ~i0_branch & ~i1_branch & ~i2_branch;
wire i0_halt = is_halt[head];
wire i1_halt = is_halt[head_overflow_1] & ~i0_halt;
wire i2_halt = is_halt[head_overflow_2] & ~i0_halt & ~i1_halt;
wire i3_halt = is_halt[head_overflow_3] & ~i0_halt & ~i1_halt & ~i2_halt;
// add load store later
wire flush_now = flush | last_flush;
wire [1:0] head_overflow_1 = head + 1;
wire [1:0] head_overflow_2 = head + 2;
wire [1:0] head_overflow_3 = head + 3;
wire stall_0 = ~flush_now & ((is_fxu[head] & (~i0_fxu_0 & ~i0_fxu_1)) | (is_branch[head] & ~i0_branch)) & ib_valid; // never need to stall if first one is a halt
wire stall_1 = ~flush_now & ((is_fxu[head_overflow_1] & (~i1_fxu_0 & ~i1_fxu_1)) | (is_branch[head_overflow_1] & ~i1_branch) | (is_halt[head_overflow_1] & stall_0)) & ib_valid;
wire stall_2 = ~flush_now & ((is_fxu[head_overflow_2] & (~i2_fxu_0 & ~i2_fxu_1)) | (is_branch[head_overflow_2] & ~i2_branch) | (is_halt[head_overflow_2] & stall_1)) & ib_valid;
wire stall_3 = ~flush_now & ((is_fxu[head_overflow_3] & (~i3_fxu_0 & ~i3_fxu_1)) | (is_branch[head_overflow_3] & ~i3_branch) | (is_halt[head_overflow_3] & stall_2)) & ib_valid;
wire stall_none = ~stall_0 & ~stall_1 & ~stall_2 & ~stall_3;
wire [3:0]m_num_fetch_wire = ib_valid ? (stall_none ? 4 : (stall_0 ? 0 : (stall_1 ? 1 : (stall_2 ? 2 : (stall_3 ? 3 : `NULL))))) : 4;
assign num_fetch = m_num_fetch_wire;
wire [2:0]fxu_0_instr = i0_fxu_0 ? head : (i1_fxu_0 ? head_overflow_1 : (i2_fxu_0 ? head_overflow_2 : (i3_fxu_0 ? head_overflow_3 : `NULL)));
wire [2:0]fxu_1_instr = i0_fxu_1 ? head : (i1_fxu_1 ? head_overflow_1 : (i2_fxu_1 ? head_overflow_2 : (i3_fxu_1 ? head_overflow_3 : `NULL)));
wire [2:0]branch_instr = i0_branch ? head : (i1_branch ? head_overflow_1 : (i2_branch ? head_overflow_2 : (i3_branch ? head_overflow_3 : `NULL)));
wire fxu_0_valid = ~flush_now & fxu_0_instr != `NULL;
wire fxu_1_valid = ~flush_now & fxu_1_instr != `NULL;
wire branch_valid = ~flush_now & branch_instr != `NULL;
assign out_fxu_0_instr_valid = fxu_0_valid;
assign out_fxu_0_rob_idx = rob_head_idx + (fxu_0_instr - head);
assign out_fxu_0_opcode = ib_opcode[fxu_0_instr];
assign out_fxu_0_i = immediate[fxu_0_instr];
assign out_fxu_0_a_valid = ib_a_valid[fxu_0_instr];
assign out_fxu_0_a_owner = ib_a_owner[fxu_0_instr];
assign out_fxu_0_a_value = ib_a_value[fxu_0_instr];
assign out_fxu_0_b_valid = ib_b_valid[fxu_0_instr];
assign out_fxu_0_b_owner = ib_b_owner[fxu_0_instr];
assign out_fxu_0_b_value = ib_b_value[fxu_0_instr];
assign out_fxu_1_instr_valid = fxu_1_valid;
assign out_fxu_1_rob_idx = rob_head_idx + (fxu_1_instr - head);
assign out_fxu_1_opcode = ib_opcode[fxu_1_instr];
assign out_fxu_1_i = immediate[fxu_1_instr];
assign out_fxu_1_a_valid = ib_a_valid[fxu_1_instr];
assign out_fxu_1_a_owner = ib_a_owner[fxu_1_instr];
assign out_fxu_1_a_value = ib_a_value[fxu_1_instr];
assign out_fxu_1_b_valid = ib_b_valid[fxu_1_instr];
assign out_fxu_1_b_owner = ib_b_owner[fxu_1_instr];
assign out_fxu_1_b_value = ib_b_value[fxu_1_instr];
assign out_branch_instr_valid = branch_valid;
assign out_branch_rob_idx = rob_head_idx + branch_instr;
assign out_branch_opcode = ib_opcode[branch_instr];
assign out_branch_a_valid = ib_a_valid[branch_instr];
assign out_branch_a_owner = ib_a_owner[branch_instr];
assign out_branch_a_value = ib_a_value[branch_instr];
assign out_branch_b_valid = ib_b_valid[branch_instr];
assign out_branch_b_owner = ib_b_owner[branch_instr];
assign out_branch_b_value = ib_b_value[branch_instr];
wire rob_valid [0:3];
assign rob_valid[0] = ~undef_0 & ib_valid & ~stall_0;
assign rob_valid[1] = ~undef_0 & ~undef_1 & ib_valid & ~stall_0 & ~stall_1;
assign rob_valid[2] = ~undef_0 & ~undef_1 & ~undef_2 & ib_valid & ~stall_0 & ~stall_1 & ~stall_2;
assign rob_valid[3] = ~undef_0 & ~undef_1 & ~undef_2 & ~undef_3 & ib_valid & ~stall_0 & ~stall_1 & ~stall_2 & ~stall_3;
wire undef_0 = ib_opcode[head] > 12 && ib_opcode[head] != 15;
wire undef_1 = ib_opcode[head_overflow_1] > 12 && ib_opcode[head_overflow_1] != 15;
wire undef_2 = ib_opcode[head_overflow_2] > 12 && ib_opcode[head_overflow_2] != 15;
wire undef_3 = ib_opcode[head_overflow_3] > 12 && ib_opcode[head_overflow_3] != 15;
wire rob_halt[0:3];
// keep it in same format as everything else with flattening and unflattening
assign rob_halt[0] = ib_valid & is_halt[head] & !stall_0;
assign rob_halt[1] = ib_valid & is_halt[head_overflow_1] & !stall_1;
assign rob_halt[2] = ib_valid & is_halt[head_overflow_2] & !stall_2;
assign rob_halt[3] = ib_valid & is_halt[head_overflow_3] & !stall_3;
wire i3_writes_to_reg = ib_opcode[head_overflow_3] == 0 | ib_opcode[head_overflow_3] == 1 | ib_opcode[head_overflow_3] == 2 | ib_opcode[head_overflow_3] == 4 | ib_opcode[head_overflow_3] == 5 | ib_opcode[head_overflow_3] == 6;
wire i2_writes_to_reg = ib_opcode[head_overflow_2] == 0 | ib_opcode[head_overflow_2] == 1 | ib_opcode[head_overflow_2] == 2 | ib_opcode[head_overflow_2] == 4 | ib_opcode[head_overflow_2] == 5 | ib_opcode[head_overflow_2] == 6;
wire i1_writes_to_reg = ib_opcode[head_overflow_1] == 0 | ib_opcode[head_overflow_1] == 1 | ib_opcode[head_overflow_1] == 2 | ib_opcode[head_overflow_1] == 4 | ib_opcode[head_overflow_1] == 5 | ib_opcode[head_overflow_1] == 6;
wire i0_writes_to_reg = ib_opcode[head] == 0 | ib_opcode[head] == 1 | ib_opcode[head] == 2 | ib_opcode[head] == 4 | ib_opcode[head] == 5 | ib_opcode[head] == 6;
wire rt_update_enable [0:3];
wire [3:0] rt_target_reg[0:3];
wire [3:0] rt_owner[0:3];
// TODO: unflatten
assign rt_update_enable[3] = 1 & i3_writes_to_reg;
assign rt_update_enable[2] = rt[head_overflow_3] != rt[head_overflow_2] & i2_writes_to_reg;
assign rt_update_enable[1] = rt[head_overflow_1] != rt[head_overflow_2] & rt[head_overflow_1] != rt[head_overflow_3] & i1_writes_to_reg;
assign rt_update_enable[0] = rt[head] != rt[head_overflow_1] & rt[head] != rt[head_overflow_2] & rt[head] != rt[head_overflow_3] & i0_writes_to_reg;
assign rt_target_reg[0] = rt[head];
assign rt_target_reg[1] = rt[head_overflow_1];
assign rt_target_reg[2] = rt[head_overflow_2];
assign rt_target_reg[3] = rt[head_overflow_3];
assign rt_owner[0] = rob_head_idx;
assign rt_owner[1] = rob_head_idx + 1;
assign rt_owner[2] = rob_head_idx + 2;
assign rt_owner[3] = rob_head_idx + 3;
endmodule