1 |
152 |
diegovalve |
`timescale 1ns / 1ps
|
2 |
|
|
`include "aDefinitions.v"
|
3 |
|
|
/**********************************************************************************
|
4 |
|
|
Theia, Ray Cast Programable graphic Processing Unit.
|
5 |
|
|
Copyright (C) 2010 Diego Valverde (diego.valverde.g@gmail.com)
|
6 |
|
|
|
7 |
|
|
This program is free software; you can redistribute it and/or
|
8 |
|
|
modify it under the terms of the GNU General Public License
|
9 |
|
|
as published by the Free Software Foundation; either version 2
|
10 |
|
|
of the License, or (at your option) any later version.
|
11 |
|
|
|
12 |
|
|
This program is distributed in the hope that it will be useful,
|
13 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
|
|
GNU General Public License for more details.
|
16 |
|
|
|
17 |
|
|
You should have received a copy of the GNU General Public License
|
18 |
|
|
along with this program; if not, write to the Free Software
|
19 |
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20 |
|
|
|
21 |
|
|
***********************************************************************************/
|
22 |
|
|
/**********************************************************************************
|
23 |
|
|
Description:
|
24 |
|
|
This is the instruction fetch unit.
|
25 |
|
|
It gets the next instruction from the IMEM module at the MEM unit.
|
26 |
|
|
It increments the instruction pointer (IP) in such a way that EXE has always
|
27 |
|
|
one instruction per clock cycle (best pipeline performance). In order to achieve this,
|
28 |
|
|
IFU has 2 instruction pointers, so that in case of 'branch' instructions,
|
29 |
|
|
two instructions pointer are generated and two different instructions are simultaneously
|
30 |
|
|
fetched from IMEM: the branch-taken and branch-not-taken instructions, so that once the
|
31 |
|
|
branch outcome is calculted in EXE, both possible outcomes are already pre-fetched.
|
32 |
|
|
**********************************************************************************/
|
33 |
|
|
module InstructionFetch
|
34 |
|
|
(
|
35 |
|
|
input wire Clock,
|
36 |
|
|
input wire Reset,
|
37 |
|
|
input wire iTrigger,
|
38 |
|
|
input wire[`ROM_ADDRESS_WIDTH-1:0] iInitialCodeAddress,
|
39 |
|
|
input wire[`INSTRUCTION_WIDTH-1:0] iInstruction1, //Branch not taken instruction
|
40 |
|
|
input wire[`INSTRUCTION_WIDTH-1:0] iInstruction2, //Branch taken instruction
|
41 |
|
|
input wire iBranchTaken,
|
42 |
|
|
output wire oInstructionAvalable,
|
43 |
|
|
output wire [`ROM_ADDRESS_WIDTH-1:0] oIP,
|
44 |
|
|
output wire [`ROM_ADDRESS_WIDTH-1:0] oIP2, //calcule both decide later
|
45 |
|
|
output wire[`INSTRUCTION_WIDTH-1:0] oCurrentInstruction,
|
46 |
|
|
input wire iEXEDone,
|
47 |
|
|
output wire oMicroCodeReturnValue,
|
48 |
|
|
input wire iSubroutineReturn,
|
49 |
|
|
//input wire [`ROM_ADDRESS_WIDTH-1:0] iReturnAddress,
|
50 |
|
|
output wire oExecutionDone
|
51 |
|
|
);
|
52 |
|
|
`define INSTRUCTION_OPCODE oCurrentInstruction[`INSTRUCTION_WIDTH-1:`INSTRUCTION_WIDTH-`INSTRUCTION_OP_LENGTH]
|
53 |
|
|
|
54 |
|
|
|
55 |
|
|
assign oMicroCodeReturnValue = oCurrentInstruction[0];
|
56 |
|
|
assign oIP2 = oCurrentInstruction[47:32];
|
57 |
|
|
|
58 |
|
|
wire wTriggerDelay1,wTriggerDelay2,wIncrementIP_Delay1,wIncrementIP_Delay2,
|
59 |
|
|
wLastInst_Delay1,wLastInst_Delay2;
|
60 |
|
|
wire wIncrementIP,wLastInstruction;
|
61 |
|
|
wire wInstructionAvalable,wSubReturnDelay1,wSubReturnDelay2;
|
62 |
|
|
|
63 |
|
|
assign wLastInstruction = (`INSTRUCTION_OPCODE == `RETURN );
|
64 |
|
|
|
65 |
|
|
wire IsCall;
|
66 |
|
|
reg [`ROM_ADDRESS_WIDTH-1:0] rReturnAddress;
|
67 |
|
|
assign IsCall = ( `INSTRUCTION_OPCODE == `CALL ) ? 1'b1 : 1'b0;
|
68 |
|
|
always @ (posedge IsCall)
|
69 |
|
|
rReturnAddress <= oIP+1;
|
70 |
|
|
|
71 |
|
|
//Increment IP 2 cycles after trigger or everytime EXE is done, or 2 cycles after return from sub, but stop if we get to the RETURN
|
72 |
|
|
assign wIncrementIP = wTriggerDelay2 | (iEXEDone & ~wLastInstruction) | wSubReturnDelay2;
|
73 |
|
|
//It takes 1 clock cycle to read the instruction back from IMEM
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
//Instructions become available to IDU:
|
77 |
|
|
//* 2 cycles after IFU is initially triggered
|
78 |
|
|
//* Everytime previous instruction execution is complete except for the last instruction in
|
79 |
|
|
//the flow
|
80 |
|
|
assign wInstructionAvalable = wTriggerDelay2 | (iEXEDone & ~wLastInst_Delay2);
|
81 |
|
|
|
82 |
|
|
|
83 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD22
|
84 |
|
|
(
|
85 |
|
|
.Clock( Clock ),
|
86 |
|
|
.Reset( Reset ),
|
87 |
|
|
.Enable(1'b1),
|
88 |
|
|
.D( iSubroutineReturn ),
|
89 |
|
|
.Q( wSubReturnDelay1 )
|
90 |
|
|
);
|
91 |
|
|
|
92 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD23
|
93 |
|
|
(
|
94 |
|
|
.Clock( Clock ),
|
95 |
|
|
.Reset( Reset ),
|
96 |
|
|
.Enable(1'b1),
|
97 |
|
|
.D( wSubReturnDelay1 ),
|
98 |
|
|
.Q( wSubReturnDelay2 )
|
99 |
|
|
);
|
100 |
|
|
//Special case for instruction available pin: if a return from subroutine instruction was issued,
|
101 |
|
|
//then wait 1 cycle before anouncing Instruction available to IDU
|
102 |
|
|
assign oInstructionAvalable = wInstructionAvalable & ~iSubroutineReturn | wSubReturnDelay2;
|
103 |
|
|
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
|
107 |
|
|
|
108 |
|
|
//Once we reach the last instruction, wait until EXE says he is done, then assert oExecutionDone
|
109 |
|
|
assign oExecutionDone = (wLastInstruction & iEXEDone);
|
110 |
|
|
|
111 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD2
|
112 |
|
|
(
|
113 |
|
|
.Clock( Clock ),
|
114 |
|
|
.Reset( Reset ),
|
115 |
|
|
.Enable(1'b1),
|
116 |
|
|
.D( iTrigger ),
|
117 |
|
|
.Q( wTriggerDelay1 )
|
118 |
|
|
);
|
119 |
|
|
|
120 |
|
|
|
121 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD3
|
122 |
|
|
(
|
123 |
|
|
.Clock( Clock ),
|
124 |
|
|
.Reset( Reset ),
|
125 |
|
|
.Enable(1'b1),
|
126 |
|
|
.D( wTriggerDelay1 ),
|
127 |
|
|
.Q( wTriggerDelay2 )
|
128 |
|
|
);
|
129 |
|
|
|
130 |
|
|
|
131 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD4
|
132 |
|
|
(
|
133 |
|
|
.Clock( Clock ),
|
134 |
|
|
.Reset( Reset ),
|
135 |
|
|
.Enable(wLastInstruction),
|
136 |
|
|
.D( oInstructionAvalable ),
|
137 |
|
|
.Q( wLastInst_Delay1 )
|
138 |
|
|
);
|
139 |
|
|
|
140 |
|
|
|
141 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFD5
|
142 |
|
|
(
|
143 |
|
|
.Clock( Clock ),
|
144 |
|
|
.Reset( Reset ),
|
145 |
|
|
.Enable(1'b1),//wLastInstruction),
|
146 |
|
|
.D( wLastInst_Delay1 ),
|
147 |
|
|
.Q( wLastInst_Delay2 )
|
148 |
|
|
);
|
149 |
|
|
|
150 |
|
|
wire [`ROM_ADDRESS_WIDTH-1:0] oIP2_Next;
|
151 |
|
|
|
152 |
|
|
/*
|
153 |
|
|
In case the branch is taken:
|
154 |
|
|
We point current instruction into the iInstruction2 (branch-taken) instruction
|
155 |
|
|
that corresponds to oIP2.
|
156 |
|
|
Then, in the next clock cycle we should use the oIP2 incremented by one,
|
157 |
|
|
so we need to load UPCOUNTER_POSEDGE with oIP2+1
|
158 |
|
|
*/
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
//If the branch was taken, then use the pre-fetched instruction (iInstruction2)
|
162 |
|
|
wire[`INSTRUCTION_WIDTH-1:0] wCurrentInstruction_Delay1,wCurrentInstruction_BranchTaken;
|
163 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( `INSTRUCTION_WIDTH ) FFDX
|
164 |
|
|
(
|
165 |
|
|
.Clock( Clock ),
|
166 |
|
|
.Reset( Reset ),
|
167 |
|
|
.Enable(iBranchTaken),
|
168 |
|
|
.D( oCurrentInstruction ),
|
169 |
|
|
.Q( wCurrentInstruction_Delay1 )
|
170 |
|
|
);
|
171 |
|
|
|
172 |
|
|
wire wBranchTaken_Delay1;
|
173 |
|
|
FFD_POSEDGE_SYNCRONOUS_RESET # ( 1 ) FFDY
|
174 |
|
|
(
|
175 |
|
|
.Clock( Clock ),
|
176 |
|
|
.Reset( Reset ),
|
177 |
|
|
.Enable(1'b1),
|
178 |
|
|
.D( iBranchTaken ),
|
179 |
|
|
.Q( wBranchTaken_Delay1 )
|
180 |
|
|
);
|
181 |
|
|
|
182 |
|
|
|
183 |
|
|
assign wCurrentInstruction_BranchTaken = ( iBranchTaken & ~iSubroutineReturn) ? iInstruction2 : iInstruction1;
|
184 |
|
|
|
185 |
|
|
assign oCurrentInstruction = (wBranchTaken_Delay1 ) ?
|
186 |
|
|
wCurrentInstruction_Delay1 : wCurrentInstruction_BranchTaken;
|
187 |
|
|
|
188 |
|
|
INCREMENT # (`ROM_ADDRESS_WIDTH) INC1
|
189 |
|
|
(
|
190 |
|
|
.Clock( Clock ),
|
191 |
|
|
.Reset( Reset ),
|
192 |
|
|
.A( oIP2 ),
|
193 |
|
|
.R( oIP2_Next )
|
194 |
|
|
);
|
195 |
|
|
|
196 |
|
|
wire[`ROM_ADDRESS_WIDTH-1:0] wIPEntryPoint;
|
197 |
|
|
//assign wIPEntryPoint = (iBranchTaken) ? oIP2_Next : iInitialCodeAddress;
|
198 |
|
|
|
199 |
|
|
//iReturnAddress is a register stored @ IDU everytime a CALL instruction is decoded
|
200 |
|
|
assign wIPEntryPoint = (iBranchTaken & ~wBranchTaken_Delay1) ? (iSubroutineReturn) ? rReturnAddress : oIP2_Next : iInitialCodeAddress;
|
201 |
|
|
|
202 |
|
|
|
203 |
|
|
UPCOUNTER_POSEDGE # (`ROM_ADDRESS_WIDTH) InstructionPointer
|
204 |
|
|
(
|
205 |
|
|
.Clock( Clock ),
|
206 |
|
|
.Reset(iTrigger | (iBranchTaken & ~wBranchTaken_Delay1)),
|
207 |
|
|
.Enable(wIncrementIP & (~iBranchTaken | wBranchTaken_Delay1 ) ),
|
208 |
|
|
.Initial( wIPEntryPoint ),
|
209 |
|
|
.Q(oIP)
|
210 |
|
|
);
|
211 |
|
|
|
212 |
|
|
|
213 |
|
|
endmodule
|
214 |
|
|
|
215 |
|
|
//-------------------------------------------------------------------------------
|