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 | Only display areas with differences | Details | Blame | View Log

Rev 23 Rev 60
`timescale 1ns / 1ps
`timescale 1ns / 1ps
`include "aDefinitions.v"
`include "aDefinitions.v"
/**********************************************************************************
/**********************************************************************************
Theia, Ray Cast Programable graphic Processing Unit.
Theia, Ray Cast Programable graphic Processing Unit.
Copyright (C) 2010  Diego Valverde (diego.valverde.g@gmail.com)
Copyright (C) 2010  Diego Valverde (diego.valverde.g@gmail.com)
 
 
This program is free software; you can redistribute it and/or
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
of the License, or (at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
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.