Instructions
Objective
Write a java assignment to create a simplified cycle accurate simulation of a limited number of ARM instructions.
Requirements and Specifications
Build a simulation of a simplified Armv8 CPU.
Need someone familiar with Assembly, machine language and ARMv8 machine, and the code will be written in java and please provide screenshots. The documents for understanding the context have been provided, they are likely not necessary.
Screenshots of output
Source Code
/**
* Represents a simple CPU based on the ARMv8 datapath.
*
* CS318 Programming Project 4
* Name:
*
*/
import java.io.*;
import java.util.Arrays;
public class CPU {
/** Memory unit for instructions */
private Memory instructionMemory;
/** Memory unit for data */
private Memory dataMemory;
/** Register unit */
private Registers registers;
/** Arithmetic and logic unit */
private ALU alu;
/** Adder for incrementing the program counter */
private ALU adderPC;
/** Adder for computing branches */
private ALU adderBranch;
/** Control unit */
private SimpleControl control;
/** Multiplexor output connects to Read Register 2 */
private Multiplexor2 muxRegRead2;
/** Mulitplexor ouptut connects to ALU input B */
private Multiplexor2 muxALUb;
/** Multiplexor output connects to Register Write Data */
private Multiplexor2 muxRegWriteData;
/** Multiplexor output connects to Program Counter */
private Multiplexor2 muxPC;
/** Program counter */
private boolean[] pc;
/**
* STUDENT SHOULD NOT MODIFY THIS METHOD
*
* Constructor initializes all data members.
*
* @param iMemFile Path to the file with instruction memory contents.
* @param dMemFile Path to the file with data memory contents.
* @exception FileNotFoundException if a file cannot be opened.
*/
public CPU(String iMemFile, String dMemFile) throws FileNotFoundException {
// Create objects for all data members
instructionMemory = new Memory(iMemFile);
dataMemory = new Memory(dMemFile);
registers = new Registers();
alu = new ALU();
control = new SimpleControl();
muxRegRead2 = new Multiplexor2(5);
muxALUb = new Multiplexor2(32);
muxRegWriteData = new Multiplexor2(32);
muxPC = new Multiplexor2(32);
// Activate adderPC with ADD operation, and inputB set to 4
// Send adderPC output to muxPC input 0
adderPC = new ALU();
adderPC.setControl(2);
boolean[] four = Binary.uDecToBin(4L, 32);
adderPC.setInputB(four);
// Initalize adderBranch with ADD operation
adderBranch = new ALU();
adderBranch.setControl(2);
// initialize program counter to 0
pc = new boolean[32];
for(int i = 0; i < 32; i++) {
pc[i] = false;
}
}
/**
* STUDENT SHOULD NOT MODIFY THIS METHOD
*
* Runs the CPU in single cycle (non-pipelined) mode. Stops when a halt
* instruction is decoded.
*
* This method can be used with any (assembled) assembly language program
* that uses the 9 instructions from Programming Project 2.
*/
public void singleCycle() {
int cycleCount = 0;
// Start the first cycle.
boolean[] instruction = fetch();
boolean op = decode(instruction);
// Loop until a halt instruction is decoded
while(op) {
execute();
memoryAccess();
writeBack();
cycleCount++;
// Start the next cycle
instruction = fetch();
op = decode(instruction);
}
System.out.println("CPU halt after " + cycleCount + " cycles.");
}
/**
* STUDENT MUST ADD MORE TESTING CODE TO THIS METHOD AS INDICATED BY
* COMMENTS WIHTIN THIS METHOD.
*
* DO NOT CHANGE the calls to the CPU private methods.
*
* The comments in this method indicate the minimum amount of testing code
* that you must add. You are encouraged to add additional testing code
* to help you develop and verify the correctness of the CPU private methods.
* Tests for the first instruction in testProg3.s are included as an
* example of how to test the correctness of the CPU private methods.
*
* Runs the CPU in single cycle (non-pipelined) mode. Stops when a halt
* instruction is decoded.
*
* This method should only be used with the assembled testProg3.s
* because this method verifies correct values based on that specific program.
*/
public void runTestProg3() {
int cycleCount = 0;
// Start the first cycle.
boolean[] instruction = fetch();
// Example Test: Verify that when cycleCount is 0 the insruction returned by fetch is the
// binary version of the first instruction from testProg3.s ADD R9,R31,R31 boolean[] firstInstr = {true,false,false,true,false,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,false,false,false,true,true,false,true,false,false,false,true};
if(cycleCount == 0 && !Arrays.equals(instruction,firstInstr)) {
System.out.println("FAIL: cycle " + cycleCount + " did not fetch correct instruction:");
System.out.println("------ fetch returned: " + Binary.toString(instruction));
System.out.println("------ correct instruction: " + Binary.toString(firstInstr));
}
boolean op = decode(instruction);
// Example Test: Verify that when cycleCount is 0 the control signals
// are correctly set for an ADD instruction
if(cycleCount == 0 && (control.Uncondbranch != false || control.RegWrite != true
|| control.Reg2Loc != false || control.MemWrite != false || control.MemtoReg != false
|| control.MemRead != false || control.Branch != false || control.ALUSrc != false
|| control.ALUControl != 2))
{
System.out.println("FAIL: cycle " + cycleCount + " after decode, control lines incorrect");
}
// Loop until a halt instruction is decoded
while(op) {
execute();
// Example Test: Verify that when cycleCount is 0 the ALU result is zero
boolean[] correctALU = Binary.uDecToBin(0L, 32);
if(cycleCount == 0 && !Arrays.equals(alu.getOutput(), correctALU)) {
System.out.println("FAIL: cycle " + cycleCount + " incorrect ALU result:");
System.out.println("------ ALU result: " + Binary.toString(alu.getOutput()));
System.out.println("------ correct result: " + Binary.toString(correctALU));
}
// ***** PROG. 4 STUDENT MUST ADD
// Test that when cycleCount is 1, the ALU result is the correct
// data memory address (should be 16)
correctALU = Binary.uDecToBin(16L, 32);
if(cycleCount == 1 && !Arrays.equals(alu.getOutput(), correctALU)) {
System.out.println("FAIL: cycle " + cycleCount + " incorrect ALU result:");
System.out.println("------ ALU result: " + Binary.toString(alu.getOutput()));
System.out.println("------ correct result: " + Binary.toString(correctALU));
}
// ***** PROG. 4 STUDENT MUST ADD
// Test that when cycleCount is 6, the branch adder's (adderBranch)
// result is the offset of the branch destination instruction (should be 32)
boolean [] correctDest = Binary.uDecToBin(32L, 32);
if(cycleCount == 6 && !Arrays.equals(adderBranch.getOutput(), correctDest)) {
System.out.println("FAIL: cycle " + cycleCount + " incorrect adderBranch result:");
System.out.println("------ adderBranch result: " + Binary.toString(adderBranch.getOutput()));
System.out.println("------ correct result: " + Binary.toString(correctDest));
}
memoryAccess();
// ***** PROG. 4 STUDENT MUST ADD
// Test that when cycleCount is 1, the value that was read from
// memory (should be 6) is in the register write multiplexor
// (muxRegWriteData) at input 1
boolean [] correctMem = Binary.uDecToBin(6L, 32);
if(cycleCount == 1 && !Arrays.equals(muxRegWriteData.output(true), correctMem)) {
System.out.println("FAIL: cycle " + cycleCount + " incorrect muxRegWriteData input 1 result:");
System.out.println("------ muxRegWriteData input 1 result: " + Binary.toString(muxRegWriteData.output(true)));
System.out.println("------ correct result: " + Binary.toString(correctMem));
}
writeBack();
cycleCount++;
// Start the next cycle
instruction = fetch();
// ***** PROG. 4 STUDENT MUST ADD
// Test that when cycleCount is 7, the instruction returned by fetch is
// the last instruction in the program: STR R5,[R9,#8] boolean[] lastInstr = {true,false,true,false,false,true,false,false,true,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true};
if(cycleCount == 7 && !Arrays.equals(instruction,lastInstr)) {
System.out.println("FAIL: cycle " + cycleCount + " did not fetch correct instruction:");
System.out.println("------ fetch returned: " + Binary.toString(instruction));
System.out.println("------ correct instruction: " + Binary.toString(lastInstr));
}
op = decode(instruction);
// ***** PROG. 4 STUDENT MUST ADD
// Test that when cycleCount is 1, the the control signals are correctly
// set for a LDR instruction
if(cycleCount == 1 && (control.Uncondbranch != false || control.RegWrite != true
|| control.MemWrite != false || control.MemtoReg != true
|| control.MemRead != true || control.Branch != false || control.ALUSrc != true
|| control.ALUControl != 2))
{
System.out.println("FAIL: cycle " + cycleCount + " after decode, control lines incorrect");
}
}
System.out.println("CPU halt after " + cycleCount + " cycles.");
}
/**
* STUDENT MUST COMPLETE THIS METHOD
*
* Instruction Fetch Step
* Fetch the instruction from the instruction memory starting at address pc.
* Activate the PC adder and place the adder's output into muxPC input 0.
*
* @return The instruction starting at address pc
*/
private boolean[] fetch() {
boolean [] instruction = instructionMemory.read32(pc); // use pc as the address to read instruction
adderPC.setInputA(pc); // set adder input to PC
adderPC.activate(); // increment PC
muxPC.setInput0(adderPC.getOutput()); // pass incremented PC to mux
return instruction;
}
/**
* STUDENT MUST COMPLETE THIS METHOD
*
* Instruction Decode and Register Read
*
* Decode the instruction. Sets the control lines and sends appropriate bits
* from the instruction to various inputs within the processor.
*
* Set the Read Register inputs so that the values to be read from
* the registers will be available in the next phase.
*
* @param instruction The 32-bit instruction to decode
* @return false if the opcode is HLT; true for any other opcode
*/
private boolean decode(boolean[] instruction) {
// decode instruction parts
boolean [] inst20_16 = Arrays.copyOfRange(instruction, 16, 21);
boolean [] inst4_0 = Arrays.copyOfRange(instruction, 0, 5);
boolean [] inst9_5 = Arrays.copyOfRange(instruction, 5, 10);
// opcodes for the supported instructions
boolean [] opcodeR_D = Arrays.copyOfRange(instruction, 21, 32);
boolean [] opcodeB = Arrays.copyOfRange(instruction, 26, 32);
boolean [] opcodeCB = Arrays.copyOfRange(instruction, 24, 32);
boolean [] inst25_0 = Arrays.copyOfRange(instruction, 0, 26);
boolean [] inst23_5 = Arrays.copyOfRange(instruction, 5, 24);
boolean [] inst20_12 = Arrays.copyOfRange(instruction, 12, 21);
boolean [] brAddress = Arrays.copyOf(inst25_0, 32); // zero extend to 32 bits
Arrays.fill(brAddress, 26, 32, inst25_0[25]); // sign extend immediate
boolean [] cbrAddress = Arrays.copyOf(inst23_5, 32); // zero extend to 32 bits
Arrays.fill(cbrAddress, 19, 32, inst23_5[18]); // sign extend immediate
boolean [] dtAddress = Arrays.copyOf(inst20_12, 32); // zero extend to 32 bits
Arrays.fill(dtAddress, 9, 32, inst20_12[8]); // sign extend immediate
// set muxReadReg2 inputs
muxRegRead2.setInput0(inst20_16);
muxRegRead2.setInput1(inst4_0);
registers.setRead1Reg(inst9_5);
registers.setWriteRegNum(inst4_0);
boolean noHalt = true; // indicates if the instruction was not a halt
// set default control lines
control.MemRead = false; // no memory read
control.MemWrite = false; // no memory write
control.Branch = false; // no branch
control.MemtoReg = false; // no save from memory to register
control.Uncondbranch = false; // no unconditional branch
control.ALUSrc = false; // use read data from register 2
control.ALUControl = 2; // add by default
// decode corresponding instruction
// If 11 bit opcode R instructions
if (Arrays.equals(Opcode.ADD, opcodeR_D)) {
control.ALUControl = 2; // add
control.Reg2Loc = false; // use register Rm
control.RegWrite = true; // save result in register
}
else if (Arrays.equals(Opcode.SUB, opcodeR_D)) {
control.ALUControl = 6; // sub
control.Reg2Loc = false; // use register Rm
control.RegWrite = true; // save result in register
}
else if (Arrays.equals(Opcode.AND, opcodeR_D)) {
control.ALUControl = 0; // and
control.Reg2Loc = false; // use register Rm
control.RegWrite = true; // save result in register
}
else if (Arrays.equals(Opcode.ORR, opcodeR_D)) {
control.ALUControl = 1; // or
control.Reg2Loc = false; // use register Rm
control.RegWrite = true; // save result in register
}
// If 11 bit opcode D instructions
else if (Arrays.equals(Opcode.LDR, opcodeR_D)) {
control.ALUControl = 2; // add
control.MemRead = true; // read memory
control.MemtoReg = true; // save memory to register
control.ALUSrc = true; // use immediate field
control.RegWrite = true; // save result in register
muxALUb.setInput1(dtAddress); // set data address immediate
}
else if (Arrays.equals(Opcode.STR, opcodeR_D)) {
control.ALUControl = 2; // add
control.Reg2Loc = true; // use register Rt
control.MemWrite = true; // write memory
control.ALUSrc = true; // use immediate field
control.RegWrite = false; // don't save result in register
muxALUb.setInput1(dtAddress); // set data address immediate
}
else if (Arrays.equals(Opcode.HLT, opcodeR_D)) {
noHalt = false;
}
// If 8 bit opcode CB instruction
else if (Arrays.equals(Opcode.CBZ, opcodeCB)) {
control.ALUControl = 7; // pass input B
control.Reg2Loc = true; // use register Rt
control.Branch = true; // it's a branch
control.RegWrite = false; // don't save result in register
adderBranch.setInputA(pc); // set adder for branch
adderBranch.setInputB(cbrAddress); // set immediate for second input
}
// If 6 bit opcode B instruction
else if (Arrays.equals(Opcode.B, opcodeB)) {
control.Uncondbranch = true; // it's an unconditional branch
control.RegWrite = false; // don't save result in register
adderBranch.setInputA(pc); // set adder for branch
adderBranch.setInputB(brAddress); // set immediate for second input
}
// set second input for registers based on the mux
registers.setRead2Reg(muxRegRead2.output(control.Reg2Loc));
// read register 2 and put it in mux
muxALUb.setInput0(registers.getReadReg2());
return noHalt;
}
/**
* STUDENT MUST COMPLETE THIS METHOD
*
* Execute Phase
* Activate the ALU to execute an arithmetic or logic operation, or to calculate
* a memory address.
*
* The branch adder is activated during this phase, and the branch adder
* result is placed into muxPC input 1.
*
* This method must make decisions based on the values of the control lines.
* This method has no information about the opcode!
*
*/
private void execute() {
alu.setInputA(registers.getReadReg1()); // connect first register to alu
alu.setInputB(muxALUb.output(control.ALUSrc)); // read input b from mux
alu.setControl(control.ALUControl); // set operation to make
alu.activate(); // make operation
adderBranch.activate(); // add address to PC
muxPC.setInput1(adderBranch.getOutput()); // set new address in mux
}
/**
* STUDENT MUST COMPLETE THIS METHOD
*
* Memory Access Phase
* Read or write from/to data memory.
*
* This method must make decisions based on the values of the control lines.
* This method has no information about the opcode!
*/
private void memoryAccess() {
if (control.MemRead) { // if load
// read using alu output as address
boolean [] data = dataMemory.read32(alu.getOutput());
muxRegWriteData.setInput1(data); // set read data in mux
} else if (control.MemWrite) { // if store
// write in address taken from alu, write data from register 2
dataMemory.write32(alu.getOutput(), registers.getReadReg2());
}
// set input 0 of mux with alu result
muxRegWriteData.setInput0(alu.getOutput());
}
/**
* STUDENT MUST COMPLETE THIS METHOD
*
* Write Back Phase
* Perform writes to registers: the PC and the processor registers.
*
* This method must make decisions based on the values of the control lines.
* This method has no information about the opcode!
*/
private void writeBack() {
// put data from rw mux in the data to write in registers
registers.setWriteRegData(muxRegWriteData.output(control.MemtoReg));
// if we need to write register, activate
if (control.RegWrite)
registers.activateWrite();
// see if branch is activated
boolean branch = (alu.getZeroFlag() && control.Branch) || control.Uncondbranch;
// select next PC based on branch mux
pc = muxPC.output(branch);
}
}
Related Samples
Explore our free Java assignment samples to enhance your coding skills and understanding of Java concepts. Each sample includes detailed explanations and practical examples, making it easier to grasp key programming techniques and improve your assignments. Dive into our resources and start learning today!
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java
Java