/*******************************************************************************
* 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 openDLX.datatypes.*;
import openDLX.util.Statistics;
import org.apache.log4j.Logger;
public class WriteBack
{
private static Logger logger = Logger.getLogger("WRITEBACK");
private Statistics stat = Statistics.getInstance();
private RegisterSet reg_set;
private Queue<MemoryWritebackData> memory_writeback_latch;
public WriteBack(RegisterSet reg_set)
{
this.reg_set = reg_set;
}
public void setInputLatch(Queue<MemoryWritebackData> memoryWritebackLatch)
{
memory_writeback_latch = memoryWritebackLatch;
}
public WritebackOutputData doCycle()
{
MemoryWritebackData mwd = memory_writeback_latch.element();
uint32[] alu_out = mwd.getAluOut();
uint32 alu_outLO = alu_out[0];
uint32 alu_outHI = alu_out[1];
uint32 ld_result = mwd.getLdResult();
Instruction inst = mwd.getInst();
uint32 pc = mwd.getPc();
boolean jump = mwd.getJump();
boolean caught_break = false;
if((ArchCfg.isa_type == ISAType.MIPS) && (inst.getOpNormal() == OpcodeNORMAL.SPECIAL) && (inst.getOpSpecial() == OpcodeSPECIAL.BREAK))
{
logger.info("Caught BREAK instruction - finishing simulation.");
caught_break = true;
}
if((ArchCfg.isa_type == ISAType.DLX) && (inst.getOpNormal() == OpcodeNORMAL.SPECIAL) && (inst.getOpSpecial() == OpcodeSPECIAL.TRAP) && (alu_outLO.getValue() == PipelineConstants.DLX_TRAP_STOP))
{
logger.info("Caught TRAP 0 - finishing simulation.");
caught_break = true;
}
boolean regWrite = false;
uint8 regWriteSelect = new uint8(0);
uint32 regWriteValue = new uint32(0);
logger.info("PC: " + pc.getValueAsHexString());
if (inst.getLoad())
{
// write load result into the register
regWriteValue = ld_result;
}
else if(inst.getBranchAndLink())
{
// write return address into the return address register (RA, reg 31)
regWriteValue = new uint32(pc.getValue() + 8);
}
else
{
// normal register write
regWriteValue = alu_outLO;
}
if (inst.getWriteRd())
{
// write the register RD
// if for a non-BranchAndLink instruction or if the BranchAndLink instruction jumps
if((!inst.getBranchAndLink()) || (inst.getBranchAndLink() && jump))
{
regWrite = true;
regWriteSelect = inst.getRd();
}
}
else if (inst.getWriteRt())
{
// write the register RD (only for non branches)
regWrite = true;
regWriteSelect = inst.getRt();
}
if (regWrite)
{
if(regWriteSelect.getValue() != 0)
{
logger.debug("writing: " + regWriteValue.getValueAsHexString() + " to register " + regWriteSelect.getValue() + "/" + ArchCfg.getRegisterDescription(regWriteSelect.getValue()));
reg_set.write(regWriteSelect, regWriteValue);
}
else
{
logger.info("suppressing writing of register 0/" + ArchCfg.getRegisterDescription(0) + " with value: " + regWriteValue.getValueAsHexString());
}
}
if (inst.getWriteLO() || inst.getWriteHI())
{
regWrite = true;
if (inst.getWriteLO())
{
logger.debug("writing: " + alu_outLO.getValueAsHexString() + " to register " + SpecialRegisters.LO);
reg_set.write_SP(SpecialRegisters.LO, alu_outLO);
}
if (inst.getWriteHI())
{
logger.debug("writing: " + alu_outHI.getValueAsHexString() + " to register " + SpecialRegisters.HI);
reg_set.write_SP(SpecialRegisters.HI, alu_outHI);
}
}
if (regWrite)
{
reg_set.printContent();
}
// count all instructions that are no NOP
// TODO: This only works, because the write back currently cannot be stalled
if(inst.getOpNormal() != OpcodeNORMAL.NOP)
{
stat.countInstruction();
}
WriteBackData wbd = new WriteBackData(inst, pc, alu_out, ld_result);
return new WritebackOutputData(wbd, caught_break);
}
}