+1 (315) 557-6473 

Simplified Cycle Accurate Simulation of Limited Number Of ARM Instructions In Java Assignment Solution.


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
Simplified cycle accurate simulation of limited number of ARM instructions in Java
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);
    }
}