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

Subversion Repositories aemb

[/] [aemb/] [branches/] [DEV_SYBREON/] [rtl/] [verilog/] [aeMB2_aslu.v] - Rev 80

Go to most recent revision | Compare with Previous | Blame | View Log

/* $Id: aeMB2_aslu.v,v 1.2 2007-12-12 19:16:59 sybreon Exp $
**
** AEMB2 INTEGER ARITHMETIC SHIFT LOGIC UNIT
** 
** Copyright (C) 2004-2007 Shawn Tan Ser Ngiap <shawn.tan@aeste.net>
**  
** This file is part of AEMB.
**
** AEMB is free software: you can redistribute it and/or modify it
** under the terms of the GNU Lesser General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** AEMB is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
** or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
** Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with AEMB. If not, see <http://www.gnu.org/licenses/>.
*/
 
module aeMB2_aslu (/*AUTOARG*/
   // Outputs
   dwb_adr_o, dwb_sel_o, rSEL_MA, cwb_adr_o, cwb_tga_o, cwb_sel_o,
   rMUL_MA, rRES_MA, rRES_EX, rMSR_IE, rMSR_BE, rMSR_TXE, rMSR_BIP,
   // Inputs
   rIMM_OF, rALU_OF, rOPC_OF, rOPC_IF, rRA_OF, rRD_OF, rOPA_OF,
   rOPB_OF, pha_i, clk_i, rst_i, ena_i
   );
 
   parameter DWB = 32;
   parameter TXE = 1;
 
   parameter MUL = 0;
   parameter BSF = 1;
   parameter FSL = 1;   
 
   // DWB
   output [DWB-1:2] dwb_adr_o;
   output [3:0]     dwb_sel_o;
   output [3:0]     rSEL_MA;   
 
   // FSL
   output [6:2]     cwb_adr_o;
   output [1:0]     cwb_tga_o;
   output [3:0]     cwb_sel_o;   
 
   // PIPELINE
   output [31:0]    rMUL_MA;   
   output [31:0]    rRES_MA,
		    rRES_EX;   
 
   output 	    rMSR_IE,
		    rMSR_BE,
		    rMSR_TXE,
		    rMSR_BIP;
 
   input [15:0]     rIMM_OF;   
   input [2:0] 	    rALU_OF;   
   input [5:0] 	    rOPC_OF,
		    rOPC_IF;
 
   input [4:0] 	    rRA_OF,
		    rRD_OF;
 
   input [31:0]     rOPA_OF, // RA, PC
		    rOPB_OF; // RB, IMM
 
   // SYSTEM
   input 	    pha_i,
		    clk_i,
		    rst_i,
		    ena_i;
 
   /*AUTOREG*/
   // Beginning of automatic regs (for this module's undeclared outputs)
   reg [6:2]		cwb_adr_o;
   reg [3:0]		cwb_sel_o;
   reg [1:0]		cwb_tga_o;
   reg [DWB-1:2]	dwb_adr_o;
   reg [3:0]		dwb_sel_o;
   reg			rMSR_BE;
   reg			rMSR_BIP;
   reg			rMSR_IE;
   reg			rMSR_TXE;
   reg [31:0]		rMUL_MA;
   reg [31:0]		rRES_EX;
   reg [31:0]		rRES_MA;
   reg [3:0]		rSEL_MA;
   // End of automatics
 
   reg 			rMSR_C0, 
			rMSR_C1, 
			rMSR_CL[0:1];
 
 
   wire [4:0] 		rRD = rRD_OF;   
   wire [31:0] 		rOPA = rOPA_OF;
   wire [31:0] 		rOPB = rOPB_OF;   
   wire [5:0] 		rOPC = rOPC_OF;
   wire [4:0] 		rRA = rRA_OF;   
   wire [15:0] 		rIMM = rIMM_OF;
   wire [10:0] 		rALT = rIMM_OF[10:0];
 
   /*
    C SELECTOR 
 
    Preselects the C in the OF stage to speed things up.  */
 
   // TODO: Optimise
 
   wire 		wMSR_CX, wMSR_C;   
   assign 		wMSR_CX = (pha_i) ? rMSR_C0 : 
				  (TXE) ? rMSR_C1 : 1'bX;
 
   assign 		wMSR_C = (rOPC_IF == 6'o44) & wMSR_CX | // SRX
				 (rOPC_IF[5:4] == 2'o0) & rOPC_IF[1] & wMSR_CX | // ADDC/RSUBC
				 (rOPC_IF[5:4] == 2'o0) & (rOPC_IF[1:0] == 2'o1); // RSUB
 
   reg 			rMSR_C;
 
   always @(posedge clk_i)
     if (rst_i) begin
	/*AUTORESET*/
	// Beginning of autoreset for uninitialized flops
	rMSR_C <= 1'h0;
	// End of automatics
     end else if (ena_i) begin
	rMSR_C <= #1 wMSR_C;	
     end
 
   /* 
    ADD/SUB SELECTOR
 
    Current implementation is a clutz. It needs to be
    re-implemented. It is also in the critical path.  */
 
   // FIXME: Redesign
   // TODO: Verify signed compare   
 
   wire 		wADDC, wSUBC, wRES_AC, wCMPC, wOPC;
   wire [31:0] 		wADD, wSUB, wRES_A, wCMP, wOPX;
 
   wire 		wCMPU = (rOPA > rOPB);         
   wire 		wCMPF = (rIMM[1]) ? wCMPU :
			((wCMPU & ~(rOPB[31] ^ rOPA[31])) | (rOPB[31] & ~rOPA[31]));
 
   assign 		{wCMPC,wCMP} = {wSUBC,wCMPF,wSUB[30:0]};  
   assign 		wOPX = (rOPC[0] & !rOPC[5]) ? ~rOPA : rOPA ;
   //assign 		wOPC = ((wMSR_C & rOPC[1]) | (rOPC[0] & !rOPC[1])) & (!rOPC[5] & ~&rOPC[5:4]);
   assign 		wOPC = rMSR_C;   
 
   assign 		{wSUBC,wSUB} = {wADDC,wADD}; 
   assign 		{wADDC,wADD} = (rOPB + wOPX) + wOPC; 
 
   reg 			rRES_ADDC;
   reg [31:0] 		rRES_ADD;
   always @(rIMM or rOPC or wADD or wADDC or wCMP
	    or wCMPC or wSUB or wSUBC)
     case ({rOPC[3],rOPC[0],rIMM[0]})
       4'h2, 4'h6, 4'h7: {rRES_ADDC,rRES_ADD} <= #1 {~wSUBC,wSUB}; // SUB
       4'h3: {rRES_ADDC,rRES_ADD} <= #1 {~wCMPC,wCMP}; // CMP
       default: {rRES_ADDC,rRES_ADD} <= #1 {wADDC,wADD};       
     endcase // case ({rOPC[3],rOPC[0],rIMM[0]})
 
   /* 
    LOGIC
 
    This can be combined with the shifter below.
    */
 
   reg [31:0] 		rRES_LOG;
   always @(/*AUTOSENSE*/rOPA or rOPB or rOPC)
     case (rOPC[2:0])
       2'o0: rRES_LOG <= #1 rOPA | rOPB;
       2'o1: rRES_LOG <= #1 rOPA & rOPB;
       2'o2: rRES_LOG <= #1 rOPA ^ rOPB;
       2'o3: rRES_LOG <= #1 rOPA & ~rOPB;
     endcase // case (rOPC[2:0])
 
   /* 
    SIMPLE SHIFTER
 
    Implemented as wiring and registers.
    */
 
   reg [31:0] 		rRES_SFT;
   reg 			rRES_SFTC;
 
   always @(/*AUTOSENSE*/rIMM or rMSR_C or rOPA)
     case (rIMM[6:5])
       2'o0: rRES_SFT <= {rOPA[31],rOPA[31:1]}; // SRA
       2'o1: rRES_SFT <= {rMSR_C,rOPA[31:1]}; // SRC
       2'o2: rRES_SFT <= {1'b0,rOPA[31:1]}; // SRL
       2'o3: rRES_SFT <= (rIMM[0]) ? 
			 {{(16){rOPA[15]}}, rOPA[15:0]} : // SEXT16
			 {{(24){rOPA[7]}}, rOPA[7:0]}; // SEXT8
     endcase // case (rIMM[6:5])
 
   always @(/*AUTOSENSE*/rIMM or rMSR_C or rOPA)
     rRES_SFTC <= (&rIMM[6:5]) ? rMSR_C : rOPA[0];
 
   /*
    MOVE FROM SPECIAL
 
    MSR bits
    31 - CC (carry copy)
    30 - PHA (current phase)
    29 - TXE (enable second thread)
 
     3 - BIP (break in progress)
     2 - C (carry flag)
     1 - IE (interrupt enable)
     0 - BE (bus-lock enable)    
    */
 
   wire 		wTXE = (TXE) ? 1'b1 : 1'b0;
   wire [31:0] 		wMSR = {rMSR_C, // MSR_CC		
				pha_i, // Current phase
				rMSR_TXE, // Thread Execution Enabled
				wTXE,
				4'h0, // Reserved
				8'hAE, // Vendor
				8'h32, // Version
				4'h0, // Reserved
				rMSR_BIP, // MSR_BIP
				rMSR_C, // MSR_C
				rMSR_IE, // MSR_IE
				rMSR_BE}; // MSR_BE
 
   wire 		fMFSR = (rOPC == 6'o45) & !rIMM[14] & rIMM[0];
   wire 		fMFPC = (rOPC == 6'o45) & !rIMM[14] & !rIMM[0];
   reg [31:0] 		rRES_MOV;
   always @(/*AUTOSENSE*/fMFSR or rOPA or rOPB or rRA or wMSR)
     rRES_MOV <= (fMFSR) ? wMSR :
		 //(fMFPC) ? rOPA :
		 (rRA[3]) ? rOPB : 
		 rOPA;   
 
   /* 
    MULTIPLIER
 
    Implemented as a 2-stage multiplier in order to increase clock
    speed. */
 
   reg [31:0] 	    rRES_MUL;
   always @(posedge clk_i) begin
      rMUL_MA <= (MUL) ? rRES_MUL : 32'hX;      
      rRES_MUL <= (MUL) ? (rOPA * rOPB) : 32'hX;
   end
 
   /* 
    BARREL SHIFTER
 
    This can be potentially made 2-stage to increase clock
    speed. Doesn't seem necessary at the moment as the critical path
    runs through the adder. */
 
   reg [31:0] 	 rRES_BSF;
   reg [31:0] 	 xBSRL, xBSRA, xBSLL;
 
   /* logical left barrel shifter */
   always @(/*AUTOSENSE*/rOPA or rOPB)
     xBSLL <= rOPA << rOPB[4:0];
 
   /* logical right barrel shifter */
   always @(/*AUTOSENSE*/rOPA or rOPB)
     xBSRL <= rOPA >> rOPB[4:0];
 
   /* arithmetic right barrel shifter */
   always @(/*AUTOSENSE*/rOPA or rOPB)
     case (rOPB[4:0])
       5'd00: xBSRA <= rOPA;
       5'd01: xBSRA <= {{(1){rOPA[31]}}, rOPA[31:1]};
       5'd02: xBSRA <= {{(2){rOPA[31]}}, rOPA[31:2]};
       5'd03: xBSRA <= {{(3){rOPA[31]}}, rOPA[31:3]};
       5'd04: xBSRA <= {{(4){rOPA[31]}}, rOPA[31:4]};
       5'd05: xBSRA <= {{(5){rOPA[31]}}, rOPA[31:5]};
       5'd06: xBSRA <= {{(6){rOPA[31]}}, rOPA[31:6]};
       5'd07: xBSRA <= {{(7){rOPA[31]}}, rOPA[31:7]};
       5'd08: xBSRA <= {{(8){rOPA[31]}}, rOPA[31:8]};
       5'd09: xBSRA <= {{(9){rOPA[31]}}, rOPA[31:9]};
       5'd10: xBSRA <= {{(10){rOPA[31]}}, rOPA[31:10]};
       5'd11: xBSRA <= {{(11){rOPA[31]}}, rOPA[31:11]};
       5'd12: xBSRA <= {{(12){rOPA[31]}}, rOPA[31:12]};
       5'd13: xBSRA <= {{(13){rOPA[31]}}, rOPA[31:13]};
       5'd14: xBSRA <= {{(14){rOPA[31]}}, rOPA[31:14]};
       5'd15: xBSRA <= {{(15){rOPA[31]}}, rOPA[31:15]};
       5'd16: xBSRA <= {{(16){rOPA[31]}}, rOPA[31:16]};
       5'd17: xBSRA <= {{(17){rOPA[31]}}, rOPA[31:17]};
       5'd18: xBSRA <= {{(18){rOPA[31]}}, rOPA[31:18]};
       5'd19: xBSRA <= {{(19){rOPA[31]}}, rOPA[31:19]};
       5'd20: xBSRA <= {{(20){rOPA[31]}}, rOPA[31:20]};
       5'd21: xBSRA <= {{(21){rOPA[31]}}, rOPA[31:21]};
       5'd22: xBSRA <= {{(22){rOPA[31]}}, rOPA[31:22]};
       5'd23: xBSRA <= {{(23){rOPA[31]}}, rOPA[31:23]};
       5'd24: xBSRA <= {{(24){rOPA[31]}}, rOPA[31:24]};
       5'd25: xBSRA <= {{(25){rOPA[31]}}, rOPA[31:25]};
       5'd26: xBSRA <= {{(26){rOPA[31]}}, rOPA[31:26]};
       5'd27: xBSRA <= {{(27){rOPA[31]}}, rOPA[31:27]};
       5'd28: xBSRA <= {{(28){rOPA[31]}}, rOPA[31:28]};
       5'd29: xBSRA <= {{(29){rOPA[31]}}, rOPA[31:29]};
       5'd30: xBSRA <= {{(30){rOPA[31]}}, rOPA[31:30]};
       5'd31: xBSRA <= {{(31){rOPA[31]}}, rOPA[31]};
     endcase // case (rOPB[4:0])
 
   /* select the shift result (2nd stage) */
   always @(/*AUTOSENSE*/rALT or xBSLL or xBSRA or xBSRL)
     case (rALT[10:9])
       2'd0: rRES_BSF <= xBSRL;
       2'd1: rRES_BSF <= xBSRA;       
       2'd2: rRES_BSF <= xBSLL;
       default: rRES_BSF <= 32'hX;       
     endcase // case (rALT[10:9])
 
 
   /*
    MSR REGISTER
 
    Move data to the MSR or change due to break/returns. */
 
   reg 		 xMSR_C;
 
   // C
   wire 	 fMTS = (rOPC == 6'o45) & rIMM[14];
   wire 	 fADDC = ({rOPC[5:4], rOPC[2]} == 3'o0);
 
   always @(/*AUTOSENSE*/fADDC or fMTS or rALU_OF or rMSR_C or rOPA
	    or rRES_ADDC or rRES_SFTC)
     case (rALU_OF)
       3'o0: xMSR_C <= (fADDC) ? rRES_ADDC : rMSR_C;	 
       3'o1: xMSR_C <= rMSR_C; // LOGIC       
       3'o2: xMSR_C <= rRES_SFTC; // SHIFT
       3'o3: xMSR_C <= (fMTS) ? rOPA[2] : rMSR_C;
       3'o4: xMSR_C <= rMSR_C;	 
       3'o5: xMSR_C <= rMSR_C;	 
       default: xMSR_C <= 1'hX;       
     endcase // case (rALU_OF)
 
   always @(posedge clk_i)
     if (rst_i) begin
	/*AUTORESET*/
	// Beginning of autoreset for uninitialized flops
	rMSR_C0 <= 1'h0;
	rMSR_C1 <= 1'h0;
	// End of automatics
     end else begin
	if (pha_i & ena_i & rMSR_TXE)
	  rMSR_C1 <= #1 xMSR_C;
 
	if (!pha_i & ena_i)
	  rMSR_C0 <= #1 xMSR_C;	
     end // else: !if(rst_i)
 
   // IE/BIP/BE
   wire 	    fRTID = (rOPC == 6'o55) & rRD[0];   
   wire 	    fRTBD = (rOPC == 6'o55) & rRD[1];
   wire 	    fBRK = ((rOPC == 6'o56) | (rOPC == 6'o66)) & (rRA == 5'hC);
   wire 	    fINT = ((rOPC == 6'o56) | (rOPC == 6'o66)) & (rRA == 5'hE);
 
   always @(posedge clk_i)
     if (rst_i) begin
	/*AUTORESET*/
	// Beginning of autoreset for uninitialized flops
	rMSR_BE <= 1'h0;
	rMSR_BIP <= 1'h0;
	rMSR_IE <= 1'h0;
	rMSR_TXE <= 1'h0;
	// End of automatics
     end else if (ena_i) begin
 
	// Interrupt enable (compatible)
	rMSR_IE <= #1
		   (fINT) ? 1'b0 :
		   (fRTID) ? 1'b1 : 
		   (fMTS) ? rOPA[1] :
		   rMSR_IE;
 
	// Break in progress (compatible)
	rMSR_BIP <= #1
		    (fBRK) ? 1'b1 :
		    (fRTBD) ? 1'b0 : 
		    (fMTS) ? rOPA[3] :
		    rMSR_BIP;
 
	// Forcibly assert dwb_cyc_o signal	
	rMSR_BE <= #1
		   (fMTS) ? rOPA[0] : rMSR_BE;
 
	// Enable the thread extension
	rMSR_TXE <= #1
		    (fMTS) ? rOPA[28] & TXE : rMSR_TXE;
 
     end // if (ena_i)
 
   /*
    RESULTS
    */
 
   // RESULT   
   always @(posedge clk_i)
     if (rst_i) begin
	/*AUTORESET*/
	// Beginning of autoreset for uninitialized flops
	rRES_EX <= 32'h0;
	rRES_MA <= 32'h0;
	// End of automatics
     end else if (ena_i) begin
	rRES_MA <= #1 rRES_EX;
	case (rALU_OF)
	  3'o0: rRES_EX <= #1 rRES_ADD;
	  3'o1: rRES_EX <= #1 rRES_LOG;
	  3'o2: rRES_EX <= #1 rRES_SFT;
	  3'o3: rRES_EX <= #1 rRES_MOV;
	  //3'o4: rRES_EX <= (MUL) ? rRES_MUL : 32'hX;	 
	  3'o5: rRES_EX <= #1 (BSF) ? rRES_BSF : 32'hX;	 
	  default: rRES_EX <= #1 32'hX;	  
	endcase // case (rALU_OF)
     end // if (ena_i)
 
   /*
    DATA/FSL WISHBONE
 
    Asserts the data address as calculated by the adder and the
    appropriate byte select lanes depending on the byte offset of the
    address. It does not check for mis-aligned addresses.  */
 
   // TODO: Check for mis-alignment
 
   always @(posedge clk_i)
     if (rst_i) begin
	/*AUTORESET*/
	// Beginning of autoreset for uninitialized flops
	cwb_adr_o <= 5'h0;
	cwb_sel_o <= 4'h0;
	cwb_tga_o <= 2'h0;
	dwb_adr_o <= {(1+(DWB-1)-(2)){1'b0}};
	dwb_sel_o <= 4'h0;
	rSEL_MA <= 4'h0;
	// End of automatics
     end else if (ena_i) begin // if (rst_i)
	rSEL_MA <= #1 dwb_sel_o;	
 
	dwb_adr_o <= #1 wADD[DWB-1:2];	
	case (rOPC[1:0])
	  2'o0: case (wADD[1:0]) // 8'bit
		  2'o0: dwb_sel_o <= #1 4'h8;	       
		  2'o1: dwb_sel_o <= #1 4'h4;	       
		  2'o2: dwb_sel_o <= #1 4'h2;	       
		  2'o3: dwb_sel_o <= #1 4'h1;	       
		endcase // case (wADD[1:0])
	  2'o1: dwb_sel_o <= #1 (wADD[1]) ? 4'h3 : 4'hC; // 16'bit
	  2'o2: dwb_sel_o <= #1 4'hF; // 32'bit
	  2'o3: dwb_sel_o <= #1 4'h0; // FSL
	endcase // case (rOPC[1:0])
 
	{cwb_adr_o, cwb_tga_o} <= #1 {rIMM_OF[4:0], rIMM_OF[15:14]};
	cwb_sel_o <= #1 {(4){ &rOPC[1:0]}};	
 
     end // if (ena_i)
 
 
   // synopsys translate_off
   integer r;   
   initial begin
      for (r=0; r<TXE; r=r+1) begin
	 rMSR_CL[r] <= $random;
      end
   end
   // synopsys translate_on
 
endmodule // aeMB2_aslu
 
/* $Log: not supported by cvs2svn $
/* Revision 1.1  2007/12/11 00:43:17  sybreon
/* initial import
/* */

Go to most recent revision | 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.