HW4 - Kontrack/for_wiki GitHub Wiki
๋ชฉํ
- upgrade single cycle CPU into a multicycle CPU
- Defining additional control signals for multi-cycle architecture
- Building an FSM to control multi-cycle execution
- Supporting jal and jr


- State Control
- IRWrite: Instruction Register์ ๋ฉ๋ชจ๋ฆฌ๋ก๋ถํฐ ์ฝ์ ๋ช
๋ น์ด๋ฅผ ์ ์ฅํ ์ง ๊ฒฐ์
- PCWrite: Program Counter ์ ๋ฐ์ดํธ ์ฌ๋ถ๋ฅผ ๊ฒฐ์
- PCWriteCond: Branch ๋ช ๋ น์ด์์ ์กฐ๊ฑด์ด ๋ง์กฑ๋ ๋ PC ์ ๋ฐ์ดํธ ์ฌ๋ถ๋ฅผ ๊ฒฐ์
- Memory Access Control
- IorD: Memory ์ฃผ์๋ก PC๋ฅผ ์ฌ์ฉํ ์ง(0) ALUOut์ ์ฌ์ฉํ ์ง(1) ๊ฒฐ์
- ALU Input Control
- ALUSrcA[1:0]: ALU์ ์ฒซ ๋ฒ์งธ ์
๋ ฅ ์ ํ
- 00: PC
- 01: Register A
- 10: Don't care
- 11: Don't care
- ALUSrcB[1:0]: ALU์ ๋ ๋ฒ์งธ ์
๋ ฅ ์ ํ
- 00: Register B
- 01: 4 (PC increment)
- 10: Sign-extended immediate
- 11: Shifted sign-extended immediate
- PC Source Control
- PCSource[1:0]: ๋ค์ PC ๊ฐ ์ ํ
- 00: ALU Result
- 01: ALUOut
- 10: Jump Target ({PC[31:28], immediate[25:0], 2'b00})
- 11: Register A (JR instruction)
- Register Write Control
- SavePC: JAL ๋ช ๋ น์ด์์ return address๋ฅผ $ra์ ์ ์ฅํ ์ง ๊ฒฐ์
- jal_save: JAL ๋ช ๋ น์ด ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ด๋ถ ์ํ ์ ์ฅ

- S0_IFETCH:
- ๋์: IR โ Memory[PC], PC โ PC + 4
- ์ ์ด: ๋ฌด์กฐ๊ฑด S1_IDECODE๋ก
- S1_IDECODE:
- ๋์: A โ Reg[rs], B โ Reg[rt]
- ์ ์ด ์กฐ๊ฑด: opcode์ ๋ฐ๋ผ ๋ค๋ฅธ ์ํ๋ก
- R-type โ S2_RTYPE_EXEC
- I-type โ S2_ITYPE_EXEC
- BEQ/BNE โ S2_BRANCH_COMP
- JAL โ S2_JAL_SAVE
- JR โ S2_JR
- LW โ S2_LW_ADDR
- SW โ S2_SW_ADDR
- ๊ฐ ์คํ ์ํ:
- S2_RTYPE_EXEC: ALUOut โ ALU(A,B)
- S2_ITYPE_EXEC: ALUOut โ ALU(A,imm)
- S2_BRANCH_COMP: ALUOut โ ALU(A,B) (EQ/NEQ ๋น๊ต)
- S2_JAL_SAVE: Reg[31] โ PC + 4
- S2_JR: PC โ A
- ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ํ:
- S2_LW_ADDR: ALUOut โ A + SignExt(imm)
- S3_LW_MEM: MDR โ Memory[ALUOut]
- S2_SW_ADDR: ALUOut โ A + SignExt(imm)
- S3_SW_MEM: Memory[ALUOut] โ B
- Write-Back ์ํ:
- S3_RTYPE_WB: Reg[rd] โ ALUOut
- S3_ITYPE_WB: Reg[rt] โ ALUOut
- S4_LW_WB: Reg[rt] โ MDR
- CPU ์ด๊ธฐํ
void CPU::init(string inst_file) {
rf.init(false);
mem.load(inst_file);
PC = 0;
state = S0_IFETCH;
status = CONTINUE;
}
- ๊ธฐ๋ณธ ์์ฑ์๋ ๋น์ด์์
- init ํจ์๋ CPU์ ์ด๊ธฐ ์ํ๋ฅผ ์ค์ :
- rf.init(false): ๋ ์ง์คํฐ ํ์ผ ์ด๊ธฐํ
- mem.load(inst_file): ๋ฉ๋ชจ๋ฆฌ์ ๋ช ๋ น์ด ํ์ผ ๋ก๋
- PC = 0: ํ๋ก๊ทธ๋จ ์นด์ดํฐ ์ด๊ธฐํ
- state = S0_IFETCH: ์ด๊ธฐ ์ํ๋ฅผ ๋ช ๋ น์ด ํ์น๋ก ์ค์
- status = CONTINUE: CPU ์คํ ์ํ๋ฅผ ์ ์ ์คํ์ผ๋ก ์ค์
- Instruction Fetch
case S0_IFETCH: {
mem.memAccess(PC, &IR, 0, 1, 0); // MemRead
if (status != CONTINUE) return 0;
PC += 4;
state = ctrl.nextState(state, parsed_inst);
break;
}
- mem.memAccess: ๋ฉ๋ชจ๋ฆฌ์์ ๋ช
๋ น์ด ์ฝ๊ธฐ
- PC: ์ฝ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์
- &IR: ์ฝ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ช ๋ น์ด ๋ ์ง์คํฐ
- 0: ์ฐ๊ธฐ ๋ฐ์ดํฐ (์ฝ๊ธฐ๋ง ํ๋ฏ๋ก 0)
- 1: MemRead ์ ํธ
- 0: MemWrite ์ ํธ
- PC๋ฅผ 4๋งํผ ์ฆ๊ฐ (๋ค์ ๋ช ๋ น์ด ์ฃผ์)
- ๋ค์ ์ํ ๊ฒฐ์
- Instruction Decode
case S1_IDECODE: {
ctrl.splitInst(IR, &parsed_inst);
uint32_t rs_data, rt_data;
rf.read(parsed_inst.rs, parsed_inst.rt, &rs_data, &rt_data);
A = rs_data;
B = rt_data;
state = ctrl.nextState(state, parsed_inst);
break;
}
- ctrl.splitInst: ๋ช ๋ น์ด(IR)๋ฅผ ๊ฐ ํ๋๋ก ๋ถ์
- rf.read: ๋ ์ง์คํฐ ํ์ผ์์ rs์ rt ๋ ์ง์คํฐ ๊ฐ์ ์ฝ์
- A์ B ๋ ์ง์คํฐ์ ์ฝ์ ๊ฐ ์ ์ฅ
- ๋ค์ ์ํ ๊ฒฐ์
- R-type Instruction ์คํ
case S2_RTYPE_EXEC: {
uint32_t result;
alu.compute(A, B, parsed_inst.shamt, controls.ALUOp, &result);
ALUOut = result;
state = ctrl.nextState(state, parsed_inst);
break;
}
- alu.compute: ALU ์ฐ์ฐ ์ํ
- A: ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์
- B: ๋ ๋ฒ์งธ ํผ์ฐ์ฐ์
- shamt: shift amount (์ํํธ ์ฐ์ฐ์ ์ฌ์ฉ)
- ALUOp: ์ํํ ์ฐ์ฐ ์ข ๋ฅ
- result: ์ฐ์ฐ ๊ฒฐ๊ณผ
- ALUOut์ ๊ฒฐ๊ณผ ์ ์ฅ
- ๋ค์ ์ํ ๊ฒฐ์
- R-type Instruction ์ฐ๊ธฐ
case S3_RTYPE_WB: {
uint32_t dst = parsed_inst.rd;
rf.write(dst, ALUOut, controls.RegWrite);
state = S0_IFETCH;
break;
}
- rd ๋ ์ง์คํฐ๋ฅผ ๋ชฉ์ ์ง๋ก ์ค์
- rf.write: ๋ ์ง์คํฐ ํ์ผ์ ๊ฒฐ๊ณผ ์ฐ๊ธฐ
- dst: ๋ชฉ์ ์ง ๋ ์ง์คํฐ ๋ฒํธ
- ALUOut: ์ธ ๋ฐ์ดํฐ
- RegWrite: ์ฐ๊ธฐ ์ ์ด ์ ํธ
- ๋ค์ ์ํ๋ฅผ IFETCH๋ก ์ค์
- I-type Instruction ์คํ
case S2_ITYPE_EXEC: {
uint32_t imm_ext;
ctrl.signExtend(parsed_inst.immi, controls.SignExtend, &imm_ext);
uint32_t result;
alu.compute(A, imm_ext, 0, controls.ALUOp, &result);
ALUOut = result;
state = ctrl.nextState(state, parsed_inst);
break;
}
- ctrl.signExtend: immediate ๊ฐ์ ๋ถํธ ํ์ฅ
- ALU ์ฐ์ฐ ์ํ (A์ ํ์ฅ๋ immediate ๊ฐ ์ฌ์ฉ)
- ๊ฒฐ๊ณผ๋ฅผ ALUOut์ ์ ์ฅ
- I-type Instruction ์ฐ๊ธฐ
case S3_ITYPE_WB: {
rf.write(parsed_inst.rt, ALUOut, controls.RegWrite);
state = S0_IFETCH;
break;
}
- rt ๋ ์ง์คํฐ์ ๊ฒฐ๊ณผ ์ฐ๊ธฐ
- IFETCH ์ํ๋ก ๋์๊ฐ๊ธฐ
- Load/Store ์ฃผ์ ๊ณ์ฐ
case S2_LW_ADDR:
case S2_SW_ADDR: {
uint32_t imm_ext;
ctrl.signExtend(parsed_inst.immi, 1, &imm_ext);
uint32_t result;
alu.compute(A, imm_ext, 0, controls.ALUOp, &result);
ALUOut = result;
state = ctrl.nextState(state, parsed_inst);
break;
}
- Load์ Store ๋ช ๋ น์ด์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๊ณ์ฐ
- immediate ๊ฐ์ ๋ถํธ ํ์ฅ
- ๋ฒ ์ด์ค ์ฃผ์(A)์ ์คํ์ (imm_ext)์ ๋ํด ์ต์ข ์ฃผ์ ๊ณ์ฐ
- Load memory access
case S3_LW_MEM: {
cerr << "[CPU] ALUOut (byte addr): " << hex << ALUOut << endl;
mem.memAccess(ALUOut, &MDR, 0, controls.MemRead, 0);
if (status != CONTINUE) return 0;
state = ctrl.nextState(state, parsed_inst);
break;
}
- ๊ณ์ฐ๋ ์ฃผ์(ALUOut)์์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
- ์ฝ์ ๋ฐ์ดํฐ๋ฅผ MDR(Memory Data Register)์ ์ ์ฅ
- Load write
case S4_LW_WB: {
rf.write(parsed_inst.rt, MDR, controls.RegWrite);
state = S0_IFETCH;
break;
}
- MDR์ ๋ฐ์ดํฐ๋ฅผ rt ๋ ์ง์คํฐ์ ์ฐ๊ธฐ
- Store memory access
case S3_SW_MEM: {
mem.memAccess(ALUOut, nullptr, B, 0, controls.MemWrite);
if (status != CONTINUE) return 0;
state = S0_IFETCH;
break;
}
- ๊ณ์ฐ๋ ์ฃผ์(ALUOut)์ ๋ฐ์ดํฐ(B) ์ฐ๊ธฐ
- branch ๋น๊ต
case S2_BRANCH_COMP: {
uint32_t result;
alu.compute(A, B, 0, controls.ALUOp, &result);
ALUOut = result;
state = ctrl.nextState(state, parsed_inst);
break;
}
- ๋ ๋ ์ง์คํฐ ๊ฐ(A, B) ๋น๊ต
- ๋น๊ต ๊ฒฐ๊ณผ๋ฅผ ALUOut์ ์ ์ฅ
- branch ๊ฒฐ์
case S3_BRANCH_DECIDE: {
if (ALUOut == 1) {
uint32_t imm_ext;
ctrl.signExtend(parsed_inst.immi, 1, &imm_ext);
PC = PC + (static_cast<int32_t>(imm_ext) << 2);
}
state = S0_IFETCH;
break;
}
- ๋น๊ต ๊ฒฐ๊ณผ๊ฐ ์ฐธ์ด๋ฉด ๋ถ๊ธฐ ์ํ
- immediate ๊ฐ์ ๋ถํธ ํ์ฅํ๊ณ 4๋ฅผ ๊ณฑํด ์คํ์ ๊ณ์ฐ
- PC์ ์คํ์ ๋ํ๊ธฐ
- Jump
case S2_JUMP: {
PC = (PC & 0xf0000000) | (parsed_inst.immj << 2);
state = S0_IFETCH;
break;
}
case S2_JAL_SAVE: {
rf.write(31, PC, controls.RegWrite); // Save return address
state = ctrl.nextState(state, parsed_inst);
break;
}
case S3_JAL_JUMP: {
PC = (PC & 0xf0000000) | (parsed_inst.immj << 2);
state = S0_IFETCH;
break;
}
case S2_JR: {
PC = A;
state = S0_IFETCH;
break;
}
- S2_JUMP: ์ง์ jump ์ํ
- PC์ ์์ 4๋นํธ ์ ์ง, ํ์ 28๋นํธ๋ฅผ target ์ฃผ์๋ก ์ค์
- S2_JAL_SAVE: ๋ฆฌํด ์ฃผ์๋ฅผ $ra์ ์ ์ฅ
- S3_JAL_JUMP: JAL์ jump ์ํ
- S2_JR: ๋ ์ง์คํฐ์ ์ ์ฅ๋ ์ฃผ์๋ก jump
- Instruction ๋ถ์
void CTRL::splitInst(uint32_t inst, ParsedInst* parsed_inst) {
parsed_inst->opcode = (inst >> 26) & 0x3F;
parsed_inst->rs = (inst >> 21) & 0x1F;
parsed_inst->rt = (inst >> 16) & 0x1F;
parsed_inst->rd = (inst >> 11) & 0x1F;
parsed_inst->shamt = (inst >> 6) & 0x1F;
parsed_inst->funct = inst & 0x3F;
parsed_inst->immi = inst & 0xFFFF;
parsed_inst->immj = inst & 0x3FFFFFF;
}
- 32๋นํธ MIPS ๋ช ๋ น์ด๋ฅผ ๊ฐ ํ๋๋ก ๋ถ๋ฆฌ
- opcode (31-26๋นํธ): ๋ช ๋ น์ด ์ข ๋ฅ ์๋ณ (6๋นํธ)
- rs (25-21๋นํธ): ์ฒซ ๋ฒ์งธ ์์ค ๋ ์ง์คํฐ (5๋นํธ)
- rt (20-16๋นํธ): ๋ ๋ฒ์งธ ์์ค ๋ ์ง์คํฐ ๋๋ ๋ชฉ์ ์ง (5๋นํธ)
- rd (15-11๋นํธ): ๋ชฉ์ ์ง ๋ ์ง์คํฐ (R-type์ฉ, 5๋นํธ)
- shamt (10-6๋นํธ): ์ํํธ ์ (5๋นํธ)
- funct (5-0๋นํธ): ํจ์ ์ฝ๋ (R-type์ฉ, 6๋นํธ)
- immi: I-type ๋ช ๋ น์ด์ฉ immediate ๊ฐ (16๋นํธ)
- immj: J-type ๋ช ๋ น์ด์ฉ jump target (26๋นํธ)
- ๋ค์ ์ํ ๊ฒฐ์
State CTRL::nextState(State current, const ParsedInst& inst) {
switch (current) {
case S0_IFETCH:
return S1_IDECODE;
case S1_IDECODE:
switch (inst.opcode) {
case OP_RTYPE:
if (inst.funct == FUNCT_JR) return S2_JR;
else return S2_RTYPE_EXEC;
case OP_LW: return S2_LW_ADDR;
case OP_SW: return S2_SW_ADDR;
case OP_BEQ:
case OP_BNE: return S2_BRANCH_COMP;
case OP_J: return S2_JUMP;
case OP_JAL: return S2_JAL_SAVE;
case OP_ADDIU:
case OP_ANDI:
case OP_ORI:
case OP_XORI:
case OP_SLTI:
case OP_SLTIU:
case OP_LUI: return S2_ITYPE_EXEC;
default:
cerr << "[CTRL] INVALID OPCODE: " << hex << inst.opcode << endl;
status = INVALID_INST;
return S0_IFETCH;
}
- ํ์ฌ ์ํ์ ๋ช ๋ น์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ ์ํ ๊ฒฐ์
- IFETCH ์ํ ๋ค์์ ํญ์ IDECODE
- IDECODE ์ํ์์๋ opcode์ ๋ฐ๋ผ ๋ค์ ์ํ ๊ฒฐ์ :
- R-type: JR์ด๋ฉด S2_JR, ์๋๋ฉด S2_RTYPE_EXEC
- Load/Store: ์ฃผ์ ๊ณ์ฐ ์ํ๋ก
- ๋ถ๊ธฐ: ๋น๊ต ์ํ๋ก
- ์ ํ: ๊ฐ๊ฐ์ ์ ํ ์ฒ๋ฆฌ ์ํ๋ก
- I-type: ์ฆ์ ์คํ ์ํ๋ก
case S2_RTYPE_EXEC: return S3_RTYPE_WB;
case S2_ITYPE_EXEC: return S3_ITYPE_WB;
case S2_LW_ADDR: return S3_LW_MEM;
case S3_LW_MEM: return S4_LW_WB;
case S2_SW_ADDR: return S3_SW_MEM;
case S2_BRANCH_COMP: return S3_BRANCH_DECIDE;
case S2_JAL_SAVE: return S3_JAL_JUMP;
default:
return S0_IFETCH;
}
}
- ๊ฐ ์คํ ๋จ๊ณ ํ์ ๋ค์ ์ํ ์ ์
- ๋๋ถ๋ถ์ ๋ช ๋ น์ด๋ ์คํ ํ ์ฐ๊ธฐ ๋จ๊ณ๋ก
- ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ์ ์ถ๊ฐ ๋จ๊ณ ํ์
- ๊ธฐ๋ณธ์ ์ผ๋ก IFETCH๋ก ๋์๊ฐ
- control signal ์ค์
void CTRL::setControlSignals(State state, const ParsedInst& inst, Controls* c) {
c->ALUOp = 0;
c->ALUSrc = 0;
c->ALUSrcA = 0;
c->ALUSrcB = 0;
c->Branch = 0;
c->IorD = 0;
c->IRWrite = 0;
c->JR = 0;
c->Jump = 0;
c->MemRead = 0;
c->MemtoReg = 0;
c->MemWrite = 0;
c->PCSource = 0;
c->PCWrite = 0;
c->PCWriteCond = 0;
c->RegDst = 0;
c->RegWrite = 0;
c->SavePC = 0;
c->SignExtend = 0;
- ALUOp: ALU ์ฐ์ฐ ์ข ๋ฅ
- ALUSrc: ALU ์ ๋ ฅ ์ ํ
- ALUSrcA/B: ALU ์ ๋ ฅ ์์ค ์ ํ
- Branch: ๋ถ๊ธฐ ๋ช ๋ น์ด ํ์
- IorD: ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ์ ํ
- IRWrite: ๋ช ๋ น์ด ๋ ์ง์คํฐ ์ฐ๊ธฐ
- JR/Jump: ์ ํ ๊ด๋ จ ์ ์ด
- MemRead/Write: ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ ์ด
- MemtoReg: ๋ ์ง์คํฐ ์ฐ๊ธฐ ๋ฐ์ดํฐ ์ ํ
- PCSource/Write: PC ์ ์ด
- RegDst/Write: ๋ ์ง์คํฐ ํ์ผ ์ ์ด
- SignExtend: ๋ถํธ ํ์ฅ ์ ์ด
- ๊ฐ ์ํ๋ณ control signal ์ค์
switch (state) {
case S0_IFETCH:
c->MemRead = 1;
c->IRWrite = 1;
c->PCWrite = 1;
c->IorD = 0;
c->ALUSrcA = 0;
c->ALUSrcB = 1;
c->ALUOp = ALU_ADDU;
c->PCSource = 0;
break;
case S1_IDECODE:
c->ALUSrcA = 0;
c->ALUSrcB = 3;
c->ALUOp = ALU_ADDU;
break;
- IFETCH ์ํ:
- ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ, IR ์ฐ๊ธฐ, PC ๊ฐฑ์ ํ์ฑํ
- ALU๋ก ๋ค์ PC ๊ณ์ฐ
- IDECODE ์ํ:
- ALU ์ ๋ ฅ ์ค์ (branch ์ฃผ์ ๊ณ์ฐ์ฉ)
- R-type instruction ์คํ ์ ์ด
case S2_RTYPE_EXEC:
c->ALUSrcA = 1;
c->ALUSrcB = 0;
switch (inst.funct) {
case FUNCT_ADDU: c->ALUOp = ALU_ADDU; break;
case FUNCT_SUBU: c->ALUOp = ALU_SUBU; break;
case FUNCT_AND: c->ALUOp = ALU_AND; break;
case FUNCT_OR: c->ALUOp = ALU_OR; break;
case FUNCT_XOR: c->ALUOp = ALU_XOR; break;
case FUNCT_NOR: c->ALUOp = ALU_NOR; break;
case FUNCT_SLT: c->ALUOp = ALU_SLT; break;
case FUNCT_SLTU: c->ALUOp = ALU_SLTU; break;
case FUNCT_SLL: c->ALUOp = ALU_SLL; break;
case FUNCT_SRA: c->ALUOp = ALU_SRA; break;
case FUNCT_SRL: c->ALUOp = ALU_SRL; break;
default:
status = UNSUPPORTED_ALU;
break;
}
break;
- ALU ์ ๋ ฅ์ ๋ ์ง์คํฐ ๊ฐ์ผ๋ก ์ค์
- funct ํ๋์ ๋ฐ๋ผ ALU ์ฐ์ฐ ์ค์
- ๋๋จธ์ง ์ํ๋ค ์ ์ด
case S3_RTYPE_WB:
c->RegDst = 1;
c->RegWrite = 1;
c->MemtoReg = 0;
break;
case S2_ITYPE_EXEC:
c->ALUSrcA = 1;
c->ALUSrcB = 2; // imm
c->SignExtend = (inst.opcode != OP_ANDI && inst.opcode != OP_ORI && inst.opcode != OP_XORI);
switch (inst.opcode) {
case OP_ADDIU: c->ALUOp = ALU_ADDU; break;
case OP_ANDI: c->ALUOp = ALU_AND; break;
case OP_ORI: c->ALUOp = ALU_OR; break;
case OP_XORI: c->ALUOp = ALU_XOR; break;
case OP_SLTI: c->ALUOp = ALU_SLT; break;
case OP_SLTIU: c->ALUOp = ALU_SLTU; break;
case OP_LUI: c->ALUOp = ALU_LUI; break;
}
break;
case S3_ITYPE_WB:
c->RegDst = 0;
c->RegWrite = 1;
c->MemtoReg = 0;
break;
case S2_LW_ADDR:
case S2_SW_ADDR:
c->ALUSrcA = 1;
c->ALUSrcB = 2;
c->ALUOp = ALU_ADDU;
break;
case S3_LW_MEM:
c->MemRead = 1;
c->IorD = 1;
break;
case S4_LW_WB:
c->RegDst = 0;
c->RegWrite = 1;
c->MemtoReg = 1;
break;
case S3_SW_MEM:
c->MemWrite = 1;
c->IorD = 1;
break;
case S2_BRANCH_COMP:
c->ALUSrcA = 1;
c->ALUSrcB = 0;
c->ALUOp = (inst.opcode == OP_BEQ) ? ALU_EQ : ALU_NEQ;
break;
case S3_BRANCH_DECIDE:
c->PCWriteCond = 1;
c->PCSource = 1;
break;
case S2_JUMP:
case S3_JAL_JUMP:
c->PCWrite = 1;
c->PCSource = 2;
break;
case S2_JAL_SAVE:
c->RegWrite = 1;
c->SavePC = 1;
break;
case S2_JR:
c->PCWrite = 1;
c->PCSource = 3;
c->JR = 1;
break;
- R-type ์ฐ๊ธฐ: rd ๋ ์ง์คํฐ์ ALU ๊ฒฐ๊ณผ ์ ์ฅ
- I-type ์คํ: immediate ๊ฐ๊ณผ ๋ ์ง์คํฐ ์ฐ์ฐ
- Load/Store: ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๊ณ์ฐ๊ณผ ์ ๊ทผ
- ๋ถ๊ธฐ: ์กฐ๊ฑด ๋น๊ต์ PC ๊ฐฑ์
- ์ ํ: PC ๊ฐฑ์ ๊ณผ ๋ฆฌํด ์ฃผ์ ์ ์ฅ
- FSM ๊ตฌํ
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= S0_IFETCH;
PC_reg <= 32'h0;
IR <= 32'h0;
A <= 32'h0;
B <= 32'h0;
ALUOut <= 32'h0;
MDR <= 32'h0;
end else begin
case (state)
S0_IFETCH: begin
IR <= mem_data;
PC_reg <= PC_reg + 4;
state <= S1_IDECODE;
end
S1_IDECODE: begin
A <= reg_file[rs];
B <= reg_file[rt];
case (opcode)
OP_RTYPE: state <= S2_RTYPE_EXEC;
OP_LW, OP_SW: state <= S2_MEM_ADDR;
OP_BEQ, OP_BNE: state <= S2_BRANCH;
OP_J, OP_JAL: state <= S2_JUMP;
endcase
end
S2_RTYPE_EXEC: begin
case (funct)
FUNC_ADD: ALUOut <= A + B;
FUNC_SUB: ALUOut <= A - B;
FUNC_AND: ALUOut <= A & B;
FUNC_OR: ALUOut <= A | B;
FUNC_SLT: ALUOut <= ($signed(A) < $signed(B)) ? 32'h1 : 32'h0;
endcase
state <= S3_RTYPE_WB;
end
S2_MEM_ADDR: begin
ALUOut <= A + {{16{immediate[15]}}, immediate};
state <= (opcode == OP_LW) ? S3_LW_MEM : S3_SW_MEM;
end
S3_LW_MEM: begin
MDR <= mem_data;
state <= S4_LW_WB;
end
S3_SW_MEM: begin
mem_write_data <= B;
mem_write_en <= 1'b1;
state <= S0_IFETCH;
end
- S0_IFETCH: ๋ฉ๋ชจ๋ฆฌ์์ ๋ช ๋ น์ด ๊ฐ์ ธ์ค๊ธฐ
- S1_IDECODE: ๋ช ๋ น์ด ํด์ ๋ฐ ๋ ์ง์คํฐ ์ฝ๊ธฐ
- S2_RTYPE_EXEC: R-type ๋ช ๋ น์ด ์คํ
- S2_MEM_ADDR: ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๊ณ์ฐ
- S3_LW_MEM/S3_SW_MEM: ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ/์ฐ๊ธฐ
- S4_LW_WB: ๋ ์ง์คํฐ์ ๋ฐ์ดํฐ ์ฐ๊ธฐ
2 branch ๋ฐ jump
S2_BRANCH: begin
case (opcode)
OP_BEQ: begin
if (A == B)
PC_reg <= PC_reg + {{16{immediate[15]}}, immediate} << 2;
end
OP_BNE: begin
if (A != B)
PC_reg <= PC_reg + {{16{immediate[15]}}, immediate} << 2;
end
endcase
state <= S0_IFETCH;
end
S2_JUMP: begin
PC_reg <= {PC_reg[31:28], jump_target, 2'b00};
if (opcode == OP_JAL)
reg_file[31] <= PC_reg + 4;
state <= S0_IFETCH;
end
- control signal ์์ฑ
always @(*) begin
case (state)
S0_IFETCH: begin
MemRead = 1'b1;
ALUSrcA = 2'b00; // PC ์ ํ
ALUSrcB = 2'b01; // 4 ์ ํ
ALUOp = 3'b000; // ๋ง์
PCWrite = 1'b1;
PCSource = 2'b00; // ALU ๊ฒฐ๊ณผ
end
S1_IDECODE: begin
ALUSrcA = 2'b00; // PC ์ ํ
ALUSrcB = 2'b11; // ๋ถ๊ธฐ ์คํ์
ALUOp = 3'b000; // ๋ง์
end
S2_RTYPE_EXEC: begin
ALUSrcA = 2'b01; // A ๋ ์ง์คํฐ
ALUSrcB = 2'b00; // B ๋ ์ง์คํฐ
case (funct)
FUNC_ADD: ALUOp = 3'b000;
FUNC_SUB: ALUOp = 3'b001;
FUNC_AND: ALUOp = 3'b010;
FUNC_OR: ALUOp = 3'b011;
FUNC_SLT: ALUOp = 3'b100;
endcase
end
- memory access ์ ์ด
S2_MEM_ADDR: begin
ALUSrcA = 2'b01; // A ๋ ์ง์คํฐ
ALUSrcB = 2'b10; // ํ์ฅ๋ immediate
ALUOp = 3'b000; // ๋ง์
end
S3_LW_MEM: begin
MemRead = 1'b1;
IorD = 1'b1; // ALUOut์ผ๋ก๋ถํฐ ์ฃผ์
end
S3_SW_MEM: begin
MemWrite = 1'b1;
IorD = 1'b1; // ALUOut์ผ๋ก๋ถํฐ ์ฃผ์
end
S3_RTYPE_WB: begin
RegWrite = 1'b1;
RegDst = 1'b1; // rd ํ๋ ์ ํ
MemtoReg = 1'b0; // ALUOut ์ ํ
end
S4_LW_WB: begin
RegWrite = 1'b1;
RegDst = 1'b0; // rt ํ๋ ์ ํ
MemtoReg = 1'b1; // MDR ์ ํ
end
- ALUSrcA/B: ALU ์ ๋ ฅ ์ ํ
- ALUOp: ALU ์ฐ์ฐ ์ข ๋ฅ
- RegDst: ๋ชฉ์ ์ง ๋ ์ง์คํฐ ์ ํ
- MemtoReg: ๋ ์ง์คํฐ ์ฐ๊ธฐ ๋ฐ์ดํฐ ์ ํ
- RegWrite: ๋ ์ง์คํฐ ์ฐ๊ธฐ ํ์ฑํ
- MemRead/Write: ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ ์ด
- PCWrite: PC ๊ฐฑ์ ์ ์ด
kontrack@DESKTOP-BJ4BPMI:~/HW4$ make clean
rm -f main.o CPU.o ALU.o RF.o MEM.o CTRL.o cpu *.mem
kontrack@DESKTOP-BJ4BPMI:~/HW4$ make
g++ -Wall -Wextra -O2 -c main.cpp -o main.o
g++ -Wall -Wextra -O2 -c CPU.cpp -o CPU.o
g++ -Wall -Wextra -O2 -c ALU.cpp -o ALU.o
g++ -Wall -Wextra -O2 -c RF.cpp -o RF.o
g++ -Wall -Wextra -O2 -c MEM.cpp -o MEM.o
g++ -Wall -Wextra -O2 -c CTRL.cpp -o CTRL.o
g++ -Wall -Wextra -O2 -o cpu main.o CPU.o ALU.o RF.o MEM.o CTRL.o
kontrack@DESKTOP-BJ4BPMI:~/HW4$ ./cpu testcase7.hex
Loading instruction memory...
Starting CPU simulation...
c
Simulation done successfully.
RF states after the program execution
$zero 00000000
$at e2810000
$v0 00000000
$v1 00000000
$a0 00000000
$a1 00000000
$a2 00000000
$a3 00000000
$t0 ffffffff
$t1 00000000
$t2 ffffffff
$t3 ffffffff
$t4 00000000
$t5 00000000
$t6 00000000
$t7 00000000
$s0 00000000
$s1 00000000
$s2 00000000
$s3 00000000
$s4 00000000
$s5 00000000
$s6 00000000
$s7 00000000
$t8 00000000
$t9 00000000
$k0 00000000
$k1 00000000
$gp 00001800
$sp 00003ffc
$fp 00000000
$ra 00000000
make์ ํตํด ์ปดํ์ผ ํ์ฌ ์์ฑ๋ cpu์ testcase1.hex๋ฅผ ๋ช
๋ น์ธ์๋ก ๋ฃ๊ณ ์คํ ํ ๊ฒฐ๊ณผ ์ ์์ ์ผ๋ก Starting CPU simulation...์ message๊ฐ ์ถ๋ ฅ๋์๋ค.
์ฌ๊ธฐ์ s๋ฅผ ํตํด 1cycle์ ์์ง์ด๊ณ r๋ก register์ ๊ฒฐ๊ณผ๋ฅผ dumpํ๋ฉด์ MARS์ 1 step์ฉ ๋น๊ตํ๋ฉฐ ์ ์์ ์ผ๋ก ๊ตฌ๋๋๋์ง๋ฅผ ํ์ธํ์๋ค.
1 step ์คํ ๊ฒฐ๊ณผ
run all ๊ฒฐ๊ณผ
๋ชจ๋ ๊ฒฐ๊ณผ๊ฐ ์ผ์นํ๋ ๊ฒ์ ํ์ธํ์๋ค.
program์ด ์ข
๋ฃ๋ ํ verilog testbench๋ฅผ ์ํ .memํ์ผ์ด ์ ์์ ์ผ๋ก ์์ฑ๋์๋ค.
์ดํ ๋ชจ๋ testcase์ ๋ํด์๋ ์๋ฎฌ๋ ์ด์ ์ด ์ฑ๊ณต์ ๋ฐํํ๋ ๊ฒ์ ํ์ธํ์๋ค.
โฏ
launch_simulation: Time (s): cpu = 00:00:16 ; elapsed = 00:00:18 . Memory (MB): peak = 3132.801 ; gain = 0.000
run all
Program Terminate
Simulation success!!!
$finish called at time : 8515 ns : File "C:/Users/LG/HW4/HW4.srcs/sources_1/imports/verilog/CPU_tb.v" Line 57
์์ testcase1.hex์ ๋ํด cpp์ด ์์ฑํ๋ .mem file๋ค ๋ฐํ์ผ๋ก vivado์์ verilog ์ฝ๋๋ฅผ ์ํํด๋ณธ ๊ฒฐ๊ณผ ์ฑ๊ณต์ ์ผ๋ก simulation์ ์๋ฃํ์๋ค.
์ดํ ๋ชจ๋ testcase์ ๋ํด์๋ ์๋ฎฌ๋ ์ด์
์ด ์ฑ๊ณต์ ๋ฐํํ๋ ๊ฒ์ ํ์ธํ์๋ค.
run all ๊ฒฐ๊ณผ
๋ฌธ์
Branch ๋ช
๋ น์ด(BEQ, BNE) ์คํ ์ ์๋ชป๋ ๋ถ๊ธฐ๊ฐ ๋ฐ์ํ์ฌ ํ๋ก๊ทธ๋จ์ด ์์์น ๋ชปํ ๊ฒฝ๋ก๋ก ์คํ๋๋ ํ์์ด ๋ฐ์ํ๋ค. ํนํ ํ
์คํธ์ผ์ด์ค 2์์ branch ์กฐ๊ฑด ํ์ธ๊ณผ target ์ฃผ์ ๊ณ์ฐ์ด ๋ถ์ ํํ๊ฒ ์ฒ๋ฆฌ๋์๋ค.
์์ธ
- Branch ์กฐ๊ฑด ํ์ธ ์ ALU ๊ฒฐ๊ณผ๊ฐ์ ์ตํ์ ๋นํธ(alu_result[0])๋ง์ ํ์ธํ์ฌ, ์ ์ฒด ๋น๊ต ๊ฒฐ๊ณผ๋ฅผ ์ ํํ๊ฒ ๋ฐ์ํ์ง ๋ชปํ๋ค.
- Branch target ์ฃผ์ ๊ณ์ฐ์ด PC_next ๋ก์ง์ ์์กด์ ์ด์์ผ๋ฉฐ, S3_BRANCH_DECIDE ์ํ์์ ์ง์ ์ ์ผ๋ก ๊ณ์ฐ๋์ง ์์๋ค.
ํด๊ฒฐ
- Branch ์กฐ๊ฑด ํ์ธ์ ALUOut == 32'b1๋ก ๋ณ๊ฒฝํ์ฌ ALU์ ์ ์ฒด ๋น๊ต ๊ฒฐ๊ณผ๋ฅผ ์ ํํ๊ฒ ๋ฐ์
- S3_BRANCH_DECIDE ์ํ์์ branch target ์ฃผ์๋ฅผ PC + (sign_extended_immediate << 2)๋ก ์ง์ ๊ณ์ฐํ๋๋ก ์์
- PC ์ ๋ฐ์ดํธ ๋ก์ง์ ์์ ํ์ฌ branch ์ํ์ผ ๋ ๋ณ๋์ ์ฃผ์ ๊ณ์ฐ์ ์ํํ๋๋ก ๋ณ๊ฒฝ
๊ฒฐ๊ณผ
- Branch ๋ช ๋ น์ด์ ์กฐ๊ฑด ํ๋จ์ด ์ ํํ๊ฒ ์ด๋ฃจ์ด์ ธ ์ฌ๋ฐ๋ฅธ ๋ถ๊ธฐ ๊ฒฐ์ ์ด ๊ฐ๋ฅํด์ง
- Branch target ์ฃผ์๊ฐ ์ ํํ๊ฒ ๊ณ์ฐ๋์ด ์๋ํ ์ฃผ์๋ก ์ ํํ ๋ถ๊ธฐ๊ฐ ์ด๋ฃจ์ด์ง
- ํ ์คํธ์ผ์ด์ค 2์ ๋ชจ๋ branch ๋ช ๋ น์ด๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๊ฒ ๋จ