Architecture of Computer Assignment 4. Improving the Pipelined CPU
Assignment 3에서 구현했던 Piplined CPU에 Dataforwarding 기능과 HazardDetection 기능을 추가하는 과제다.
어제 밤 9시부터 새벽 5시, 아침 9시부터 저녁 7시까지 컴퓨터 앞에 앉아서 vscode와 virtual machine만 뚫어지게 본 결과 과제를 해낼 수 있었다. 총 18시간 ㄷㄷㄷ.. 잠자는거 포함해서 22시간 동안 커피 한잔 밖에 먹은게 없다.
기본적인 Skeleton Code는 교수님이 제공해주시고, 핵심 코드인 PipelinedCPU.cpp 코드만 작성하는 것이 과제였다. 그래도 나름 과제3을 기반으로 하는 과제라 쉬울 줄 알았는데(과제3 만점 받았음) 생각보다 쉽지 않았다. 나만 어려웠던건지, 계속 이해 안되는 사소한 에러가 발생했다. 잘 안됐던 부분이 워낙에 많아서 다 기억나지도 않는다. 그래도 하나하나 출력디버깅 하고 출력예시와 비교해가면서 진짜 바느질 하듯이 한땀 한땀 하나씩 고쳐나갔다.
한 줄 작성 완료하면 잘 작동하는지 확인하고, 또 한 줄 작성하고 확인하고...
함수 하나 만들어지면 함수 잘 기능하는지 확인하고, 안되면 어디서 안되는지 출력디버깅 해서 확인하고 뜯어고치고
그래도 나름 재밌었다. 솔직히 과제 1,2,3,4에 들어간 시간 모두 합치면 거의 100~150시간 정도 나올 거 같은데, 너무너무 힘들기도 했지만 다 만들고 나면 이것 만큼 기분 좋은 과제 없었다.
과제 내용 관련해서 설명을 더 쓰고 싶은데, 이거는 나중에 시간 내서 컴퓨터 아키텍쳐 수업에서 배웠던 내용들을 정리해서 올려봐야겠다.
PipelinedCPU.cpp 완성본
#include "PipelinedCPU.hpp"
void PipelinedCPU::InstructionFetch() {
std::bitset<1> one(1), trash(0);
std::bitset<1> zero(0);
std::bitset<32> four(4);
HazardDetectionUnit(&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_EX_to_HazDetUnit_memRead,
&m_EX_to_HazDetUnit_rt,
&m_HazDetUnit_to_IF_PCWrite,
&m_HazDetUnit_to_IF_IFIDWrite,
&trash);
CPU::Add(&m_PC, &four, &m_latch_IF_ID.pcPlus4);
CPU::Mux(&m_PC, &m_latch_IF_ID.pcPlus4, &m_HazDetUnit_to_IF_PCWrite, &m_PC);
CPU::Add(&m_PC, &four, &m_latch_IF_ID.pcPlus4);
std::bitset<32> tempisntr;
m_instMemory->access(&m_PC, nullptr, &one, &zero, &tempisntr);
CPU::Mux(&m_latch_IF_ID.instr, &tempisntr, &m_HazDetUnit_to_IF_IFIDWrite, &m_latch_IF_ID.instr);
}
void PipelinedCPU::InstructionDecode() {
m_latch_ID_EX.pcPlus4 = m_latch_IF_ID.pcPlus4;
std::bitset<6> opcode = m_latch_IF_ID.instr.to_ulong() >> 26;
std::bitset<32> temp = m_latch_IF_ID.instr.to_ulong() >> 21;
std::bitset<5> rs = temp.to_ulong();
m_latch_ID_EX.instr_25_21 = rs;
temp = m_latch_IF_ID.instr.to_ulong() >> 16;
std::bitset<5> rt = temp.to_ulong();
m_latch_ID_EX.instr_20_16 = rt;
temp = m_latch_IF_ID.instr.to_ulong() >> 11;
m_latch_ID_EX.instr_15_11 = temp.to_ulong();
std::bitset<16> instr_15_0 = m_latch_IF_ID.instr.to_ulong();
CPU::SignExtend<16, 32>(&instr_15_0, &m_latch_ID_EX.immediate);
m_registerFile->access(&rs, &rt, nullptr, nullptr, nullptr, &m_latch_ID_EX.readData1, &m_latch_ID_EX.readData2);
CPU::Control(&opcode,
&m_latch_ID_EX.ctrlEXRegDst,
&m_latch_ID_EX.ctrlMEMBranch,
&m_latch_ID_EX.ctrlMEMMemRead,
&m_latch_ID_EX.ctrlWBMemToReg,
&m_latch_ID_EX.ctrlEXALUOp,
&m_latch_ID_EX.ctrlMEMMemWrite,
&m_latch_ID_EX.ctrlEXALUSrc,
&m_latch_ID_EX.ctrlWBRegWrite);
std::bitset<1> ctrlSelect, zero(0);
std::bitset<2> zero2(0);
HazardDetectionUnit(&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_EX_to_HazDetUnit_memRead,
&m_EX_to_HazDetUnit_rt,
&m_HazDetUnit_to_IF_PCWrite,
&m_HazDetUnit_to_IF_IFIDWrite,
&ctrlSelect);
CPU::Mux(&m_latch_ID_EX.ctrlEXRegDst, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlEXRegDst);
CPU::Mux(&m_latch_ID_EX.ctrlMEMBranch, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMBranch);
CPU::Mux(&m_latch_ID_EX.ctrlMEMMemRead, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMMemRead);
CPU::Mux(&m_latch_ID_EX.ctrlWBMemToReg, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlWBMemToReg);
CPU::Mux(&m_latch_ID_EX.ctrlEXALUOp, &zero2, &ctrlSelect, &m_latch_ID_EX.ctrlEXALUOp);
CPU::Mux(&m_latch_ID_EX.ctrlMEMMemWrite, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMMemWrite);
CPU::Mux(&m_latch_ID_EX.ctrlEXALUSrc, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlEXALUSrc);
CPU::Mux(&m_latch_ID_EX.ctrlWBRegWrite, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlWBRegWrite);
}
void PipelinedCPU::Execute() {
std::bitset<32> immed4;
CPU::ShiftLeft2(&m_latch_ID_EX.immediate, &immed4);
CPU::Add(&immed4, &m_latch_ID_EX.pcPlus4, &m_latch_EX_MEM.branchTarget);
std::bitset<32> temp = m_latch_ID_EX.immediate.to_ulong();
std::bitset<6> funct = temp.to_ulong();
std::bitset<4> aluControl;
CPU::ALUControl(&m_latch_ID_EX.ctrlEXALUOp, &funct, &aluControl);
std::bitset<2> forwardA, forwardB;
ForwardingUnit(
&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_MEM_to_FwdUnit_regWrite, &m_MEM_to_FwdUnit_rd,
&m_WB_to_FwdUnit_regWrite, &m_WB_to_FwdUnit_rd,
&forwardA, &forwardB
);
PipelinedCPU::Mux<32>(&m_latch_ID_EX.readData1, &m_WB_to_FwdUnit_rdValue, &m_MEM_to_FwdUnit_rdValue, &forwardA, &m_latch_ID_EX.readData1);
PipelinedCPU::Mux<32>(&m_latch_ID_EX.readData2, &m_WB_to_FwdUnit_rdValue, &m_MEM_to_FwdUnit_rdValue, &forwardB, &m_latch_ID_EX.readData2);
CPU::Mux<5>(&m_latch_ID_EX.instr_20_16, &m_latch_ID_EX.instr_15_11, &m_latch_ID_EX.ctrlEXRegDst, &m_latch_EX_MEM.rd);
std::bitset<32> ex;
CPU::Mux(&m_latch_ID_EX.readData2, &m_latch_ID_EX.immediate, &m_latch_ID_EX.ctrlEXALUSrc, &ex);
CPU::ALU(&m_latch_ID_EX.readData1, &ex, &aluControl, &m_latch_EX_MEM.aluResult, &m_latch_EX_MEM.aluZero);
m_EX_to_HazDetUnit_memRead = m_latch_ID_EX.ctrlMEMMemRead;
m_EX_to_HazDetUnit_rt = m_latch_ID_EX.instr_20_16;
m_latch_EX_MEM.readData2 = m_latch_ID_EX.readData2;
m_latch_EX_MEM.ctrlMEMBranch = m_latch_ID_EX.ctrlMEMBranch;
m_latch_EX_MEM.ctrlMEMMemRead = m_latch_ID_EX.ctrlMEMMemRead;
m_latch_EX_MEM.ctrlMEMMemWrite = m_latch_ID_EX.ctrlMEMMemWrite;
m_latch_EX_MEM.ctrlWBRegWrite = m_latch_ID_EX.ctrlWBRegWrite;
m_latch_EX_MEM.ctrlWBMemToReg = m_latch_ID_EX.ctrlWBMemToReg;
}
void PipelinedCPU::MemoryAccess() {
std::bitset<32> branchbit = m_PC;
std::bitset<32> mfour(-4);
CPU::Add(&m_latch_EX_MEM.branchTarget, &mfour, &m_MEM_to_IF_branchTarget);
CPU::AND<1>(&m_latch_EX_MEM.ctrlMEMBranch, &m_latch_EX_MEM.aluZero, &m_MEM_to_IF_PCSrc);
CPU::Mux(&branchbit, &m_MEM_to_IF_branchTarget, &m_MEM_to_IF_PCSrc, &m_PC);
m_dataMemory->access(&m_latch_EX_MEM.aluResult, &m_latch_EX_MEM.readData2, &m_latch_EX_MEM.ctrlMEMMemRead, &m_latch_EX_MEM.ctrlMEMMemWrite, &m_latch_MEM_WB.readData);
m_latch_MEM_WB.aluResult = m_latch_EX_MEM.aluResult;
m_latch_MEM_WB.rd = m_latch_EX_MEM.rd;
m_latch_MEM_WB.ctrlWBRegWrite = m_latch_EX_MEM.ctrlWBRegWrite;
m_latch_MEM_WB.ctrlWBMemToReg = m_latch_EX_MEM.ctrlWBMemToReg;
m_MEM_to_FwdUnit_regWrite = m_latch_EX_MEM.ctrlWBRegWrite;
m_MEM_to_FwdUnit_rd = m_latch_EX_MEM.rd;
m_MEM_to_FwdUnit_rdValue = m_latch_EX_MEM.aluResult;
}
void PipelinedCPU::WriteBack() {
std::bitset<32> writeData;
CPU::Mux(&m_latch_MEM_WB.aluResult, &m_latch_MEM_WB.readData, &m_latch_MEM_WB.ctrlWBMemToReg, &writeData);
m_registerFile->access(nullptr, nullptr, &m_latch_MEM_WB.rd, &writeData, &m_latch_MEM_WB.ctrlWBRegWrite, nullptr, nullptr);
m_WB_to_FwdUnit_regWrite = m_latch_MEM_WB.ctrlWBRegWrite;
m_WB_to_FwdUnit_rd = m_latch_MEM_WB.rd;
m_WB_to_FwdUnit_rdValue = writeData;
}
void PipelinedCPU::ForwardingUnit(
const std::bitset<5> *ID_EX_rs, const std::bitset<5> *ID_EX_rt,
const std::bitset<1> *EX_MEM_regWrite, const std::bitset<5> *EX_MEM_rd,
const std::bitset<1> *MEM_WB_regWrite, const std::bitset<5> *MEM_WB_rd,
std::bitset<2> *forwardA, std::bitset<2> *forwardB
) {
std::bitset<1> zero(0), one(1), tempa, tempb, temp, check, onetp;
std::bitset<2> one2(1), two2(2), zero2(0);
std::bitset<5> zero5(0), sum, temp1, temp2;
CPU::Mux(&one, &zero, MEM_WB_regWrite, &check);
onetp = MEM_WB_rd->to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
temp = MEM_WB_rd->none(); CPU::Mux(&check, &one, &temp, &check);
CPU::Mux(&one2, &zero2, &check, forwardA);
CPU::Mux(&one, &zero, MEM_WB_regWrite, &check);
onetp = MEM_WB_rd->to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = MEM_WB_rd->to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
temp = MEM_WB_rd->none(); CPU::Mux(&check, &one, &temp, &check);
CPU::Mux(&one2, &zero2, &check, forwardB);
CPU::Mux(&one, &zero, EX_MEM_regWrite, &check);
onetp = EX_MEM_rd->to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = ID_EX_rs->to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
temp = EX_MEM_rd->none(); CPU::Mux(&check, &one, &temp, &check);
CPU::Mux(&two2, forwardA, &check, forwardA);
CPU::Mux(&one, &zero, EX_MEM_regWrite, &check);
onetp = EX_MEM_rd->to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
onetp = EX_MEM_rd->to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = ID_EX_rt->to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check, &one, &temp, &check);
temp = EX_MEM_rd->none(); CPU::Mux(&check, &one, &temp, &check);
CPU::Mux(&two2, forwardB, &check, forwardB);
}
void PipelinedCPU::HazardDetectionUnit(
const std::bitset<5> *IF_ID_rs, const std::bitset<5> *IF_ID_rt,
const std::bitset<1> *ID_EX_memRead, const std::bitset<5> *ID_EX_rt,
std::bitset<1> *PCWrite, std::bitset<1> *IFIDWrite, std::bitset<1> *ctrlSelect
) {
std::bitset<1> one(1), zero(0), check1, check2, tempa, tempb, temp, check, onetp;
std::bitset<5> rs = *IF_ID_rs, rt = *IF_ID_rt, exrt = *ID_EX_rt;
onetp = exrt.to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = rs.to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&zero, &one, &temp, &check1);
onetp = exrt.to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = rs.to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check1, &one, &temp, &check1);
onetp = exrt.to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = rs.to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check1, &one, &temp, &check1);
onetp = exrt.to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = rs.to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check1, &one, &temp, &check1);
onetp = exrt.to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = rs.to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check1, &one, &temp, &check1);
onetp = exrt.to_ulong() >> 0; tempa = onetp.to_ulong(); onetp = rt.to_ulong() >> 0; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&zero, &one, &temp, &check2);
onetp = exrt.to_ulong() >> 1; tempa = onetp.to_ulong(); onetp = rt.to_ulong() >> 1; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check2, &one, &temp, &check2);
onetp = exrt.to_ulong() >> 2; tempa = onetp.to_ulong(); onetp = rt.to_ulong() >> 2; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check2, &one, &temp, &check2);
onetp = exrt.to_ulong() >> 3; tempa = onetp.to_ulong(); onetp = rt.to_ulong() >> 3; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check2, &one, &temp, &check2);
onetp = exrt.to_ulong() >> 4; tempa = onetp.to_ulong(); onetp = rt.to_ulong() >> 4; tempb = onetp.to_ulong(); temp = tempa ^ tempb;
CPU::Mux(&check2, &one, &temp, &check2);
CPU::AND(&check1, &check2, &check);
CPU::Mux(&zero, &one, &check, PCWrite);
CPU::Mux(&one, PCWrite, ID_EX_memRead, PCWrite);
CPU::Mux(&zero, &one, &check, IFIDWrite);
CPU::Mux(&one, IFIDWrite, ID_EX_memRead, IFIDWrite);
CPU::Mux(&one, &zero, &check, ctrlSelect);
CPU::Mux(&zero, ctrlSelect, ID_EX_memRead, ctrlSelect);
}
ForwardingUnit 과 HazardDetectionUnit 메소드의 코드를 보면, 비슷한 형태의 코드가 반복되는 걸 볼 수 있다. 내가 봐도 너무 가독성 떨어진다. 이게 다 if 문이나 그 외 로직 등을 사용하면 감점시키는 영컴아 과제시스템의 문제다!! (실제로 Assignment2. SingleCycleCPU 구현할 때 if 문 썼다고 20점이나 감점하심 ㅜㅜㅠ)
챗지피티한테 Mux와 Add메소드 만을 활용해서 If문 기능을 구현하려면 어떻게 코딩해야하는지 물어봤었는데, 자꾸 엉뚱한 대답만 내놔서 그냥 내 생각 내 맘대로 짜봤다.
사실 저렇게 많은 양의 코드가 필요 없었을 수도 있다. 내가 bitset에 익숙하지 않기도 하고, 저거 작성할 때 거의 정신이 반 쯤 나가있었다. 지금 생각해보니 아마 Add랑 bit.none() 어떻게 잘 활용했으면 훨씬 짧게도 가능했을 수도? 근데 알빠노 어차피 작동만 하면 점수는 받는다.
아래는 중간에 if문 사용해서 작성했던 코드다. if문 사용이 가능하다고 가정하고 나머지를 구현 한 후, if문을 다른 코드로 대체해줬다. 이거 구현하는 데도 3시간 가까이 걸렸던 것 같다.
#include "PipelinedCPU.hpp"
void PipelinedCPU::InstructionFetch() {
std::bitset<1> one(1), trash(0);
std::bitset<1> zero(0);
std::bitset<32> four(4);
HazardDetectionUnit(&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_EX_to_HazDetUnit_memRead,
&m_EX_to_HazDetUnit_rt,
&m_HazDetUnit_to_IF_PCWrite,
&m_HazDetUnit_to_IF_IFIDWrite,
&trash);
CPU::Add(&m_PC, &four, &m_latch_IF_ID.pcPlus4);
CPU::Mux(&m_PC, &m_latch_IF_ID.pcPlus4, &m_HazDetUnit_to_IF_PCWrite, &m_PC);
CPU::Add(&m_PC, &four, &m_latch_IF_ID.pcPlus4);
std::bitset<32> tempisntr;
m_instMemory->access(&m_PC, nullptr, &one, &zero, &tempisntr);
CPU::Mux(&m_latch_IF_ID.instr, &tempisntr, &m_HazDetUnit_to_IF_IFIDWrite, &m_latch_IF_ID.instr);
}
void PipelinedCPU::InstructionDecode() {
m_latch_ID_EX.pcPlus4 = m_latch_IF_ID.pcPlus4;
std::bitset<6> opcode = m_latch_IF_ID.instr.to_ulong() >> 26;
std::bitset<32> temp = m_latch_IF_ID.instr.to_ulong() >> 21;
std::bitset<5> rs = temp.to_ulong();
m_latch_ID_EX.instr_25_21 = rs;
temp = m_latch_IF_ID.instr.to_ulong() >> 16;
std::bitset<5> rt = temp.to_ulong();
m_latch_ID_EX.instr_20_16 = rt;
temp = m_latch_IF_ID.instr.to_ulong() >> 11;
m_latch_ID_EX.instr_15_11 = temp.to_ulong();
std::bitset<16> instr_15_0 = m_latch_IF_ID.instr.to_ulong();
CPU::SignExtend<16, 32>(&instr_15_0, &m_latch_ID_EX.immediate);
m_registerFile->access(&rs, &rt, nullptr, nullptr, nullptr, &m_latch_ID_EX.readData1, &m_latch_ID_EX.readData2);
CPU::Control(&opcode,
&m_latch_ID_EX.ctrlEXRegDst,
&m_latch_ID_EX.ctrlMEMBranch,
&m_latch_ID_EX.ctrlMEMMemRead,
&m_latch_ID_EX.ctrlWBMemToReg,
&m_latch_ID_EX.ctrlEXALUOp,
&m_latch_ID_EX.ctrlMEMMemWrite,
&m_latch_ID_EX.ctrlEXALUSrc,
&m_latch_ID_EX.ctrlWBRegWrite);
std::bitset<1> ctrlSelect, zero(0);
std::bitset<2> zero2(0);
HazardDetectionUnit(&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_EX_to_HazDetUnit_memRead,
&m_EX_to_HazDetUnit_rt,
&m_HazDetUnit_to_IF_PCWrite,
&m_HazDetUnit_to_IF_IFIDWrite,
&ctrlSelect);
CPU::Mux(&m_latch_ID_EX.ctrlEXRegDst, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlEXRegDst);
CPU::Mux(&m_latch_ID_EX.ctrlMEMBranch, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMBranch);
CPU::Mux(&m_latch_ID_EX.ctrlMEMMemRead, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMMemRead);
CPU::Mux(&m_latch_ID_EX.ctrlWBMemToReg, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlWBMemToReg);
CPU::Mux(&m_latch_ID_EX.ctrlEXALUOp, &zero2, &ctrlSelect, &m_latch_ID_EX.ctrlEXALUOp);
CPU::Mux(&m_latch_ID_EX.ctrlMEMMemWrite, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlMEMMemWrite);
CPU::Mux(&m_latch_ID_EX.ctrlEXALUSrc, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlEXALUSrc);
CPU::Mux(&m_latch_ID_EX.ctrlWBRegWrite, &zero, &ctrlSelect, &m_latch_ID_EX.ctrlWBRegWrite);
}
void PipelinedCPU::Execute() {
std::bitset<32> immed4;
CPU::ShiftLeft2(&m_latch_ID_EX.immediate, &immed4);
CPU::Add(&immed4, &m_latch_ID_EX.pcPlus4, &m_latch_EX_MEM.branchTarget);
std::bitset<32> temp = m_latch_ID_EX.immediate.to_ulong();
std::bitset<6> funct = temp.to_ulong();
std::bitset<4> aluControl;
CPU::ALUControl(&m_latch_ID_EX.ctrlEXALUOp, &funct, &aluControl);
std::bitset<2> forwardA, forwardB;
ForwardingUnit(
&m_latch_ID_EX.instr_25_21, &m_latch_ID_EX.instr_20_16,
&m_MEM_to_FwdUnit_regWrite, &m_MEM_to_FwdUnit_rd,
&m_WB_to_FwdUnit_regWrite, &m_WB_to_FwdUnit_rd,
&forwardA, &forwardB
);
PipelinedCPU::Mux<32>(&m_latch_ID_EX.readData1, &m_WB_to_FwdUnit_rdValue, &m_MEM_to_FwdUnit_rdValue, &forwardA, &m_latch_ID_EX.readData1);
PipelinedCPU::Mux<32>(&m_latch_ID_EX.readData2, &m_WB_to_FwdUnit_rdValue, &m_MEM_to_FwdUnit_rdValue, &forwardB, &m_latch_ID_EX.readData2);
CPU::Mux<5>(&m_latch_ID_EX.instr_20_16, &m_latch_ID_EX.instr_15_11, &m_latch_ID_EX.ctrlEXRegDst, &m_latch_EX_MEM.rd);
std::bitset<32> ex;
CPU::Mux(&m_latch_ID_EX.readData2, &m_latch_ID_EX.immediate, &m_latch_ID_EX.ctrlEXALUSrc, &ex);
CPU::ALU(&m_latch_ID_EX.readData1, &ex, &aluControl, &m_latch_EX_MEM.aluResult, &m_latch_EX_MEM.aluZero);
m_EX_to_HazDetUnit_memRead = m_latch_ID_EX.ctrlMEMMemRead;
m_EX_to_HazDetUnit_rt = m_latch_ID_EX.instr_20_16;
m_latch_EX_MEM.readData2 = m_latch_ID_EX.readData2;
m_latch_EX_MEM.ctrlMEMBranch = m_latch_ID_EX.ctrlMEMBranch;
m_latch_EX_MEM.ctrlMEMMemRead = m_latch_ID_EX.ctrlMEMMemRead;
m_latch_EX_MEM.ctrlMEMMemWrite = m_latch_ID_EX.ctrlMEMMemWrite;
m_latch_EX_MEM.ctrlWBRegWrite = m_latch_ID_EX.ctrlWBRegWrite;
m_latch_EX_MEM.ctrlWBMemToReg = m_latch_ID_EX.ctrlWBMemToReg;
}
void PipelinedCPU::MemoryAccess() {
std::bitset<32> branchbit = m_PC;
std::bitset<32> mfour(-4);
CPU::Add(&m_latch_EX_MEM.branchTarget, &mfour, &m_MEM_to_IF_branchTarget);
CPU::AND<1>(&m_latch_EX_MEM.ctrlMEMBranch, &m_latch_EX_MEM.aluZero, &m_MEM_to_IF_PCSrc);
CPU::Mux(&branchbit, &m_MEM_to_IF_branchTarget, &m_MEM_to_IF_PCSrc, &m_PC);
m_dataMemory->access(&m_latch_EX_MEM.aluResult, &m_latch_EX_MEM.readData2, &m_latch_EX_MEM.ctrlMEMMemRead, &m_latch_EX_MEM.ctrlMEMMemWrite, &m_latch_MEM_WB.readData);
m_latch_MEM_WB.aluResult = m_latch_EX_MEM.aluResult;
m_latch_MEM_WB.rd = m_latch_EX_MEM.rd;
m_latch_MEM_WB.ctrlWBRegWrite = m_latch_EX_MEM.ctrlWBRegWrite;
m_latch_MEM_WB.ctrlWBMemToReg = m_latch_EX_MEM.ctrlWBMemToReg;
m_MEM_to_FwdUnit_regWrite = m_latch_EX_MEM.ctrlWBRegWrite;
m_MEM_to_FwdUnit_rd = m_latch_EX_MEM.rd;
m_MEM_to_FwdUnit_rdValue = m_latch_EX_MEM.aluResult;
}
void PipelinedCPU::WriteBack() {
std::bitset<32> writeData;
CPU::Mux(&m_latch_MEM_WB.aluResult, &m_latch_MEM_WB.readData, &m_latch_MEM_WB.ctrlWBMemToReg, &writeData);
m_registerFile->access(nullptr, nullptr, &m_latch_MEM_WB.rd, &writeData, &m_latch_MEM_WB.ctrlWBRegWrite, nullptr, nullptr);
m_WB_to_FwdUnit_regWrite = m_latch_MEM_WB.ctrlWBRegWrite;
m_WB_to_FwdUnit_rd = m_latch_MEM_WB.rd;
m_WB_to_FwdUnit_rdValue = writeData;
}
void PipelinedCPU::ForwardingUnit(
const std::bitset<5> *ID_EX_rs, const std::bitset<5> *ID_EX_rt,
const std::bitset<1> *EX_MEM_regWrite, const std::bitset<5> *EX_MEM_rd,
const std::bitset<1> *MEM_WB_regWrite, const std::bitset<5> *MEM_WB_rd,
std::bitset<2> *forwardA, std::bitset<2> *forwardB
) {
*forwardA = std::bitset<2>(0);
*forwardB = std::bitset<2>(0);
if (*MEM_WB_regWrite == std::bitset<1>(1) && *MEM_WB_rd != std::bitset<5>(0) && *MEM_WB_rd == *ID_EX_rs)
*forwardA = std::bitset<2>(1);
if (*MEM_WB_regWrite == std::bitset<1>(1) && *MEM_WB_rd != std::bitset<5>(0) && *MEM_WB_rd == *ID_EX_rt)
*forwardB = std::bitset<2>(1);
if (*EX_MEM_regWrite == std::bitset<1>(1) && *EX_MEM_rd != std::bitset<5>(0) && *EX_MEM_rd == *ID_EX_rs)
*forwardA = std::bitset<2>(2);
if (*EX_MEM_regWrite == std::bitset<1>(1) && *EX_MEM_rd != std::bitset<5>(0) && *EX_MEM_rd == *ID_EX_rt)
*forwardB = std::bitset<2>(2);
}
void PipelinedCPU::HazardDetectionUnit(
const std::bitset<5> *IF_ID_rs, const std::bitset<5> *IF_ID_rt,
const std::bitset<1> *ID_EX_memRead, const std::bitset<5> *ID_EX_rt,
std::bitset<1> *PCWrite, std::bitset<1> *IFIDWrite, std::bitset<1> *ctrlSelect
) {
if (*ID_EX_memRead == std::bitset<1>(1) && (*ID_EX_rt == *IF_ID_rs || *ID_EX_rt == *IF_ID_rt))
{
*PCWrite = std::bitset<1>(0);
*IFIDWrite = std::bitset<1>(0);
*ctrlSelect = std::bitset<1>(1);
}
else
{
*PCWrite = std::bitset<1>(1);
*IFIDWrite = std::bitset<1>(1);
*ctrlSelect = std::bitset<1>(0);
}
}
만약에 미래에 영컴아를 수강하는 사람이 이 게시글을 보게 된다면, 고민하지 말고 그대로 코드 복사해서 제출하면 될 것 같다. 100점 받을 코드니까 ㅋㅋㅋ
드디어 종강이다.
하하~ 이제 내가 풀고 싶은 알고리즘 문제 풀고, 하고 싶은 공부도 마음껏 할 수 있다.
칼바람 3판만 하고 백준 문제 풀어야겠다.
'diary' 카테고리의 다른 글
ClapSynchronize test site 구현 (1) | 2023.06.23 |
---|---|
기록 시작 (4) | 2023.06.23 |