/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX;
import java.util.Queue;
import org.apache.log4j.Logger;
import openDLX.datatypes.*;
import openDLX.exception.MemoryException;
import openDLX.memory.InstructionMemory;
import openDLX.util.Statistics;
public class Fetch {
private static Logger logger = Logger.getLogger("FETCH");
private Statistics stat = Statistics.getInstance();
private uint32 program_counter;
private InstructionMemory imem;
private Queue<ExecuteFetchData> execute_fetch_latch;
private Queue<BranchPredictionModuleFetchData> branchprediction_fetch_latch;
public Fetch(uint32 init_pc, InstructionMemory imem)
{
program_counter = new uint32(init_pc);
this.imem = imem;
}
private void setPc(uint32 pc)
{
program_counter.setValue(pc.getValue());
logger.debug("Set Pc to: " + program_counter.getValueAsHexString());
}
public uint32 getPc()
{
return new uint32(program_counter);
}
private uint32 doFetch() throws MemoryException
{
uint32 instr = null;
if(imem.getRequestDelay(program_counter)==0)
{
instr = imem.read_u32(program_counter);
stat.countFetch();
}
return new uint32(instr);
}
public void increasePC()
{
program_counter.setValue(program_counter.getValue()+4);
logger.debug("Pc is now at: " + program_counter.getValueAsHexString());
}
public void setInputLatches(Queue<ExecuteFetchData> executeFetchLatch, Queue<BranchPredictionModuleFetchData> branchpredictionFetchLatch)
{
execute_fetch_latch = executeFetchLatch;
branchprediction_fetch_latch = branchpredictionFetchLatch;
}
public FetchOutputData doCycle() throws MemoryException
{
ExecuteFetchData efd = execute_fetch_latch.element();
BranchPredictionModuleFetchData bpmfd = branchprediction_fetch_latch.element();
boolean[] flush = new boolean[PipelineConstants.STAGES];
for(byte i = 0; i < PipelineConstants.STAGES; i++)
{
flush[i] = false;
}
if(bpmfd.getDoSpeculativeJump())
{
logger.debug("speculatively jumping from " + bpmfd.getPc().getValueAsHexString() + " to " + bpmfd.getBranchTgt().getValueAsHexString());
// the branch predictor predicted a branch, set the pc to the predicted target
setPc(bpmfd.getBranchTgt());
}
if((ArchCfg.isa_type == ISAType.MIPS) || (ArchCfg.use_load_stall_bubble == true))
{
if(efd.getMispredictedBranch() == true)
{
logger.debug("mispredicted branch at pc " + efd.getPc().getValueAsHexString() + " the branch was actually " + ((efd.getJump())?("taken to " + efd.getNewPc().getValueAsHexString()):("not taken next instr is " + new uint32(efd.getPc().getValue()+8).getValueAsHexString())));
flush[PipelineConstants.DECODE_STAGE] = true;
if(efd.getJump() == true)
{
setPc(efd.getNewPc());
}
else
{
setPc(new uint32(efd.getPc().getValue()+8));
}
// if(efd.getJump() == true)
// {
// setPc(efd.getNewPc());
// // according to the MIPS specification one instruction is executed in the branch delay
// // slot, this instruction will be already in the execute stage (i.e. in the latch before the execute stage).
// // Consequently the instruction in the decode stage has to be kicked out.
// flush[CONST.DECODE_STAGE] = true;
// }
}
}
else
{
if(efd.getMispredictedBranch() == true)
{
if(efd.getJump() == true)
{
setPc(efd.getNewPc());
}
else
{
setPc(new uint32(efd.getPc().getValue()+8));
}
}
}
if((efd.getInst().getBranch()) && (efd.getJump() == false) && (efd.getInst().getBranchLikely()))
{
logger.debug("likely branch was not taken, flushing branch delay slot");
// for likely branches if they are not taken the instruction in the branch delay slot hat to be nullified, e.g. by flushing it.
// notice: this is independent of the branch prediction
flush[PipelineConstants.EXECUTE_STAGE] = true;
}
uint32 instr = doFetch();
if(instr != null)
{
logger.debug("PC: " + getPc().getValueAsHexString() + " fetched instruction " + instr.getValueAsHexString());
}
else
{
// stalling
}
FetchDecodeData fdd = new FetchDecodeData(instr, getPc());
return new FetchOutputData(fdd, flush);
}
}