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
|