HW4 - Kontrack/for_wiki GitHub Wiki

Outline

๋ชฉํ‘œ

  • 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
image

1. Design

1. additional control signals

image
  1. State Control
  • IRWrite: Instruction Register์— ๋ฉ”๋ชจ๋ฆฌ๋กœ๋ถ€ํ„ฐ ์ฝ์€ ๋ช…๋ น์–ด๋ฅผ ์ €์žฅํ• ์ง€ ๊ฒฐ์ •
    • PCWrite: Program Counter ์—…๋ฐ์ดํŠธ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •
    • PCWriteCond: Branch ๋ช…๋ น์–ด์—์„œ ์กฐ๊ฑด์ด ๋งŒ์กฑ๋  ๋•Œ PC ์—…๋ฐ์ดํŠธ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •
  1. Memory Access Control
    • IorD: Memory ์ฃผ์†Œ๋กœ PC๋ฅผ ์‚ฌ์šฉํ• ์ง€(0) ALUOut์„ ์‚ฌ์šฉํ• ์ง€(1) ๊ฒฐ์ •
  2. 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
  1. 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)
  1. Register Write Control
  • SavePC: JAL ๋ช…๋ น์–ด์—์„œ return address๋ฅผ $ra์— ์ €์žฅํ• ์ง€ ๊ฒฐ์ •
  • jal_save: JAL ๋ช…๋ น์–ด ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋‚ด๋ถ€ ์ƒํƒœ ์ €์žฅ

2. FSM

image
  1. S0_IFETCH:
  • ๋™์ž‘: IR โ† Memory[PC], PC โ† PC + 4
  • ์ „์ด: ๋ฌด์กฐ๊ฑด S1_IDECODE๋กœ
  1. 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
  1. ๊ฐ ์‹คํ–‰ ์ƒํƒœ:
  • 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
  1. ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์ƒํƒœ:
  • 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
  1. Write-Back ์ƒํƒœ:
  • S3_RTYPE_WB: Reg[rd] โ† ALUOut
  • S3_ITYPE_WB: Reg[rt] โ† ALUOut
  • S4_LW_WB: Reg[rt] โ† MDR

2. Implement

1. cpp์—์„œ ๊ตฌํ˜„

โ€ข CPU.cpp

  1. 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 ์‹คํ–‰ ์ƒํƒœ๋ฅผ ์ •์ƒ ์‹คํ–‰์œผ๋กœ ์„ค์ •
  1. 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๋งŒํผ ์ฆ๊ฐ€ (๋‹ค์Œ ๋ช…๋ น์–ด ์ฃผ์†Œ)
  • ๋‹ค์Œ ์ƒํƒœ ๊ฒฐ์ •
  1. 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 ๋ ˆ์ง€์Šคํ„ฐ์— ์ฝ์€ ๊ฐ’ ์ €์žฅ
  • ๋‹ค์Œ ์ƒํƒœ ๊ฒฐ์ •
  1. 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์— ๊ฒฐ๊ณผ ์ €์žฅ
  • ๋‹ค์Œ ์ƒํƒœ ๊ฒฐ์ •
  1. 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๋กœ ์„ค์ •
  1. 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์— ์ €์žฅ
  1. I-type Instruction ์“ฐ๊ธฐ
    case S3_ITYPE_WB: {
        rf.write(parsed_inst.rt, ALUOut, controls.RegWrite);
        state = S0_IFETCH;
        break;
    }
  • rt ๋ ˆ์ง€์Šคํ„ฐ์— ๊ฒฐ๊ณผ ์“ฐ๊ธฐ
  • IFETCH ์ƒํƒœ๋กœ ๋Œ์•„๊ฐ€๊ธฐ
  1. 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)์„ ๋”ํ•ด ์ตœ์ข… ์ฃผ์†Œ ๊ณ„์‚ฐ
  1. 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)์— ์ €์žฅ
  1. Load write
    case S4_LW_WB: {
        rf.write(parsed_inst.rt, MDR, controls.RegWrite);
        state = S0_IFETCH;
        break;
    }
  • MDR์˜ ๋ฐ์ดํ„ฐ๋ฅผ rt ๋ ˆ์ง€์Šคํ„ฐ์— ์“ฐ๊ธฐ
  1. 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) ์“ฐ๊ธฐ
  1. 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์— ์ €์žฅ
  1. 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์— ์˜คํ”„์…‹ ๋”ํ•˜๊ธฐ
  1. 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

โ€ข CTRL.cpp

  1. 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๋น„ํŠธ)
  1. ๋‹ค์Œ ์ƒํƒœ ๊ฒฐ์ •
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๋กœ ๋Œ์•„๊ฐ
  1. 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: ๋ถ€ํ˜ธ ํ™•์žฅ ์ œ์–ด
  1. ๊ฐ ์ƒํƒœ๋ณ„ 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 ์ฃผ์†Œ ๊ณ„์‚ฐ์šฉ)
  1. 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 ์—ฐ์‚ฐ ์„ค์ •
  1. ๋‚˜๋จธ์ง€ ์ƒํƒœ๋“ค ์ œ์–ด
	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 ๊ฐฑ์‹ ๊ณผ ๋ฆฌํ„ด ์ฃผ์†Œ ์ €์žฅ

2. verilog์—์„œ ๊ตฌํ˜„

โ€ข CPU.v

  1. 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

โ€ข CTRL.v

  1. 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
  1. 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

2.3 ๋ ˆ์ง€์Šคํ„ฐ ์“ฐ๊ธฐ ์ œ์–ด

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 ๊ฐฑ์‹  ์ œ์–ด

3. Result

1. cpp ์‹คํ–‰ ๊ฒฐ๊ณผ

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์”ฉ ๋น„๊ตํ•˜๋ฉฐ ์ •์ƒ์ ์œผ๋กœ ๊ตฌ๋™๋˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜์˜€๋‹ค. image1 step ์‹คํ–‰ ๊ฒฐ๊ณผ imagerun all ๊ฒฐ๊ณผ
๋ชจ๋“  ๊ฒฐ๊ณผ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค.
image
program์ด ์ข…๋ฃŒ๋œ ํ›„ verilog testbench๋ฅผ ์œ„ํ•œ .memํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ๋‹ค.

์ดํ›„ ๋ชจ๋“  testcase์— ๋Œ€ํ•ด์„œ๋„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์ด ์„ฑ๊ณต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค.

2. verilog ์‹คํ–‰ ๊ฒฐ๊ณผ

โ‹ฏ
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์— ๋Œ€ํ•ด์„œ๋„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์ด ์„ฑ๊ณต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค. imagerun all ๊ฒฐ๊ณผ


4. Troubleshooting

1. Branch ๋ช…๋ น์–ด ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜

๋ฌธ์ œ
Branch ๋ช…๋ น์–ด(BEQ, BNE) ์‹คํ–‰ ์‹œ ์ž˜๋ชป๋œ ๋ถ„๊ธฐ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์ด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฝ๋กœ๋กœ ์‹คํ–‰๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ๋‹ค. ํŠนํžˆ ํ…Œ์ŠคํŠธ์ผ€์ด์Šค 2์—์„œ branch ์กฐ๊ฑด ํ™•์ธ๊ณผ target ์ฃผ์†Œ ๊ณ„์‚ฐ์ด ๋ถ€์ •ํ™•ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋˜์—ˆ๋‹ค.

์›์ธ

  1. Branch ์กฐ๊ฑด ํ™•์ธ ์‹œ ALU ๊ฒฐ๊ณผ๊ฐ’์˜ ์ตœํ•˜์œ„ ๋น„ํŠธ(alu_result[0])๋งŒ์„ ํ™•์ธํ•˜์—ฌ, ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜์˜ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.
  2. Branch target ์ฃผ์†Œ ๊ณ„์‚ฐ์ด PC_next ๋กœ์ง์— ์˜์กด์ ์ด์—ˆ์œผ๋ฉฐ, S3_BRANCH_DECIDE ์ƒํƒœ์—์„œ ์ง์ ‘์ ์œผ๋กœ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์•˜๋‹ค.

ํ•ด๊ฒฐ

  1. Branch ์กฐ๊ฑด ํ™•์ธ์„ ALUOut == 32'b1๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ALU์˜ ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜์˜
  2. S3_BRANCH_DECIDE ์ƒํƒœ์—์„œ branch target ์ฃผ์†Œ๋ฅผ PC + (sign_extended_immediate << 2)๋กœ ์ง์ ‘ ๊ณ„์‚ฐํ•˜๋„๋ก ์ˆ˜์ •
  3. PC ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์—ฌ branch ์ƒํƒœ์ผ ๋•Œ ๋ณ„๋„์˜ ์ฃผ์†Œ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋ณ€๊ฒฝ

๊ฒฐ๊ณผ

  1. Branch ๋ช…๋ น์–ด์˜ ์กฐ๊ฑด ํŒ๋‹จ์ด ์ •ํ™•ํ•˜๊ฒŒ ์ด๋ฃจ์–ด์ ธ ์˜ฌ๋ฐ”๋ฅธ ๋ถ„๊ธฐ ๊ฒฐ์ •์ด ๊ฐ€๋Šฅํ•ด์ง
  2. Branch target ์ฃผ์†Œ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๊ณ„์‚ฐ๋˜์–ด ์˜๋„ํ•œ ์ฃผ์†Œ๋กœ ์ •ํ™•ํ•œ ๋ถ„๊ธฐ๊ฐ€ ์ด๋ฃจ์–ด์ง
  3. ํ…Œ์ŠคํŠธ์ผ€์ด์Šค 2์˜ ๋ชจ๋“  branch ๋ช…๋ น์–ด๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋จ
โš ๏ธ **GitHub.com Fallback** โš ๏ธ