/*******************************************************************************
* 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.exception.MemoryException;
import openDLX.exception.MemoryStageException;
import openDLX.memory.DataMemory;
import openDLX.util.Statistics;
import org.apache.log4j.Logger;
public class Memory
{
private static Logger logger = Logger.getLogger("MEMORY");
private Statistics stat = Statistics.getInstance();
private DataMemory dmem;
private Queue<ExecuteMemoryData> execute_memory_latch;
private final boolean throwExceptionForUntestedAccesses = true;
public Memory(DataMemory dmem)
{
this.dmem = dmem;
}
public void setInputLatch(Queue<ExecuteMemoryData> executeMemoryLatch)
{
execute_memory_latch = executeMemoryLatch;
}
public MemoryOutputData doCycle() throws MemoryStageException, MemoryException
{
ExecuteMemoryData emd = execute_memory_latch.element();
uint32[] alu_out = emd.getAluOut();
uint32 alu_outLO = alu_out[0];
// uint32 alu_outHI = alu_out[1];
uint32 store_value = emd.getStoreValue();
Instruction inst = emd.getInst();
uint32 pc = emd.getPc();
boolean jump = emd.getJump();
uint32 ld_result = new uint32(0);
if (inst.getLoad())
{
if(dmem.getRequestDelay(RequestType.DATA_RD, alu_outLO)==0)
{
switch(inst.getMemoryWidth())
{
case BYTE:
ld_result.setValue((int)dmem.read_u8(alu_outLO, true).getValue());
logger.debug("PC: " + pc.getValueAsHexString() + " load from addr: " + alu_outLO.getValueAsHexString() + " value: " + ld_result.getValueAsHexString());
break;
case UBYTE:
ld_result.setValue(dmem.read_u8(alu_outLO, true).getValue()&0xFF);
logger.debug("PC: " + pc.getValueAsHexString() + " load from addr: " + alu_outLO.getValueAsHexString() + " value: " + ld_result.getValueAsHexString());
break;
case WORD:
ld_result.setValue(dmem.read_u32(alu_outLO, true).getValue());
logger.debug("PC: " + pc.getValueAsHexString() + " load from addr: " + alu_outLO.getValueAsHexString() + " value: " + ld_result.getValueAsHexString());
break;
case UWORD:
ld_result.setValue(dmem.read_u32(alu_outLO, true).getValue());
logger.debug("PC: " + pc.getValueAsHexString() + " load from addr: " + alu_outLO.getValueAsHexString() + " value: " + ld_result.getValueAsHexString());
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Untested memory width: " + inst.getMemoryWidth());
}
break;
default:
logger.error("wrong memory width: " + inst.getMemoryWidth());
throw new MemoryStageException("Wrong memory width: " + inst.getMemoryWidth());
}
stat.countMemRead();
}
else
{
// stall
}
}
else if (inst.getStore())
{
if(dmem.getRequestDelay(RequestType.DATA_WR, alu_outLO)==0)
{
switch(inst.getMemoryWidth())
{
case BYTE:
logger.debug("PC: " + pc.getValueAsHexString() + " store value: " + store_value.getValueAsHexString() + " to addr: " + alu_outLO.getValueAsHexString());
dmem.write_u8(alu_outLO, store_value);
break;
case UBYTE:
logger.debug("PC: " + pc.getValueAsHexString() + " store value: " + store_value.getValueAsHexString() + " to addr: " + alu_outLO.getValueAsHexString());
dmem.write_u8(alu_outLO, store_value);
break;
case WORD:
logger.debug("PC: " + pc.getValueAsHexString() + " store value: " + store_value.getValueAsHexString() + " to addr: " + alu_outLO.getValueAsHexString());
dmem.write_u32(alu_outLO, store_value);
break;
case UWORD:
logger.debug("PC: " + pc.getValueAsHexString() + " store value: " + store_value.getValueAsHexString() + " to addr: " + alu_outLO.getValueAsHexString());
dmem.write_u32(alu_outLO, store_value);
break;
case WORD_RIGHT_PART:
// refer to page A-153 of the MIPS IV Instruction Set Rev. 3.2
switch(alu_outLO.getValue()&0x3)
{
case 0:
dmem.write_u32(alu_outLO, store_value);
logger.warn("Verify operation of SWR (0)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (0)!");
}
break;
case 1:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue())&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()+1), new uint8((store_value.getValue()>>8)&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()+2), new uint8((store_value.getValue()>>16)&0xFF));
logger.warn("Verify operation of SWR (1)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (1)!");
}
break;
case 2:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue())&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()+1), new uint8((store_value.getValue()>>8)&0xFF));
logger.warn("Verify operation of SWR (3)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (2)!");
}
break;
case 3:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue())&0xFF));
logger.warn("Verify operation of SWR (3)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (3)!");
}
break;
}
break;
case WORD_LEFT_PART:
// refer to page A-150 of the MIPS IV Instruction Set Rev. 3.2
switch(alu_outLO.getValue()&0x3)
{
case 0:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue()>>24)&0xFF));
logger.warn("Verify operation of SWL (0)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (0)!");
}
break;
case 1:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue()>>24)&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()-1), new uint8((store_value.getValue()>>16)&0xFF));
logger.warn("Verify operation of SWL (1)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (1)!");
}
break;
case 2:
dmem.write_u8(alu_outLO, new uint8((store_value.getValue()>>24)&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()-1), new uint8((store_value.getValue()>>16)&0xFF));
dmem.write_u8(new uint32(alu_outLO.getValue()-2), new uint8((store_value.getValue()>>8)&0xFF));
logger.warn("Verify operation of SWL (2)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (2)!");
}
break;
case 3:
dmem.write_u32(new uint32(alu_outLO.getValue()-3), store_value);
logger.warn("Verify operation of SWL (3)!");
if(throwExceptionForUntestedAccesses)
{
throw new MemoryStageException("Verify operation of SWR (2)!");
}
break;
}
break;
default:
logger.error("Wrong memory width: " + inst.getMemoryWidth());
throw new MemoryStageException("Wrong memory width: " + inst.getMemoryWidth());
}
stat.countMemWrite();
}
else
{
// stall
}
}
else
{
logger.debug("PC: " + pc.getValueAsHexString() + " nothing to do");
}
MemoryWritebackData mwd = new MemoryWritebackData(inst, pc, alu_out, ld_result, jump);
return new MemoryOutputData(mwd);
}
}