1 |
3 |
toni32 |
/* MODULE: openfire_execute
|
2 |
|
|
|
3 |
|
|
DESCRIPTION: The execute module instantiates the alu and comparator and
|
4 |
|
|
updates the Machine Status Register (MSR). This module produces a status
|
5 |
|
|
signal, instr_complete, when the currently executing instruction is finished.
|
6 |
|
|
|
7 |
|
|
TO DO:
|
8 |
|
|
- Add interrupt handling
|
9 |
|
|
- Add exception handling
|
10 |
|
|
- Complete MSR
|
11 |
|
|
- Add all other special registers: EAR, ESR, ESS
|
12 |
|
|
- Add OPB interface
|
13 |
|
|
|
14 |
|
|
AUTHOR:
|
15 |
|
|
Stephen Douglas Craven
|
16 |
|
|
Configurable Computing Lab
|
17 |
|
|
Virginia Tech
|
18 |
|
|
scraven@vt.edu
|
19 |
|
|
|
20 |
|
|
REVISION HISTORY:
|
21 |
|
|
Revision 0.2, 8/10/2005 SDC
|
22 |
|
|
Initial release
|
23 |
|
|
|
24 |
|
|
Revision 0.3, 12/17/2005 SDC
|
25 |
|
|
Fixed PC size bug and CMP bug for case when both rA and rB are negative.
|
26 |
|
|
|
27 |
|
|
Revision 0.4 27/03/2007 Antonio J. Anton
|
28 |
|
|
Memory handshaking protocol
|
29 |
|
|
Removed memory read/write alignment code
|
30 |
|
|
Interrupt handling
|
31 |
|
|
Exception handling
|
32 |
|
|
MSR register handling
|
33 |
|
|
|
34 |
|
|
COPYRIGHT:
|
35 |
|
|
Copyright (c) 2005 Stephen Douglas Craven
|
36 |
|
|
|
37 |
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
38 |
|
|
this software and associated documentation files (the "Software"), to deal in
|
39 |
|
|
the Software without restriction, including without limitation the rights to
|
40 |
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
41 |
|
|
of the Software, and to permit persons to whom the Software is furnished to do
|
42 |
|
|
so, subject to the following conditions:
|
43 |
|
|
|
44 |
|
|
The above copyright notice and this permission notice shall be included in all
|
45 |
|
|
copies or substantial portions of the Software.
|
46 |
|
|
|
47 |
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
48 |
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
49 |
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
50 |
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
51 |
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
52 |
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
53 |
|
|
SOFTWARE.
|
54 |
|
|
|
55 |
|
|
*/
|
56 |
|
|
|
57 |
|
|
`include "openfire_define.v"
|
58 |
|
|
|
59 |
|
|
module openfire_execute (
|
60 |
|
|
`ifdef ENABLE_MSR_BIP
|
61 |
|
|
update_msr_bip, value_msr_bip,
|
62 |
|
|
`endif
|
63 |
|
|
`ifdef ENABLE_INTERRUPTS
|
64 |
|
|
interrupt, int_ip, int_dc, set_msr_ie,
|
65 |
|
|
`endif
|
66 |
|
|
`ifdef ENABLE_MSR_OPCODES
|
67 |
|
|
rS_update,
|
68 |
|
|
`endif
|
69 |
|
|
`ifdef ENABLE_OPCODE_EXCEPTION
|
70 |
|
|
opcode_exception,
|
71 |
|
|
`endif
|
72 |
|
|
`ifdef ENABLE_EXCEPTIONS
|
73 |
|
|
reset_msr_eip,
|
74 |
|
|
`endif
|
75 |
|
|
`ifdef ENABLE_ALIGNMENT_EXCEPTION
|
76 |
|
|
dmem_alignment_exception,
|
77 |
|
|
`endif
|
78 |
|
|
clock, reset, stall, // top level
|
79 |
|
|
immediate, pc_exe, alu_inputA_sel, alu_inputB_sel, // inputs
|
80 |
|
|
alu_inputC_sel, alu_fns_sel, comparator_fns_sel,
|
81 |
|
|
we_load, we_store, regA,
|
82 |
|
|
regB, regD, update_carry, branch_instr,
|
83 |
|
|
alu_result, pc_branch, branch_taken, // outputs
|
84 |
|
|
we_regfile, dmem_addr,
|
85 |
|
|
dmem_data_out, instr_complete, dmem_done,
|
86 |
|
|
dmem_we, dmem_re
|
87 |
|
|
);
|
88 |
|
|
|
89 |
|
|
// From top level -- all active high unless otherwise noted
|
90 |
|
|
input stall;
|
91 |
|
|
input reset;
|
92 |
|
|
input clock;
|
93 |
|
|
|
94 |
|
|
// From DECODE module
|
95 |
|
|
input [31:0] immediate;
|
96 |
|
|
input [`A_SPACE+1:0] pc_exe; // pc for use by EXECUTE
|
97 |
|
|
input [2:0] alu_inputA_sel;
|
98 |
|
|
input [1:0] alu_inputB_sel;
|
99 |
|
|
input [1:0] alu_inputC_sel;
|
100 |
|
|
input [3:0] alu_fns_sel;
|
101 |
|
|
input [2:0] comparator_fns_sel;
|
102 |
|
|
input we_load; // write_en for regfile on Load
|
103 |
|
|
input we_store; // we on DMEM on Store
|
104 |
|
|
input update_carry;
|
105 |
|
|
input branch_instr;
|
106 |
|
|
input dmem_done;
|
107 |
|
|
output dmem_re;
|
108 |
|
|
output dmem_we;
|
109 |
|
|
`ifdef ENABLE_MSR_BIP
|
110 |
|
|
input update_msr_bip;
|
111 |
|
|
input value_msr_bip;
|
112 |
|
|
`endif
|
113 |
|
|
`ifdef ENABLE_INTERRUPTS
|
114 |
|
|
input interrupt;
|
115 |
|
|
output int_ip;
|
116 |
|
|
input int_dc;
|
117 |
|
|
input set_msr_ie;
|
118 |
|
|
`endif
|
119 |
|
|
`ifdef ENABLE_MSR_OPCODES
|
120 |
|
|
input rS_update;
|
121 |
|
|
`endif
|
122 |
|
|
`ifdef ENABLE_OPCODE_EXCEPTION
|
123 |
|
|
input opcode_exception;
|
124 |
|
|
`endif
|
125 |
|
|
`ifdef ENABLE_EXCEPTIONS
|
126 |
|
|
input reset_msr_eip;
|
127 |
|
|
output insert_exception;
|
128 |
|
|
`endif
|
129 |
|
|
`ifdef ENABLE_ALIGNMENT_EXCEPTION
|
130 |
|
|
input dmem_alignment_exception;
|
131 |
|
|
`endif
|
132 |
|
|
|
133 |
|
|
// From REGFILE
|
134 |
|
|
input [31:0] regA;
|
135 |
|
|
input [31:0] regB;
|
136 |
|
|
input [31:0] regD;
|
137 |
|
|
|
138 |
|
|
output [31:0] alu_result;
|
139 |
|
|
output [`A_SPACE+1:0] pc_branch;
|
140 |
|
|
output branch_taken;
|
141 |
|
|
output we_regfile; // we for load and alu
|
142 |
|
|
output [31:0] dmem_addr;
|
143 |
|
|
output [31:0] dmem_data_out;
|
144 |
|
|
output instr_complete; // status of execution, active high
|
145 |
|
|
|
146 |
|
|
// register all outputs EXCEPT:
|
147 |
|
|
// - branch_taken and pc_branch -- registered in FETCH
|
148 |
|
|
// - alu_result -- REGFILE registers
|
149 |
|
|
// - dmem_addr -- DMEM registers
|
150 |
|
|
// - instr_complete -- needed before rise of clock by PIPLINE_CTRL
|
151 |
|
|
assign dmem_data_out = regD;
|
152 |
|
|
|
153 |
|
|
// internal registers
|
154 |
|
|
reg [31:0] MSR; // **TODO** Working: C, BIP, IE
|
155 |
|
|
reg [31:0] alu_a_input;
|
156 |
|
|
reg [31:0] alu_b_input;
|
157 |
|
|
reg alu_c_input;
|
158 |
|
|
reg MSB_signed_compare;
|
159 |
|
|
|
160 |
|
|
wire alu_multicycle_instr;
|
161 |
|
|
wire alu_multicycle_instr_complete;
|
162 |
|
|
wire multicycle_instr;
|
163 |
|
|
wire multicycle_instr_complete;
|
164 |
|
|
wire c_out;
|
165 |
|
|
wire compare_out;
|
166 |
|
|
wire [31:0] alu_out_internal;
|
167 |
|
|
wire [31:0] extended_pc; // PC with leading zeros addded
|
168 |
|
|
|
169 |
|
|
`ifdef ENABLE_EXCEPTIONS
|
170 |
|
|
reg insert_exception; // to ask DECODE to insert "brali r17,0x20"
|
171 |
|
|
wire exception = // 1 if any exception happened
|
172 |
|
|
`ifdef ENABLE_ALIGNMENT_EXCEPTION
|
173 |
|
|
dmem_alignment_exception |
|
174 |
|
|
`endif
|
175 |
|
|
`ifdef ENABLE_OPCODE_EXCEPTION
|
176 |
|
|
opcode_exception |
|
177 |
|
|
`endif
|
178 |
|
|
0;
|
179 |
|
|
`endif
|
180 |
|
|
|
181 |
|
|
`ifdef ENABLE_INTERRUPTS
|
182 |
|
|
// this code is to signal an interrupt when interrupts are enabled (MSR[IE]=1)
|
183 |
|
|
reg int_requested;
|
184 |
|
|
always @(interrupt or MSR[`MSR_IE]) // if interrupt == 1, then raise a request for
|
185 |
|
|
begin // clear the request based on clear_interrupt
|
186 |
|
|
if(interrupt && MSR[`MSR_IE]) int_requested <= 1;
|
187 |
|
|
else if(!MSR[`MSR_IE]) int_requested <= 0;
|
188 |
|
|
end
|
189 |
|
|
|
190 |
|
|
reg int_ip; // interrupt in progress
|
191 |
|
|
wire can_interrupt = // cpu can be interrupted if...
|
192 |
|
|
`ifdef ENABLE_EXCEPTION
|
193 |
|
|
~MSR[`MSR_EIP] & // no Exception in Progress
|
194 |
|
|
`endif
|
195 |
|
|
`ifdef ENABLE_MSR_BIP
|
196 |
|
|
~MSR[`MSR_BIP] & ( // no Break in Progress
|
197 |
|
|
`endif
|
198 |
|
|
~int_ip | set_msr_ie // not interrupt in progress
|
199 |
|
|
`ifdef ENABLE_MSR_BIP // and interrupts are enabled
|
200 |
|
|
)
|
201 |
|
|
`endif
|
202 |
|
|
;
|
203 |
|
|
`endif
|
204 |
|
|
|
205 |
|
|
assign branch_taken = branch_instr ? compare_out : 0;
|
206 |
|
|
assign pc_branch = alu_out_internal[`A_SPACE+1:0]; // ALU calculates next instr address
|
207 |
|
|
|
208 |
|
|
// instr_complete is always high EXCEPT for optional MUL (alu_multicycle_instr)
|
209 |
|
|
// all other instructions currently implemented are single-cycle execution except
|
210 |
|
|
// load / store that are multicycle (controlled by dmem_done)
|
211 |
|
|
// also re/we enable are only valid if EXECUTE is not stalled
|
212 |
|
|
assign dmem_we = we_store & ~stall;
|
213 |
|
|
assign dmem_re = we_load & ~stall;
|
214 |
|
|
|
215 |
|
|
assign memory_instr = we_load | we_store;
|
216 |
|
|
assign memory_instr_complete = memory_instr & dmem_done;
|
217 |
|
|
|
218 |
|
|
assign multicycle_instr = memory_instr | alu_multicycle_instr;
|
219 |
|
|
assign multicycle_instr_complete = memory_instr_complete | alu_multicycle_instr_complete;
|
220 |
|
|
|
221 |
|
|
assign instr_complete = ~multicycle_instr | multicycle_instr_complete;
|
222 |
|
|
assign we_regfile = (we_load & dmem_done) | alu_multicycle_instr_complete;
|
223 |
|
|
|
224 |
|
|
// for CMP/CMPU
|
225 |
|
|
// use comparator output for CMPU
|
226 |
|
|
// use ALU output for CMP -- signed comparison result is a function of input signs and output sign
|
227 |
|
|
assign alu_result[31] = (alu_fns_sel == `ALU_compare_uns) ? compare_out :
|
228 |
|
|
(alu_fns_sel == `ALU_compare) ? MSB_signed_compare :
|
229 |
|
|
alu_out_internal[31];
|
230 |
|
|
assign alu_result[30:0] = alu_out_internal[30:0];
|
231 |
|
|
|
232 |
|
|
always@(regA[31] or regB[31] or alu_out_internal[31])
|
233 |
|
|
begin
|
234 |
|
|
case ({regB[31], regA[31]}) // look at signs of input numbers
|
235 |
|
|
2'b00: MSB_signed_compare <= alu_out_internal[31]; // both inputs positive
|
236 |
|
|
2'b01: MSB_signed_compare <= 0; // A is negative, B is positive => B is greater
|
237 |
|
|
2'b10: MSB_signed_compare <= 1; // B is negative, A is positive => A is greater
|
238 |
|
|
2'b11: MSB_signed_compare <= alu_out_internal[31]; // both inputs negative
|
239 |
|
|
endcase
|
240 |
|
|
end
|
241 |
|
|
|
242 |
|
|
// extend PC to datapath width to store in Reg File
|
243 |
|
|
assign extended_pc[31:`A_SPACE+2] = 0;
|
244 |
|
|
assign extended_pc[`A_SPACE+1:0] = pc_exe;
|
245 |
|
|
|
246 |
|
|
// Stateful logic to handle multi-cycle instructions
|
247 |
|
|
always@(posedge clock)
|
248 |
|
|
begin
|
249 |
|
|
if(reset)
|
250 |
|
|
begin
|
251 |
|
|
MSR[`MSR_C] <= 0; // Carry
|
252 |
|
|
`ifdef ENABLE_INTERRUPTS
|
253 |
|
|
int_ip <= 0;
|
254 |
|
|
MSR[`MSR_IE] <= 1; // Interrupt Enable
|
255 |
|
|
`endif
|
256 |
|
|
`ifdef ENABLE_EXCEPTIONS
|
257 |
|
|
insert_exception <= 0;
|
258 |
|
|
MSR[`MSR_E_Ena] <= 1; // Enable Exceptions
|
259 |
|
|
MSR[`MSR_EIP] <= 0; // Exception in Progress
|
260 |
|
|
`endif
|
261 |
|
|
`ifdef ENABLE_MSR_BIP
|
262 |
|
|
MSR[`MSR_BIP`] <= 0; // Break In Progress
|
263 |
|
|
`endif
|
264 |
|
|
end
|
265 |
|
|
else if (~stall)
|
266 |
|
|
begin
|
267 |
|
|
// Update MSR[BIP] due to BREAK / RTBD
|
268 |
|
|
`ifdef ENABLE_MSR_BIP
|
269 |
|
|
if(update_msr_bip) MSR[`MSR_BIP] <= value_msr_bip;
|
270 |
|
|
`endif
|
271 |
|
|
`ifdef ENABLE_INTERRUPTS
|
272 |
|
|
if(int_requested & can_interrupt) // interrupt requested and cpu can be interrupted?
|
273 |
|
|
begin
|
274 |
|
|
MSR[`MSR_IE] <= 0; // disable further interrupts
|
275 |
|
|
int_ip <= 1; // ask DECODE to insert "brali r14,0x10" asap
|
276 |
|
|
end
|
277 |
|
|
else if(int_ip & int_dc) // if DECODE completed the instruction insert
|
278 |
|
|
int_ip <= 0; // finish interrupt in progress
|
279 |
|
|
if(set_msr_ie) MSR[`MSR_IE] <= 1; // decode asks to enable interrupts again
|
280 |
|
|
`endif
|
281 |
|
|
`ifdef ENABLE_EXCEPTIONS
|
282 |
|
|
/* TODO: exceptions handling ---
|
283 |
|
|
r17 <- PC
|
284 |
|
|
PC <- 0x20
|
285 |
|
|
MSR[EE] <- 0
|
286 |
|
|
MSR[EIP] <- 1
|
287 |
|
|
ESR[DS] <- exception in delay slot
|
288 |
|
|
ESR[EC] <- exception specific value
|
289 |
|
|
ESR[ESS] <- exception specific value
|
290 |
|
|
EAR <- exception specific value
|
291 |
|
|
FSR <- exception specific value
|
292 |
|
|
*/
|
293 |
|
|
if(reset_msr_eip) // return from an exception handler
|
294 |
|
|
begin
|
295 |
|
|
MSR[`MSR_EIP] <= 0; // disable EIP flag due to rted opcode
|
296 |
|
|
MSR[`MSR_E_Ena] <= 1; // enable exceptions agains
|
297 |
|
|
// ESR <- 0 // reset exception cause
|
298 |
|
|
end
|
299 |
|
|
`endif
|
300 |
|
|
`ifdef ENABLE_MSR_OPCODES
|
301 |
|
|
if(rS_update) MSR <= regA; // mts instruction
|
302 |
|
|
`endif
|
303 |
|
|
// Update Carry Bit in Status Register
|
304 |
|
|
if ((alu_fns_sel == `ALU_add) & update_carry)
|
305 |
|
|
MSR[`MSR_C] <= c_out;
|
306 |
|
|
if ((alu_fns_sel == `ALU_shiftR_arth) | (alu_fns_sel == `ALU_shiftR_log) |
|
307 |
|
|
(alu_fns_sel == `ALU_shiftR_c))
|
308 |
|
|
MSR[`MSR_C] <= regA[0];
|
309 |
|
|
|
310 |
|
|
`ifdef DEBUG_EXECUTE
|
311 |
|
|
$display("EXECUTE: pc_exe=%x", pc_exe);
|
312 |
|
|
`endif
|
313 |
|
|
end // end elseif (~stall)
|
314 |
|
|
end // always@
|
315 |
|
|
|
316 |
|
|
/**************************
|
317 |
|
|
* Module input selectors *
|
318 |
|
|
**************************/
|
319 |
|
|
always@(
|
320 |
|
|
`ifdef ENABLE_MSR_OPCODES
|
321 |
|
|
MSR or
|
322 |
|
|
`endif
|
323 |
|
|
alu_inputA_sel or extended_pc or regA
|
324 |
|
|
)
|
325 |
|
|
begin
|
326 |
|
|
case(alu_inputA_sel)
|
327 |
|
|
`aluA_ra: alu_a_input <= regA;
|
328 |
|
|
`aluA_ra_bar: alu_a_input <= ~regA;
|
329 |
|
|
`aluA_pc: alu_a_input <= extended_pc;
|
330 |
|
|
`aluA_zero: alu_a_input <= 0;
|
331 |
|
|
`ifdef ENABLE_MSR_OPCODES
|
332 |
|
|
`aluA_msr: alu_a_input <= MSR; // msr instruction feed to regfile via ALU
|
333 |
|
|
`endif
|
334 |
|
|
endcase
|
335 |
|
|
end // always @ ALU_input_A
|
336 |
|
|
|
337 |
|
|
always@(alu_inputB_sel or immediate or regB)
|
338 |
|
|
begin
|
339 |
|
|
case(alu_inputB_sel)
|
340 |
|
|
`aluB_rb: alu_b_input <= regB;
|
341 |
|
|
`aluB_imm: alu_b_input <= immediate;
|
342 |
|
|
`aluB_rb_bar: alu_b_input <= ~regB;
|
343 |
|
|
`aluB_imm_bar: alu_b_input <= ~immediate;
|
344 |
|
|
endcase
|
345 |
|
|
end // always @ ALU_input_B
|
346 |
|
|
|
347 |
|
|
always@(alu_inputC_sel or MSR)
|
348 |
|
|
begin
|
349 |
|
|
case(alu_inputC_sel)
|
350 |
|
|
`aluC_zero: alu_c_input <= 1'b0;
|
351 |
|
|
`aluC_one: alu_c_input <= 1'b1;
|
352 |
|
|
`aluC_carry: alu_c_input <= MSR[`MSR_C];
|
353 |
|
|
default:
|
354 |
|
|
begin // for simulation
|
355 |
|
|
$display("ERROR! Illegal ALU Input Selection! PC %x", pc_exe);
|
356 |
|
|
alu_c_input <= 1'b0;
|
357 |
|
|
end
|
358 |
|
|
endcase
|
359 |
|
|
end // always @ ALU_input_C
|
360 |
|
|
|
361 |
|
|
// Instantiate ALU and comparator
|
362 |
|
|
openfire_alu ALU0 (
|
363 |
|
|
.clock(clock),
|
364 |
|
|
.reset(reset),
|
365 |
|
|
.stall(stall),
|
366 |
|
|
.a(alu_a_input),
|
367 |
|
|
.b(alu_b_input),
|
368 |
|
|
.c_in(alu_c_input),
|
369 |
|
|
.fns(alu_fns_sel),
|
370 |
|
|
.alu_result(alu_out_internal),
|
371 |
|
|
.c_out(c_out),
|
372 |
|
|
.alu_multicycle_instr(alu_multicycle_instr),
|
373 |
|
|
.dmem_addr(dmem_addr),
|
374 |
|
|
.alu_multicycle_instr_complete(alu_multicycle_instr_complete)
|
375 |
|
|
);
|
376 |
|
|
// comparator used only for branches (and optional CMPU instruction)
|
377 |
|
|
// DECODE unit forces COMPARE output high for unconditional branchs by selecting a 1 output
|
378 |
|
|
// with comparator_fns_sel
|
379 |
|
|
openfire_compare CMP0 (
|
380 |
|
|
.in0(regA),
|
381 |
|
|
.in1(regB),
|
382 |
|
|
.out(compare_out),
|
383 |
|
|
.fns(comparator_fns_sel)
|
384 |
|
|
);
|
385 |
|
|
|
386 |
|
|
endmodule
|