×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

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

July 10, 2024
Dr. Chloe jhones
Dr. Chloe
🇸🇬 Singapore
Java
Dr. Chloe Wong, with a Ph.D. in Computer Engineering from NUS Singapore, has a wealth of knowledge in Java GUI programming and has completed 750 assignments on GUI design using Swing and JavaFX. Dr. Wong's expertise extends to optimizing GUI performance, internationalization in JavaFX applications, integrating multimedia elements, grid-based layout design, and implementing complex UI interactions.
Key Topics
  • Instructions
  • Requirements and Specifications
Tip of the day
Use Python libraries effectively by importing only what you need. For example, if you're working with data, using libraries like pandas and numpy can save time and simplify complex tasks like data manipulation and analysis.
News
In 2024, the Biden-Harris Administration has expanded high-dosage tutoring and extended learning programs to boost academic achievement, helping programming students and others recover from pandemic-related setbacks. These initiatives are funded by federal resources aimed at improving math and literacy skills​

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); } }

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!