ECE-GY 6913 Lab 2: MIPS 5 Stage Pipeline Simulator
Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit
ECE-GY 6913
Lab #2
Lab 2: MIPS 5 Stage Pipeline Simulator
In this Lab assignment, you will implement a cycle-accurate simulator for a 5-stage pipelined MIPS processor in C++. The simulator supports a subset of the MIPS instruction set and should model the execution of each instruction cycle by cycle.
An example MIPS program is provided for the simulator as a text file “imem.txt”, which is used to initialize the Instruction Memory. Each line of the file corresponds to a Byte stored in the Instruction Memory in binary format, with the first line at address 0, the next line at address 1, and so on. Four contiguous lines correspond to one whole instruction. Note that the words stored in memory are in “Big-Endian” format, meaning that the most significant byte is stored first.
The Data Memory is initialized using the “dmem.txt” file. The format of the stored words is the same as the Instruction Memory. As with the instruction memory, the data memory addresses also begin at 0 and increment by one in each line.
The instructions that the simulator supports and their encodings are shown in Table 1. Note that all instructions, except for “halt”, exist in the MIPS ISA. TheMIPS Green Sheetdefines the semantics of each instruction.
For the purposes of this lab, we use the bne instruction, rather than the beq instruction from Lab1. bne jumps to the branch address ifR[rs] != R[rt] and jumps to PC+4 otherwise,i.e., ifR[rs] = R[rt]. This is to make writing loops slightly easier.
Name |
Format Type |
Opcode (Hex) |
Func (Hex) |
addu |
R-Type |
00 |
21 |
subu |
R-Type |
00 |
23 |
lw |
I-Type |
23 |
- |
sw |
I-Type |
2B |
- |
bne |
I-Type |
05 |
- |
halt |
J-Type |
3F |
- |
Table 1. Instruction encodings for a reduced MIPS ISA
Pipeline Structure
Your MIPS pipeline has the following 5 stages:
1. Fetch (IF): fetches an instruction from the instruction memory. Updates PC.
2. Decode (ID/RF): reads from the register RF and generates control signals required in subsequent stages. In addition, branches are resolved in this stage by checking for the branch condition and computing the effective address.
3. Execute (EX): performs an ALU operation.
4. Memory (MEM): loads or stores a 32-bit word from data memory.
5. Writeback (WB): writes back data to the RF.
Your simulator can make use of the same RF, IMEM, and DMEM classes that you used for Lab1. Complete implementations of these classes are provided for you in the skeleton code.
*Note that we have not defined an ALU class since, for this lab, the ALU is simple and only needs to perform adds and subtracts.
Each pipeline stage takes inputs from flip-flops. The input flip-flops for each pipeline stage are described in the tables below.
IF Stage Input Flip-Flops
Flip-Flop Name |
Bit-width |
Functionality |
PC |
32 |
Current value of PC |
Nop |
1 |
If set, IF stage performs anop |
IF/ID Stage Flip-Flops
Flip-Flop Name |
Bit-width |
Functionality |
Instr |
32 |
32b instruction read from Imem |
Nop |
1 |
If set, ID stage performs anop |
ID/EXE Stage Flip-Flops
Flip-Flop Name |
Bit-width |
Functionality |
Read-data1, Read_data2 |
32 |
32b data values read from RF |
Rs, Rt |
5 |
Addresses of source registers rs, rt. Note these are defined for both R-type and I-type instructions |
Wrt_reg_addr |
5 |
Address of the instruction’s destination register. Don’t care is the instruction doesn’tupdate RF |
Alu_op |
1 |
Set for addu, lw, sw; unset for subu |
Is I type |
1 |
Set if the instruction is I-type |
Wrt_enable |
1 |
Set if instruction updates RF |
Rd_mem, Wr_mem |
1 |
Rd_mem set for lw and wrt_mem set for sw instructions. |
Nop |
1 |
If set, EXE stage performs anop |
EXE/MEM Stage Flip-Flops
Flip-Flop Name |
Bit-width |
Functionality |
ALU_result |
32 |
32b ALU result, don’t care for beq |
Store_data |
32 |
32b value to be stored in DMEM for sw instruction. Don’t care otherwise |
Rs, Rt |
5 |
Addresses of source registers rs, rt. Note these are defined for both R-type and I-type instructions |
Wrt_reg_addr |
5 |
Address of the instruction’s destination register. Don’t care is the instruction doesn’tupdate RF |
Wrt_enable |
1 |
Set if instruction updates RF |
Rd_mem, Wr_mem |
1 |
Rd_mem set for lw and wrt_mem set for sw instructions. |
Nop |
1 |
If set, EXE stage performs anop |
WB Stage Input Flip-Flops
Flip-Flop Name |
Bit-width |
Functionality |
Wrt_data |
32 |
32b value to be written back to RF. Don’t care for sw and beq. |
Rs, Rt |
5 |
Addresses of source registers rs, rt. Note these are defined for both R-type and I-type instructions |
Wrt_reg_addr |
5 |
Address of the instruction’s destination register. Don’t care is the instruction doesn’tupdate RF |
Wrt_enable |
1 |
Set if instruction updates RF |
Nop |
1 |
If set, EXE stage performs anop |
Dealing with Hazards
Your processor must deal with two types of hazards.
1. RAW Hazards: RAW hazards are dealt with using either only forwarding (if possible) or, if not, using stalling + forwarding. You must follow the mechanisms described in Lecture to deal with RAW hazards.
2. Control Flow Hazards: You will assume that branch conditions are resolved in the ID/RF stage of the pipeline. Your processor deals with bne instructions as follows:
a) Branches are always assumed to be NOT TAKEN. That is, when a bneis fetched in the IF stage, the PC is speculatively updated as PC+4.
b) Branch conditions are resolved in the ID/RF stage. To make your life easier, we will ensure that every bne instruction has no RAW dependency with its previous two instructions. In other words, you do NOT have to deal with RAW hazards for branches!
c) Two operations are performed in the ID/RF stage: (i) Read_data1 and Read_data2 are compared to determine the branch outcome; (ii) the effective branch address is computed.
d) If the branch is NOT TAKEN, execution proceeds normally. However, if the branch is TAKEN, the speculatively fetched instruction from PC+4 is quashed in its ID/RF stage using the nopbit and the next instruction is fetched from the effective branch address. Execution now proceeds normally.
The nop bit
The nop bit for any stage indicates whether it is performing a valid operation in the current clock cycle. The nopbit for the IF stage is initialized to 0 and for all other stages is initialized to 1. (This is because in the first clock cycle, only the IF stage performs a valid operation.)
In the absence of hazards, the value of the nopbit for a stage in the current clock cycle is equal to the nop bit of the prior stage in the previous clock cycle.
However, the nop bit is also used to implement stalls that result from a RAW hazard or to squash speculatively fetched instructions if the branch condition evaluates to TAKEN. See slides for more details on implementing stalls and squashing instructions.
The HALT Instruction
The halt instruction is a “custom” instruction we introduced so you know when to stop the simulation. When a HALT instruction is fetched in the IF stage at cycle N, the nopbit of the IF stage in the next clock cycle (cycle N+1) is set to 1 and subsequently stays at 1. The nopbit of the ID/RF stage is set to 1 in cycle N+1 and subsequently stays at 1. The nop bit of the EX stage is set to 1 in cycle N+2 and subsequently stays at 1. The nopbit of the MEM stage is set to 1 in cycle N+3 and subsequently stays at 1. The nopbit of the WB stage is set to 1 in cycle N+4 and subsequently stays at 1.
At the end of each clock cycle the simulator checks to see if the nop bit of each stage is 1. If so, the simulation halts. Note that this logic is already implemented in the skeleton code provided to you.
What to Output?
Make sure that the architectural state is updated correctly after the execution of each instruction. The architectural state consists of the Program Counter (PC), the Register File (RF), and the Data Memory (DataMem). We will check the correctness of the architectural state after each instruction. Your simulator will output the values of all flip-flops at the end of each clock cycle.
Specifically, the OutputRF() function is called at the end of each iteration of the while loop, and will add the new state of the Register File to “RFresult.txt”. Therefore, at the end of the program execution
“RFresult.txt” contains all the intermediate states of the Register File. Once the program terminates, the OutputDataMem() function will write the final state of the Data Memory to “dmemresult.txt”. These
functions have been implemented for you. Do not modify them.
(Note: You should delete the “RFresult.txt” and “dmemresult.txt” files before re-executing your program, otherwise the new results will append to the previous results.)
Your Assignment:
1. We have provided the skeleton code in the file MIPS_pipeline.cpp.
a. A Makefile has been provided for you to compile the source code (do not modify the Makefile)
b. We will be compiling your code with: g++ version 11.3.0. Please make sure that your code is compatible with g++. See 4. for more detail abo
2023-09-27