반응형

gemini가 그린 블록 다이어그램입니다.
Single Cycle

아시다시피 single cycle은 위 5단계의 명령어 처리 구조를 한 clock cycle에 완료한다는 의미입니다.
각 Stage 별 내용을 한번 봅시다.
Datapath 분석
IF Stage
목표: "다음에 실행할 명령어를 메모리에서 가져오자."
- pc_reg에서 현재 실행할 명령어의 주소(pc_o)를 출력합니다.
- instr_mem에서는 pc_o를 받아, 그곳에 저장된 32bit instruction(instr_o)를 출력합니다.
- 이와 동시에 PC + 4를 pc_plus4에서 진행합니다. 이는 다음 명령어를 의미합니다. 메모리 주소는 4byte씩 이동합니다.
- PCSrc Mux는 다음 cycle의 PC 값을 결정합니다. 기본적으로는 pc+4이지만, Branch, Jump 발생 시 EX Stage에서 계산된 타깃 주소를 선택합니다.
ID Stage
목표: "가져온 명령어를 해석하고 필요한 Data를 준비하자."
- instr_o를 여러 조각으로 나눕니다.
- 소스 레지스터 주소 (rs1, rs2): reg_file로 들어가 읽을 data의 위치를 알려줍니다.
- 목적지 레지스터 주소 (rd): 결과를 저장할 위치를 지정합니다.
- Imm: 상수입니다. 짧은 상수값을 imm_gen을 통해 32bit 크기로 확장합니다.
- Opcode / Funct: controller로 들어가서 명령어에 대한 제어 신호를 출력합니다.
EX Stage
목표: "실질적인 계산을 수행하자"
- ALUSrc B MUX: ALU의 두번째 입력으로 무엇을 쓸지 결정합니다.
- register data (예: ADD 등)
- imm data (예: ADDI, LW 등)
- ALU: 실제 연산을 수행합니다. 결과값의 상태를 알려주는 Flag 신호를 출력합니다.
- 저희는 우선 Z Flag(결과값이 0일 때)만 만들었습니다.
- 이 외에도 N, C, V가 있습니다. 앞으로 확장하겠습니다.
- Branch Adder: branch가 발생할때 현재 PC 값에 offset을 더해 점프할 목적지 주소를 계산합니다.
- 이 값은 IF 영역의 PCSrc Mux로 연결됩니다.
MEM
목표: "필요하다면 data memory에 data를 쓰거나 읽어오자."
- LW, SW 등의 명령어만 현재 Stage를 사용합니다.
WB
목표: "최종 결과를 register에 저장하여 작업을 마무리하자."
- ResultSrc Mux: register에 최종적으로 저장할 값을 선택합니다.
- ALU의 연산 결과
- memory에서 읽은 값
- 피드백 루프: 선택된 최종 값은 ID Stage의 wr_data_i 포트로 돌아갑니다.
- 이 값이 ID Stage에서 지정된 rd에 저장되면서 Instruction 실행이 완료됩니다.
시뮬레이션
TB 코드
`timescale 1ns / 1ps
module tb_single_cycle_processor();
// ---------------------------------------------------------
// Signal Declaration
// ---------------------------------------------------------
reg clk_r ;
reg rst_nr ;
// ---------------------------------------------------------
// Clock Generation (100MHz)
// ---------------------------------------------------------
always #5 clk_r = ~clk_r ;
// ---------------------------------------------------------
// DUT Instantiation
// ---------------------------------------------------------
// 사용자가 만든 최상위 모듈 이름에 맞춰 SingleCycle_Top 또는 single_cycle_processor 사용
SingleCycle_Top u_dut (
.clk_i (clk_r ),
.rst_ni (rst_nr )
);
// ---------------------------------------------------------
// Test Procedure
// ---------------------------------------------------------
initial begin
// Initialize signals
clk_r = 0 ;
rst_nr = 0 ; // Assert reset
// Release reset after 20ns
#22;
rst_nr = 1 ;
$display("==================================================");
$display(" Starting Single Cycle Processor Simulation ");
$display("==================================================");
// 시뮬레이션 시간 동안 실행 (예: 200ns)
#200;
$display("==================================================");
$display(" Simulation Finished ");
$display("==================================================");
$finish;
end
// ---------------------------------------------------------
// Monitor Register values (Debugging)
// ---------------------------------------------------------
// 시뮬레이션 중에 특정 레지스터 값이 변할 때마다 출력하여 확인
initial begin
$monitor("Time: %0t | PC: %h | Instr: %h | x1: %h | x2: %h | x3: %h | x4: %h",
$time, u_dut.pc_w, u_dut.instr_w,
u_dut.u_register_file.regs_r[1],
u_dut.u_register_file.regs_r[2],
u_dut.u_register_file.regs_r[3],
u_dut.u_register_file.regs_r[4]);
end
endmodule
Program.hex
00a00093
01400113
002081b3
00302023
00002203
프로젝트 폴더에 넣도록 하겠습니다.
현재 코드의 내용은 아래와 같습니다.
1. addi x1, x0, 10 (x1 = 10)
2. addi x2, x0, 20 (x2 = 20)
3. add x3, x1, x2 (x3 = 10 + 20 = 30)
4. sw x3, 0(x0) (mem[0] = 30)
5. lw x4, 0(x0) (x4 = mem[0] = 30)
5번째 cycle이 끝나는 순간 x4의 값이 30이 되겠죠? 확인해보겠습니다.
결과

완전 잘됐네용~
schematic 올리고 이번 포스팅 끝내겠습니다.
다음에는 자세한 성능분석을 해보겠습니다.
오늘도 읽어주셔서 감사합니다!
Schematic

반응형
'Project > RISC-V CPU Architecture Design' 카테고리의 다른 글
| [9] PC Unit, Memory 및 Single Cycle Processor 설계 (0) | 2026.01.06 |
|---|---|
| [8] RISC-V Control Unit 설계 (2) - ALU Decoder (0) | 2026.01.06 |
| [7] RISC-V Control Unit 설계 (1) - Main Decoder (0) | 2026.01.05 |
| [6] Immediate Generator 설계 (0) | 2026.01.03 |
| [5] ALU 설계 (0) | 2026.01.02 |