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

Subversion Repositories theia_gpu

[/] [theia_gpu/] [tags/] [Beta_0.2/] [rtl/] [EXE/] [Module_InstructionFetch.v] - Diff between revs 23 and 60

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 23 Rev 60
Line 17... Line 17...
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 
***********************************************************************************/
***********************************************************************************/
 
/**********************************************************************************
`define IFU_AFTER_RESET                         0
Description:
`define IFU_INITIAL_STATE                                       1
 This is the instruction fetch unit.
`define IFU_WAIT_FOR_LAST_INSTRUCTION_LATCHED_BY_IDU                                            2
 It gets the next instruction from the IMEM module at the MEM unit.
`define IFU_STALLED             3
 It increments the instruction pointer (IP) in such a way that EXE has always
`define IFU_FETCH_NEXT                          4
 one instruction per clock cycle (best pipeline performance). In order to achieve this,
`define FU_WAIT_FOR_EXE_UNIT            5
 IFU has 2 instruction pointers, so that in case of 'branch' instructions,
`define IFU_DONE                                                6
 two instructions pointer are generated and two different instructions are simultaneously
`define IFU_CHECK_FOR_JUMP_PENDING                      7
 fetched from IMEM: the branch-taken and branch-not-taken instructions, so that once the
 
 branch outcome is calculted in EXE, both possible outcomes are already pre-fetched.
 
**********************************************************************************/
`define IP_SET_VALUE_INITIAL_ADDRESS 0
module InstructionFetch
`define IP_SET_VALUE_BRANCH_ADDRESS 1
 
 
 
//-----------------------------------------------------------------------------
 
module InstructionFetchUnit
 
(
(
        input wire                                                                              Clock,
        input wire                                                                              Clock,
        input wire                                                                              Reset,
        input wire                                                                              Reset,
        input   wire                                                                            iBranchTaken,
 
        input wire                                                                              iBranchNotTaken,
 
        input wire[`ROM_ADDRESS_WIDTH-1:0]               iJumpIp,
 
        input   wire                                                                            iTrigger,
        input   wire                                                                            iTrigger,
        input   wire                                                                            iIDUBusy,
 
        input   wire                                                                            iExeBusy,
 
        input wire[`INSTRUCTION_WIDTH-1:0]               iEncodedInstruction,
 
        input wire[`ROM_ADDRESS_WIDTH-1:0]               iInitialCodeAddress,
        input wire[`ROM_ADDRESS_WIDTH-1:0]               iInitialCodeAddress,
        input wire                                                                              iDecodeUnitLatchedValues,
input wire[`INSTRUCTION_WIDTH-1:0]               iInstruction1,                  //Branch not taken instruction
        output reg                                                                              oExecutionDone,
input wire[`INSTRUCTION_WIDTH-1:0]               iInstruction2,                  //Branch taken instruction
        output wire                                                                             oMicroCodeReturnValue,
input   wire                                                                            iBranchTaken,
        output wire                                                                             oInstructionAvalable,
        output wire                                                                             oInstructionAvalable,
        output wire [`ROM_ADDRESS_WIDTH-1:0]     oInstructionPointer,
output wire [`ROM_ADDRESS_WIDTH-1:0]     oIP,
        output wire[`INSTRUCTION_WIDTH-1:0]              oCurrentInstruction
output wire [`ROM_ADDRESS_WIDTH-1:0]     oIP2, //calcule both decide later
 
output wire[`INSTRUCTION_WIDTH-1:0]              oCurrentInstruction,
 
input wire                             iEXEDone,
 
output wire                                                                             oMicroCodeReturnValue,
 
output wire                            oExecutionDone
);
);
 
`define INSTRUCTION_OPCODE oCurrentInstruction[`INSTRUCTION_WIDTH-1:`INSTRUCTION_WIDTH-`INSTRUCTION_OP_LENGTH]
 
//iInstruction1[`INSTRUCTION_WIDTH-1:`INSTRUCTION_WIDTH-`INSTRUCTION_OP_LENGTH]
 
 
//Alling the Jump Signal to the negedge of Clock,
assign oMicroCodeReturnValue = oCurrentInstruction[0];
//I do this because I finded out the simulator
assign oIP2 = oCurrentInstruction[47:32];//iInstruction1[47:32];
//behaves funny if you change a value at the edge
 
//of the clock and read from a bus that has changed
 
wire rJumpNow;
 
 
 
assign oCurrentInstruction = iEncodedInstruction;
 
 
 
assign oMicroCodeReturnValue = iEncodedInstruction[0];
 
 
 
wire [`ROM_ADDRESS_WIDTH-1:0] wInstructionPointer;
 
reg rEnable;
 
 
 
assign oInstructionPointer = wInstructionPointer;
 
 
 
reg rPreviousInstructionIsJump;
 
 
 
`define INSTRUCTION_OPCODE iEncodedInstruction[`INSTRUCTION_WIDTH-1:`INSTRUCTION_WIDTH-`INSTRUCTION_OP_LENGTH]
wire wTriggerDelay1,wTriggerDelay2,wIncrementIP_Delay1,wIncrementIP_Delay2,
 
wLastInst_Delay1,wLastInst_Delay2;
 
wire wIncrementIP,wLastInstruction;
 
 
wire wLastInstruction;
 
assign wLastInstruction =
 
(`INSTRUCTION_OPCODE == 0) ? 1'b1 : 1'b0;
 
 
 
wire rInstructionAvalable;
assign wLastInstruction = (`INSTRUCTION_OPCODE == `RETURN);
assign rInstructionAvalable = (iTrigger || iDecodeUnitLatchedValues) && rEnable;
 
 
 
 
//Increment IP 2 cycles after trigger or everytime EXE is done, but stop if we get to the RETURN
 
assign wIncrementIP =  wTriggerDelay2 | (iEXEDone & ~wLastInstruction);
 
//It takes 1 clock cycle to read the instruction back from IMEM
 
assign oInstructionAvalable = wTriggerDelay2 | (iEXEDone & ~wLastInst_Delay2);
 
//Once we reach the last instruction, wait until EXE says he is done, then assert oExecutionDone
 
assign oExecutionDone = (wLastInstruction & iEXEDone);
 
 
//if it is jump delay 1 cycle
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD2
wire wInstructionAvalableDelayed_1Cycle;
 
wire wInstructionAvalableDelayed_2Cycle;
 
wire wInstructionAvalableDelayed_3Cycle;
 
wire wInstructionAvalableDelayed_4Cycle;
 
wire wJumpNow_Delayed_1Cycle,wJumpNow_Delayed_2Cycle,wJumpNow_Delayed_3Cycle;
 
 
 
 
 
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelayJump
 
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( rJumpNow ),
        .Enable(1'b1),
        .Q( wJumpNow_Delayed_1Cycle )
        .D( iTrigger ),
);
        .Q( wTriggerDelay1 )
 
 
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelayJump2
 
(
 
        .Clock( Clock ),
 
        .Clear( Reset ),
 
        .D( wJumpNow_Delayed_1Cycle ),
 
        .Q( wJumpNow_Delayed_2Cycle )
 
);
);
 
 
 
 
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelayJump3
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD3
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( wJumpNow_Delayed_2Cycle ),
        .Enable(1'b1),
        .Q( wJumpNow_Delayed_3Cycle )
        .D( wTriggerDelay1 ),
 
        .Q( wTriggerDelay2 )
);
);
 
 
 
 
 
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD4
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelay1
 
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( rInstructionAvalable ),
        .Enable(wLastInstruction),
        .Q( wInstructionAvalableDelayed_1Cycle )
        .D( oInstructionAvalable ),
 
        .Q( wLastInst_Delay1 )
);
);
 
 
 
 
 
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD5
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelay2
 
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( wInstructionAvalableDelayed_1Cycle ),
        .Enable(wLastInstruction),
        .Q( wInstructionAvalableDelayed_2Cycle )
        .D( wLastInst_Delay1 ),
 
        .Q( wLastInst_Delay2 )
);
);
 
 
 
wire [`ROM_ADDRESS_WIDTH-1:0] oIP2_Next;
 
 
 
/*
 
In case the branch is taken:
 
We point current instruction into the iInstruction2 (branch-taken) instruction
 
that corresponds to oIP2.
 
Then, in the next clock cycle we should use the oIP2 incremented by one,
 
so we need to load UPCOUNTER_POSEDGE with oIP2+1
 
*/
 
 
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelay3
 
(
 
        .Clock( Clock ),
 
        .Clear( Reset ),
 
        .D( wInstructionAvalableDelayed_2Cycle ),
 
        .Q( wInstructionAvalableDelayed_3Cycle )
 
);
 
 
 
 
//If the branch was taken, then use the pre-fetched instruction (iInstruction2)
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelay4A
wire[`INSTRUCTION_WIDTH-1:0] wCurrentInstruction_Delay1,wCurrentInstruction_BranchTaken;
 
FFD_POSEDGE_SYNCRONOUS_RESET # ( `INSTRUCTION_WIDTH ) FFDX
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( wInstructionAvalableDelayed_3Cycle ),
        .Enable(iBranchTaken),
        .Q( wInstructionAvalableDelayed_4Cycle )
        .D( oCurrentInstruction ),
 
        .Q( wCurrentInstruction_Delay1 )
);
);
 
 
 
wire wBranchTaken_Delay1;
assign oInstructionAvalable = (wInstructionAvalableDelayed_1Cycle && !rJumpNow) ||
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFDY
                                                                (wInstructionAvalableDelayed_3Cycle && wJumpNow_Delayed_2Cycle);
 
 
 
wire wInstructionAvalableDelayed;
 
 
 
FFD_POSEDGE_ASYNC_RESET # ( 1 ) FFDelay4
 
(
(
        .Clock( Clock ),
        .Clock( Clock ),
        .Clear( Reset ),
        .Reset( Reset ),
        .D( oInstructionAvalable ),
        .Enable(1'b1),
        .Q( wInstructionAvalableDelayed )
        .D( iBranchTaken ),
);
        .Q( wBranchTaken_Delay1 )
 
 
 
 
//----------------------------------------------
 
assign rJumpNow = iBranchTaken && !iBranchNotTaken;
 
//This sucks, should be improved
 
 
 
wire JumpInstructinDetected;
 
assign JumpInstructinDetected =
 
        (
 
         `INSTRUCTION_OPCODE == `JGEX || `INSTRUCTION_OPCODE == `JLEX ||
 
         `INSTRUCTION_OPCODE == `JGEY || `INSTRUCTION_OPCODE == `JLEY ||
 
         `INSTRUCTION_OPCODE == `JGEZ || `INSTRUCTION_OPCODE == `JLEZ ||
 
         `INSTRUCTION_OPCODE == `JEQX || `INSTRUCTION_OPCODE == `JNEX ||
 
         `INSTRUCTION_OPCODE == `JEQY || `INSTRUCTION_OPCODE == `JNEY ||
 
         `INSTRUCTION_OPCODE == `JEQZ || `INSTRUCTION_OPCODE == `JNEZ
 
         ) ;
         ) ;
 
 
 
 
//Stall logic. 
assign wCurrentInstruction_BranchTaken = (iBranchTaken ) ? iInstruction2 : iInstruction1;
//it basically tells IFU to stall on Branches. 
 
//The Stall begins when a Branch instruction
 
//is detected, the Stall ends when EXE tells us it made
 
//a branch taken or branch not taken decision
 
 
 
wire wStall;
 
assign wStall = JumpInstructinDetected && !iBranchTaken && !iBranchNotTaken;
 
 
 
//Increment the IP everytime IDU tells us it has Latched the previous I we gave him,
 
//except when we reached the last instruction in the flow, or we are in a Stall
 
 
 
wire wIncrementInstructionPointer;
 
assign wIncrementInstructionPointer = (wStall || wLastInstruction) ?  1'b0 : iDecodeUnitLatchedValues;
 
 
 
 
assign oCurrentInstruction = (wBranchTaken_Delay1) ?
 
wCurrentInstruction_Delay1 : wCurrentInstruction_BranchTaken;
 
 
//-------------------------------------------------
INCREMENT # (`ROM_ADDRESS_WIDTH) INC1
wire wIP_AlternateValue;
 
wire wIP_SetValueSelector;
 
wire [`ROM_ADDRESS_WIDTH-1:0] wInstructionPointerAlternateValue;
 
 
 
MUXFULLPARALELL_16bits_2SEL InstructionPointerSetValueMUX
 
 (
 
  .Sel( wIP_SetValueSelector ),
 
  .I1( iInitialCodeAddress    ),
 
  .I2(  iJumpIp ),
 
  .O1( wInstructionPointerAlternateValue )
 
 );
 
 
 
reg rIpControl;
 
MUXFULLPARALELL_1Bit_1SEL InstructionPointerControlMUX
 
 (
 (
  .Sel( rIpControl ),
.Clock( Clock ),
  .I1(  1'b0   ),
.Reset( Reset ),
  .I2(  iBranchTaken  ),
.A( oIP2 ),
  .O1( wIP_SetValueSelector )
.R( oIP2_Next )
 );
 );
 
 
 
wire[`ROM_ADDRESS_WIDTH-1:0] wIPEntryPoint;
 
assign wIPEntryPoint = (iBranchTaken) ? oIP2_Next : iInitialCodeAddress;
 
 
 
UPCOUNTER_POSEDGE # (`ROM_ADDRESS_WIDTH) InstructionPointer
UPCOUNTER_POSEDGE # (16) InstructionPointer
 
(
(
        .Clock(wIncrementInstructionPointer || wJumpNow_Delayed_1Cycle || iTrigger),
        .Clock( Clock ),
        .Reset(iTrigger ||  wJumpNow_Delayed_1Cycle ),
        .Reset(iTrigger | iBranchTaken),
        .Enable(1'b1),
        .Enable(wIncrementIP & ~iBranchTaken ),
        .Initial(wInstructionPointerAlternateValue),
        .Initial( wIPEntryPoint ),
        .Q(wInstructionPointer)
        .Q(oIP)
);
);
 
 
 
 
reg     [5:0]    CurrentState,   NextState;
 
 
 
//------------------------------------------------
 
always @(posedge Clock or posedge Reset)
 
begin
 
 
 
 
 
    if (Reset)
 
                CurrentState <= `IFU_AFTER_RESET;
 
    else
 
                CurrentState <= NextState;
 
 
 
end
 
//------------------------------------------------
 
always @ ( * )
 
begin
 
        case ( CurrentState )
 
        //------------------------------------
 
        `IFU_AFTER_RESET:
 
        begin
 
 
 
                 rEnable                <= iTrigger;
 
                 rIpControl <= `IP_SET_VALUE_INITIAL_ADDRESS;//0;
 
                 oExecutionDone <= 0;
 
 
 
                if (iTrigger)
 
                        NextState <= `IFU_INITIAL_STATE;
 
                else
 
                        NextState <= `IFU_AFTER_RESET;
 
        end
 
        //------------------------------------
 
        `IFU_INITIAL_STATE:
 
        begin
 
 
 
                rEnable   <= 1;
 
                rIpControl <= `IP_SET_VALUE_BRANCH_ADDRESS; //1;
 
                oExecutionDone <= 0;
 
 
 
                //We reached last instrcution (RETURN), and IDU latched the one before that
 
                if ( wLastInstruction && iDecodeUnitLatchedValues && !rJumpNow )
 
                        NextState <= `IFU_WAIT_FOR_LAST_INSTRUCTION_LATCHED_BY_IDU;
 
                else
 
                        NextState <= `IFU_INITIAL_STATE;
 
 
 
        end
 
 
 
        //------------------------------------  
 
        //Here, we wait until IDU latches the last
 
        //instruction, ie. the RETURN instruction
 
        `IFU_WAIT_FOR_LAST_INSTRUCTION_LATCHED_BY_IDU:
 
        begin
 
                rEnable   <= ~iDecodeUnitLatchedValues;
 
                rIpControl <= `IP_SET_VALUE_BRANCH_ADDRESS;
 
                oExecutionDone <= 0;
 
 
 
                if ( iDecodeUnitLatchedValues && !rJumpNow)//&& !iExeBusy && !iIDUBusy )
 
                        NextState <= `IFU_DONE;
 
                else if ( rJumpNow )
 
                        NextState <= `IFU_INITIAL_STATE;
 
                else
 
                        NextState <= `IFU_WAIT_FOR_LAST_INSTRUCTION_LATCHED_BY_IDU;
 
        end
 
        //------------------------------------
 
        `IFU_DONE:
 
        begin
 
                rEnable   <= 0;
 
                rIpControl <= `IP_SET_VALUE_BRANCH_ADDRESS;
 
                oExecutionDone <= !iExeBusy && !iIDUBusy;//1'b1;
 
 
 
 
 
                if (!iExeBusy && !iIDUBusy)
 
                        NextState <= `IFU_AFTER_RESET;
 
                else
 
                        NextState <= `IFU_DONE;
 
 
 
        end
 
        //------------------------------------
 
        default:
 
        begin
 
                rEnable  <= 0;
 
                rIpControl <= `IP_SET_VALUE_INITIAL_ADDRESS; //0;
 
                oExecutionDone <= 0;
 
 
 
                NextState <= `IFU_AFTER_RESET;
 
        end
 
        //------------------------------------  
 
        endcase
 
end// always    
 
 
 
 
 
//------------------------------------------------------
 
//
 
//
 
`ifdef DEBUG2
 
        always @ ( negedge iTrigger or negedge iDecodeUnitLatchedValues )
 
        begin
 
                $write("(%dns %d)",$time,oInstructionPointer);
 
        end
 
 
 
 
 
        always @ ( negedge wLastInstruction )
 
        begin
 
                $display(" %dns RETURN %d",$time,oMicroCodeReturnValue);
 
        end
 
`endif
 
 
 
`ifdef DEBUG2
 
        always @ (posedge wStall)
 
        begin
 
                $write("<S>");
 
        end
 
`endif
 
 
 
 
 
 
 
 
 
endmodule
endmodule
 
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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