OpenCores
URL https://opencores.org/ocsvn/openfire2/openfire2/trunk

Subversion Repositories openfire2

[/] [openfire2/] [trunk/] [rtl/] [openfire_execute.v] - Rev 6

Compare with Previous | Blame | View Log

/*	MODULE: openfire_execute
 
	DESCRIPTION: The execute module instantiates the alu and comparator and
updates the Machine Status Register (MSR).  This module produces a status
signal, instr_complete, when the currently executing instruction is finished.
 
TO DO:
- Add interrupt handling
- Add exception handling
- Complete MSR
- Add all other special registers: EAR, ESR, ESS
- Add OPB interface
 
AUTHOR: 
Stephen Douglas Craven
Configurable Computing Lab
Virginia Tech
scraven@vt.edu
 
REVISION HISTORY:
Revision 0.2, 8/10/2005 SDC
Initial release
 
Revision 0.3, 12/17/2005 SDC
Fixed PC size bug and CMP bug for case when both rA and rB are negative.
 
Revision 0.4  27/03/2007 Antonio J. Anton
Memory handshaking protocol
Removed memory read/write alignment code
Interrupt handling
Exception handling
MSR register handling
 
COPYRIGHT:
Copyright (c) 2005 Stephen Douglas Craven
 
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in 
the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.
 
*/
 
`include "openfire_define.v"
 
module openfire_execute (
`ifdef ENABLE_MSR_BIP
	update_msr_bip, value_msr_bip,
`endif
`ifdef ENABLE_INTERRUPTS
	interrupt, int_ip, int_dc, set_msr_ie,
`endif
`ifdef ENABLE_MSR_OPCODES
	rS_update,
`endif
`ifdef ENABLE_OPCODE_EXCEPTION
	opcode_exception,
`endif
`ifdef ENABLE_EXCEPTIONS
	reset_msr_eip,
`endif
`ifdef ENABLE_ALIGNMENT_EXCEPTION
	dmem_alignment_exception,
`endif
`ifdef FSL_LINK
	fsl_m_control, fsl_m_write, fsl_s_read,
	fsl_cmd_vld, fsl_get, fsl_blocking, fsl_control,	//FSL
	fsl_m_full, fsl_s_control, fsl_s_exists,
`endif
	clock, reset, stall,											// top level
	immediate, pc_exe, alu_inputA_sel, alu_inputB_sel, // inputs
	alu_inputC_sel, alu_fns_sel, comparator_fns_sel,	
	we_load, we_store, regA,
	regB, regD, update_carry, branch_instr,
	alu_result, pc_branch, branch_taken, 					// outputs
	we_regfile, dmem_addr, 
	dmem_data_out, instr_complete, dmem_done,
	dmem_we, dmem_re
);
 
// From top level -- all active high unless otherwise noted
input		stall;
input		reset;
input		clock;
 
// From DECODE module
input	[31:0]	immediate;
input	[`A_SPACE+1:0]	pc_exe;			// pc for use by EXECUTE
input	[2:0]		alu_inputA_sel;
input	[1:0]		alu_inputB_sel;
input	[1:0]		alu_inputC_sel;
input	[3:0]		alu_fns_sel;
input	[2:0]		comparator_fns_sel;
input 			we_load;					// write_en for regfile on Load
input				we_store;				// we on DMEM on Store
input				update_carry;
input				branch_instr;
input				dmem_done;
output			dmem_re;
output			dmem_we;
`ifdef ENABLE_MSR_BIP
input				update_msr_bip;
input				value_msr_bip;
`endif
`ifdef ENABLE_INTERRUPTS
input				interrupt;
output			int_ip;
input			   int_dc;
input			   set_msr_ie;
`endif
`ifdef ENABLE_MSR_OPCODES
input				rS_update;
`endif
`ifdef ENABLE_OPCODE_EXCEPTION
input			  	opcode_exception;
`endif
`ifdef ENABLE_EXCEPTIONS
input				reset_msr_eip;
output			insert_exception;
`endif
`ifdef ENABLE_ALIGNMENT_EXCEPTION
input				dmem_alignment_exception;
`endif
`ifdef FSL_LINK
input			fsl_get;
input			fsl_control;
input			fsl_blocking;
input			fsl_cmd_vld;
input			fsl_s_control;		//From FSL
input			fsl_s_exists;
input			fsl_m_full;
output		fsl_m_control;
output		fsl_m_write;
output		fsl_s_read;
`endif
 
// From REGFILE
input	[31:0]	regA;
input	[31:0]	regB;
input	[31:0]	regD;
 
output	[31:0]	alu_result;
output	[`A_SPACE+1:0]	pc_branch;
output				branch_taken;
output				we_regfile;			// we for load and alu
output	[31:0]	dmem_addr;
output	[31:0]	dmem_data_out;
output				instr_complete;	// status of execution, active high
 
// register all outputs EXCEPT:
//	- branch_taken and pc_branch -- registered in FETCH
//	- alu_result -- REGFILE registers
//	- dmem_addr -- DMEM registers
//	- instr_complete -- needed before rise of clock by PIPLINE_CTRL
assign dmem_data_out = regD;
 
// internal registers
reg	[31:0]	MSR;				// **TODO** Working: C, BIP, IE
reg	[31:0]	alu_a_input;
reg	[31:0]	alu_b_input;
reg				alu_c_input;
reg				MSB_signed_compare;
 
`ifdef FSL_LINK
reg			fsl_complete;
reg			fsl_m_write;
reg			fsl_s_read;
reg			fsl_m_control;
`endif
 
wire			alu_multicycle_instr;
wire			alu_multicycle_instr_complete;
wire			multicycle_instr;
wire			multicycle_instr_complete;
wire			c_out;
wire			compare_out;
wire [31:0]	alu_out_internal;
wire [31:0]	extended_pc;	// PC with leading zeros addded
 
`ifdef ENABLE_EXCEPTIONS
reg			insert_exception;			// to ask DECODE to insert "brali r17,0x20"
wire			exception = 				// 1 if any exception happened
`ifdef ENABLE_ALIGNMENT_EXCEPTION
								dmem_alignment_exception |
`endif
`ifdef ENABLE_OPCODE_EXCEPTION
								opcode_exception |
`endif
								0;
`endif
 
`ifdef ENABLE_INTERRUPTS
// this code is to signal an interrupt when interrupts are enabled (MSR[IE]=1)
reg	int_requested;
always @(interrupt or MSR[`MSR_IE])				// if interrupt == 1, then raise a request for
begin														// clear the request based on clear_interrupt
  if(interrupt && MSR[`MSR_IE])	int_requested <= 1;
  else if(!MSR[`MSR_IE]) 			int_requested <= 0;
end
 
reg	 int_ip;											// interrupt in progress
wire	 can_interrupt  = 							// cpu can be interrupted if...
`ifdef ENABLE_EXCEPTION
						   ~MSR[`MSR_EIP] &			// no Exception in Progress
`endif
`ifdef ENABLE_MSR_BIP
							~MSR[`MSR_BIP] & 			// no Break in Progress
`endif
							(~int_ip | set_msr_ie);	// not interrupt in progress 
`endif													// and interrupts are enabled
 
assign branch_taken  = branch_instr ? compare_out : 0;
assign pc_branch     = alu_out_internal[`A_SPACE+1:0];	// ALU calculates next instr address
 
// instr_complete is always high EXCEPT for optional MUL (alu_multicycle_instr)
// all other instructions currently implemented are single-cycle execution except
// load / store that are multicycle (controlled by dmem_done)
// also re/we enable are only valid if EXECUTE is not stalled
assign dmem_we							= we_store & ~stall;
assign dmem_re							= we_load  & ~stall;
 
assign memory_instr					= we_load | we_store;
assign memory_instr_complete		= memory_instr & dmem_done;
 
assign multicycle_instr 			= 
`ifdef FSL_LINK
												fsl_cmd_vld |
`endif
												memory_instr | alu_multicycle_instr;
assign multicycle_instr_complete = 
`ifdef FSL_LINK
												fsl_complete |
`endif
												memory_instr_complete | alu_multicycle_instr_complete;
 
assign instr_complete 				= ~multicycle_instr | multicycle_instr_complete;
assign we_regfile 					= (we_load & dmem_done) | alu_multicycle_instr_complete;
 
// for CMP/CMPU
// use comparator output for CMPU
// use ALU output for CMP -- signed comparison result is a function of input signs and output sign
assign alu_result[31] = (alu_fns_sel == `ALU_compare_uns) ? compare_out :
			(alu_fns_sel == `ALU_compare) ?  MSB_signed_compare :
			alu_out_internal[31];
assign alu_result[30:0] = alu_out_internal[30:0];
 
always@(regA[31] or regB[31] or alu_out_internal[31])
begin
	case ({regB[31], regA[31]})	// look at signs of input numbers
	2'b00: MSB_signed_compare <= alu_out_internal[31];	// both inputs positive
	2'b01: MSB_signed_compare <= 0;			// A is negative, B is positive => B is greater
	2'b10: MSB_signed_compare <= 1;			// B is negative, A is positive => A is greater
	2'b11: MSB_signed_compare <= alu_out_internal[31];	// both inputs negative
	endcase
end
 
// extend PC to datapath width to store in Reg File
assign extended_pc[31:`A_SPACE+2] = 0;
assign extended_pc[`A_SPACE+1:0]  = pc_exe;
 
// Stateful logic to handle multi-cycle instructions
always@(posedge clock)
begin
	if(reset)
		begin
			MSR[`MSR_C]		<= 0;		// Carry
`ifdef ENABLE_INTERRUPTS
		   int_ip			<= 0;
			MSR[`MSR_IE]	<= 1;		// Interrupt Enable
`endif
`ifdef ENABLE_EXCEPTIONS
			insert_exception <= 0;
			MSR[`MSR_E_Ena]  <= 1;	// Enable Exceptions
			MSR[`MSR_EIP]	  <= 0;	// Exception in Progress
`endif
`ifdef ENABLE_MSR_BIP
		   MSR[`MSR_BIP`]	  <= 0;	// Break In Progress
`endif
`ifdef	FSL_LINK
			fsl_complete	<= 0;
			fsl_m_write 	<= 0;
			fsl_s_read		<= 0;			
`endif
		end
	else if (~stall)
		begin
			// Update MSR[BIP] due to BREAK / RTBD
`ifdef ENABLE_MSR_BIP
			if(update_msr_bip) MSR[`MSR_BIP] 	<= value_msr_bip;
`endif
`ifdef ENABLE_INTERRUPTS
			if(int_requested & can_interrupt)	// interrupt requested and cpu can be interrupted?
			begin
			   MSR[`MSR_IE] <= 0;			// disable further interrupts
				int_ip		 <= 1;			// ask DECODE to insert "brali r14,0x10" asap
			end
			else if(int_ip & int_dc)		// if DECODE completed the instruction insert
			   int_ip 		 <= 0;			// finish interrupt in progress
			if(set_msr_ie) MSR[`MSR_IE] <= 1;		// decode asks to enable interrupts again
`endif
`ifdef ENABLE_EXCEPTIONS
			/* TODO: exceptions handling ---
					r17 		<- PC
					PC			<- 0x20
					MSR[EE] 	<- 0
					MSR[EIP] <- 1
					ESR[DS]	<- exception in delay slot
					ESR[EC]  <- exception specific value
					ESR[ESS] <- exception specific value
					EAR 		<- exception specific value
					FSR 		<- exception specific value
			*/
			if(reset_msr_eip)			// return from an exception handler
			begin
			 MSR[`MSR_EIP] 	<= 0;	// disable EIP flag due to rted opcode
			 MSR[`MSR_E_Ena] 	<= 1;	// enable exceptions agains
			 // ESR <- 0				// reset exception cause
			end
`endif
			`ifdef ENABLE_MSR_OPCODES
			if(rS_update) MSR <= regA;	// mts instruction
			`endif
			// Update Carry Bit in Status Register
			if ((alu_fns_sel == `ALU_add) & update_carry)
				MSR[`MSR_C]	<= c_out;			
			if ((alu_fns_sel == `ALU_shiftR_arth) | (alu_fns_sel == `ALU_shiftR_log) | 
				(alu_fns_sel == `ALU_shiftR_c))
				MSR[`MSR_C]	<= regA[0];
`ifdef FSL_LINK
			// FSL get & put commands
			// Reset control signals after write / read
			if ((fsl_cmd_vld & fsl_complete) | ~fsl_cmd_vld)
				begin
					fsl_s_read		<= 0;
					fsl_complete	<= 0;
					fsl_m_write		<= 0;
				end
			else if (fsl_cmd_vld & ~fsl_get & ~fsl_blocking) // nonblocking put
				begin
					fsl_complete 	<= 1;
					MSR[`MSR_C]		<= fsl_m_full;		//**CHECK**
					if (~fsl_m_full)
						begin
							fsl_m_write 	<= 1;
							fsl_m_control 	<= fsl_control;
						end
				end
			else if (fsl_cmd_vld & fsl_get & ~fsl_blocking) // nonblocking get
				begin
					fsl_complete 	<= 1;
					fsl_s_read 	<= 1;
					MSR[`MSR_C] <= ~fsl_s_exists;		//**CHECK**
					if (fsl_s_exists)
						we_load_dly <= 1;
					if (fsl_s_control == fsl_control)
						MSR[`MSR_FSL_Err]	<= 0;	// MSR[4] = FSL_Error bit
					else
						MSR[`MSR_FSL_Err]	<= 1;
				end
			else if (fsl_cmd_vld & ~fsl_get & ~fsl_m_full & fsl_blocking) // blocking put
				begin
					fsl_complete 	<= 1;
					fsl_m_write 	<= 1;
					fsl_m_control 	<= fsl_control;
				end
			else if (fsl_cmd_vld & fsl_get & fsl_s_exists & fsl_blocking) // blocking get
				begin
					fsl_complete 	<= 1;
					we_load_dly 	<= 1;
					fsl_s_read	<= 1;
					if (fsl_s_control == fsl_control)
						MSR[`MSR_FSL_Err]	<= 0;
					else
						MSR[`MSR_FSL_Err]	<= 1;
				end
`endif // End FSL extensions				
`ifdef DEBUG_EXECUTE
		$display("EXECUTE: pc_exe=%x", pc_exe);
`endif
		end // end elseif (~stall)
end // always@
 
/**************************
 * Module input selectors *
 **************************/
always@(
`ifdef ENABLE_MSR_OPCODES
	MSR or
`endif
	alu_inputA_sel or extended_pc or regA
)
begin
	case(alu_inputA_sel)
	`aluA_ra:		alu_a_input <= regA;
	`aluA_ra_bar:	alu_a_input <= ~regA;
	`aluA_pc:		alu_a_input <= extended_pc;
	`aluA_zero:		alu_a_input <= 0;
`ifdef ENABLE_MSR_OPCODES
	`aluA_msr:		alu_a_input	<= MSR;	// msr instruction feed to regfile via ALU
`endif
	endcase
end // always @ ALU_input_A
 
always@(alu_inputB_sel or immediate or regB)
begin
	case(alu_inputB_sel)
	`aluB_rb:		alu_b_input <= regB;
	`aluB_imm:		alu_b_input <= immediate;
	`aluB_rb_bar:	alu_b_input <= ~regB;
	`aluB_imm_bar:	alu_b_input <= ~immediate;
	endcase
end // always @ ALU_input_B
 
always@(alu_inputC_sel or MSR)
begin
	case(alu_inputC_sel)
	`aluC_zero:		alu_c_input <= 1'b0;
	`aluC_one:		alu_c_input <= 1'b1;
	`aluC_carry:	alu_c_input <= MSR[`MSR_C];
	default:	
		begin	// for simulation
			$display("ERROR! Illegal ALU Input Selection! PC %x", pc_exe);
			alu_c_input <= 1'b0;
		end
	endcase
end // always @ ALU_input_C
 
// Instantiate ALU and comparator
openfire_alu	ALU0 (
	.clock(clock), 
	.reset(reset), 
	.stall(stall),
	.a(alu_a_input), 
	.b(alu_b_input), 
	.c_in(alu_c_input), 
	.fns(alu_fns_sel),
	.alu_result(alu_out_internal), 
	.c_out(c_out),
	.alu_multicycle_instr(alu_multicycle_instr), 
	.dmem_addr(dmem_addr),
	.alu_multicycle_instr_complete(alu_multicycle_instr_complete)
);
// comparator used only for branches (and optional CMPU instruction)
// DECODE unit forces COMPARE output high for unconditional branchs by selecting a 1 output
//	with comparator_fns_sel
openfire_compare	CMP0 (
	.in0(regA), 
	.in1(regB), 
	.out(compare_out), 
	.fns(comparator_fns_sel)
);
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.