懂的都懂
IF/ID | ID/EX | EX/MEM | MEM/WB | WB/END |
---|---|---|---|---|
instr |
instr |
instr |
instr |
instr |
pcPlus1 |
pcPlus1 |
branchTarget |
writeData |
writeData |
readRegA |
aluResult |
|||
readRegB |
readRegB |
|||
offset |
opcode | effect | 10987654321098765432109876543210 |
---|---|---|
add | rgD = rgA + rgB |
_______000rgArgB_____________rgD |
nor | rgD = rgA nor rgB |
_______001rgArgB_____________rgD |
lw | rgB = [rgA+offset] |
_______010rgArgB--offset-Field-- |
sw | [rgA+offset] = rgB |
_______011rgArgB--offset-Field-- |
beq | PC = (rgA==rgB) ? PC+1+offset : PC+1 |
_______100rgArgB--offset-Field-- |
halt | _______110______________________ |
|
noop | _______111______________________ |
Hazard Detection and Forward
Compare regA regB with destination reg in IDEX/EXMEM/MEMWB with opcode (add, nor, lw).
Stall once if lw
followed by a sw
and a hazard detected. (LW hazard)
Hazard Detection:
Once take the branch, change first three instructions into noop.
-
read instruction from instrMem[PC] and pass
-
calculate and pass PC+1
-
get PC as PC+1 or branchTarget based on ALUresult & instr in EXMEM
-
pass instr
-
pass PC+1
-
read RegA
-
read RegB
-
decode offset
-
pass instr
-
get the correct first ALU operand from somewhere (LIDEX.readRegA, LEXMEM.aluResult, LMEMWB.writeData, or LWBEND.writeData)
-
get the correct second ALU operand from somewhere (LIDEX.readRegB, LIDEX.offset, LEXMEM.aluResult, LMEMWB.writeData, or LWBEND.writeData)
-
calculate aluResult as add
-
calculate aluResult as nor
-
calculate aluResult as eq
-
calculate branchTarget according to eq
-
pass a correct valB from somewhere
-
pass instr
-
pass writeData as ALUresult
-
pass writeData as dataMem[aluResult]
-
write valB in dataMem[aluResult]
-
pass instr
-
pass writeData
-
save writeData to reg[dest]
op | IF | ID | EX | MEM | WB |
---|---|---|---|---|---|
add | 1,2,3 | 4,5,6,7,8 | 9,10,11,12,15,16 | 17,18 | 21,22,23 |
nor | 1,2,3 | 4,5,6,7,8 | 9,10,11,13,15,16 | 17,18 | 21,22,23 |
lw | 1,2,3 | 4,5,6,7,8 | 9,10,11,12,15,16 | 17,19 | 21,22,23 |
sw | 1,2,3 | 4,5,6,7,8 | 9,10,11,12,15,16 | 17,20 | 21,22 |
beq | 1,2,3 | 4,5,6,7,8 | 9,10,11,14,15,16 | 17,18 | 21,22 |
halt | 1,2,3 | 4,5,6,7,8 | 9,15,16 | 17 | 21 |
noop | 1,2,3 | 4,5,6,7,8 | 9,15,16 | 17 | 21 |
beq take | noop the first three instructions | ||||
LW hazard | do nothing | noop current instruction |
- Scrutinize lecture slides first.
- Write a function to find the correct value of a register (doing detection and forwarding).
- Make a MACRO for repetitive work.
- Compare your memory and register state with a correct simulator (in project1) after HALT.
#!/bin/bash
# WSL or Linux only!
# This file will automatically test your project on all *.as in current directory with properly configured:
# 1. classic.c for the simulator in project 1
# 2. simulator.c and classic.c should output the content in memory and regfiles to `output` and `output.ans, respectively (do it under -DTEST flag).
# 3. run with ./
gcc simulator.c -Wall -Wextra -Wpedantic -g -o simulator -DTEST
gcc classic.c -Wall -Wextra -Wpedantic -g -o classic -DTEST
allas=$(ls *.as)
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
for i in $allas; do
./assembler $i $i.mc
./simulator $i.mc > $i.out
k1=$?
./classic $i.mc > $i.ans
k2=$?
diff output output.ans # memory and regfiles printed to file
if (( k1==0 && k2==0 && $? == 0 )); then
echo -e "$GREEN$i passed.$NC"
rm $i.out
rm $i.ans
rm $i.mc # uncomment for further debuging
else
echo -e "$RED$i failed.$NC"
fi
done