Question
Using the sample code for the single cycle machine provided as reference for this module, create a complete program. Including: 1. A method for reading
Using the sample code for the single cycle machine provided as reference for this module, create a complete program. Including:
1. A method for reading program instructions and data into their respective memories. This function will take as an input parameter, the name of a text file (alternately, you may inline this function in main).
The contents of the file will consist of three hexadecimal numbers delimited by spaces. The first number will be 8 characters and will correspond to the byte memory address to place the data in. The next number will either be a 1 (for program memory), or a 0 (for data memory). The last number will be 8 characters that will correspond to data to place at the specified memory address. The lines may also contain comments which always begin with the # symbol.
Examples:
000C0DE0 1 11112222 # this line places 0x11112222 at program memory space 0x000C0DE0 00012340 0 0000F00D # this line places 0x0000F00D at data memory space 00012340 Note: All addresses will be word-aligned and accesses will always be 32-bits at a time, so endianness of how you store the data should not matter.
Note: You may want to use the functions Cpu.setImem() and Cpu.setDmem() to help with this function
2. Complete required macro definitions within Cpu.cpp (the area is marked by comments within the file). You will need to apply your knowledge of instruction decoding the MIPS architecture and bitwise operations to do this.
3. Instrument the Cpu.update() function in order to gather information on the following.
The total number of cycles executed
The total number of cycles where memory is accessed
The total number of cycles where data is written back to the register file
3. Write a main function that prints a startup banner (includes your name and course number), reads the input file, initializes memory, runs the simulation, and displays results. When simulating, execution will begin at instruction 0 and should execute for 270 cycles.
Upon completion of the simulation, your code should dump the contents of the registers in hexadecimal format and show the count values in decimal (you may choose to modify the CPU::dump() function for this. Example program output is shown below (your numbers will be different). PROGRAM COUNTER = 00000000 INSTRUCTION = 00000000 REGISTER FILE R00: 00000000 R08: 00000000 R10: 00000000 R18: 00000000 R01: 00000000 R09: 00000000 R11: 00000000 R19: 00000000
Total Instructions: 0 Reg Write Instructions: 0 Mem Instructions: 0 Cpu.cpp
#include
// SIGN_EXT(x) a macro to sign extend a 16 bit signed integer to 32 bits #define SIGN_EXT(x)
// each of the following are the opcodes for teh specified instruction from // the MIPS instruction set. #define OP_LW #define OP_SW #define OP_RTYPE #define OP_BEQ #define OP_JMP Cpu::Cpu() { // initialize the program counter to 0 pc = 0; } void Cpu::setImem(unsigned int address,unsigned int value) { imem.setAt(address,value); } void Cpu::setDmem(unsigned int address, unsigned int value) { dmem.update(address, value, true); } void Cpu::update() { unsigned int instruction = imem.value(pc); unsigned int opcode = BITS(instruction, 26, 31); unsigned int funct = BITS(instruction, 0, 5); unsigned int rdidx = BITS(instruction, 11, 15); unsigned int rtidx = BITS(instruction, 16, 20); unsigned int rsidx = BITS(instruction, 21, 25); signed int immed = SIGN_EXT(BITS(instruction, 0, 15)); unsigned int jmpaddr = BITS(instruction, 0, 25);
// alu operation combinational logic int ALUOp = 0x0; if ((opcode == 0x23) || (opcode == 0x2b)) ALUOp = 0x0; // load or store instructions if (opcode == 0x04) ALUOp = 0x1; // branch on equal instruction if (opcode == 0x00) ALUOp = 0x2; // r-type instructions // alu control combinational logic int ALUControl = 0xF; if (ALUOp == 0x0) ALUControl = 0x2; // lw/sw -> add if (ALUOp == 0x01) ALUControl = 0x6; // lw/sw -> subtract if (ALUOp == 0x02) { if (funct == 0x20) ALUControl = 0x2; // add if (funct == 0x22) ALUControl = 0x6; // subtract if (funct == 0x24) ALUControl = 0x0; // AND if (funct == 0x25) ALUControl = 0x1; // OR if (funct == 0x2a) ALUControl = 0x7; // set-on-less-than }
// additional control signals based on opcode unsigned int aluSrc = (opcode == OP_LW) || (opcode == OP_SW) ? 1 : 0; unsigned int regDest = (opcode == OP_RTYPE) ? 1 : 0; unsigned int branch = (opcode == OP_BEQ) ? 1 : 0; unsigned int memRead = (opcode == OP_LW) ? 1 : 0; unsigned int memToReg = (opcode == OP_LW) ? 1 : 0; unsigned int memWrite = (opcode == OP_SW) ? 1: 0; unsigned int regWrite = (opcode == OP_LW) || (opcode == OP_RTYPE) ? 1 : 0; unsigned int jump = (opcode == OP_JMP) ? 1 : 0;
// register file read operation based on rt and rd indicies unsigned int regRs = regs.readData1(rsidx); unsigned int regRt = regs.readData2(rtidx);
// alu source selection multiplexor unsigned int operand1 = regRs; unsigned int operand2 = aluSrc ? immed : regRt;
// ALU combinatinational logic int ALUResult = 0; if (ALUControl == 0x0) ALUResult = operand1 & operand2; // and if (ALUControl == 0x1) ALUResult = operand1 | operand2; // or if (ALUControl == 0x2) ALUResult = operand1 + operand2; // add if (ALUControl == 0x6) ALUResult = operand1 - operand2; // subtract if (ALUControl == 0x7) ALUResult = (operand1 < operand2) ? 1 : 0; // set less than if (ALUControl == 0xc) ALUResult = ~(operand1 | operand2); // nor int zero = (ALUResult == 0x00000000) ? 1 : 0; // read the data memory if required unsigned int memData = dmem.read( ALUResult, memRead);
// register write data multipelexor unsigned int regWrData = memToReg ? memData : ALUResult; // register write destination multiplexor unsigned int regWrAddr = regDest ? rdidx : rtidx;
// calculate the branch or jump address unsigned int branchAddr = ( immed << 2) + pc + 4; unsigned int fullJumpAddr = (( pc + 4 ) & 0xF0000000) | (jmpaddr << 2); unsigned int next_pc;
// multiplexors to select the next program counter value next_pc = (branch && zero) ? branchAddr : pc + 4; next_pc = (jump) ? fullJumpAddr : next_pc;
// update the cpu state based on the rising edge of the system clock // in real hardware, these updates would all happen simultaneously regs.update(regWrAddr,regWrData,regWrite); dmem.update(ALUResult,regRt,memWrite); pc = next_pc; //STUDENT CODE } // dump() // dump the state of the CPU object to the standard output device void Cpu::dump() { printf("PROGRAM COUNTER = %08x INSTRUCTION = %08x ",pc, imem.value(pc)); printf("REGISTER FILE "); regs.dump(); printf(" "); //STUDENT CODE }
Cpu.h #ifndef CPU_H #define CPU_H #include "DataMemory.h" #include "InstructionMemory.h" #include "RegisterFile.h"
class Cpu { public: Cpu(); void update(); // run the simulation void setDmem(unsigned int addr, unsigned int data); // place a value in data memory void setImem(unsigned int addr, unsigned int data); // place a value in instruction memory void dump(); // dump the cpu state to the standard output device private: InstructionMemory imem; DataMemory dmem; unsigned int pc; RegisterFile regs; };
#endif // CPU_H DataMemory.cpp
DataMemory.h
input.txt
00000000 1 02008025 # or $s0,$s0,$zero // s0 = 0 (i = 0) 00000004 1 02609825 # or $s3,$s3,$zero // s3 = 0 (offset to data array - think *data) 00000008 1 0280a025 # or $s4,$s4,$zero // s4 = 0 (sum) 0000000c 1 8C150008 # lw $s5,max_loops($zero) // s5 = max_loops 00000010 1 8c110000 # lw $s1,one($zero) // s1 = constant one; 00000014 1 8c120004 # lw $s2,four($zero) // s2 = constant four; 00000018 1 0215402a # slt $t0,$s0,$s5 // while (i InstructionMemory.cpp InstructionMemory.h RegisterFile.cpp RegisterFile.h
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started