![[VerilogHDL] CPU 기본 구조, 메모리, Counter 설계(Control Unit, Data Path)](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrzOB9%2FbtsHL7P7B17%2Fke3o3AkbWZQgGu69mSzfPK%2Fimg.png)
[VerilogHDL] CPU 기본 구조, 메모리, Counter 설계(Control Unit, Data Path)VerilogHDL/Study2024. 6. 3. 09:31
Table of Contents
#1. CPU
- CPU 아키텍처에는 크게 CISC와 RISC가 있다.
#1-1. CISC(Complex Instruction Set Computer)
- 복잡한 명령어
- CISC 프로세서에는 매우 복잡하고 단일 명령어로 여러 개의 Low-Level 작업(예: 산술과 결합된 메모리 액세스)을 수행할 수 있는 대규모 명령어 세트가 있다.
- 가변 명령어 길이
- CISC 아키텍처의 명령어는 길이가 다양할 수 있으므로 더 복잡한 작업이 더 적은 명령어로 인코딩되므로 프로그램 크기가 더 작아질 수 있다.
- 레지스터 적음
- 각 명령어의 복잡성과 기능으로 인해 CISC는 더 적은 수의 레지스터를 가지며 메모리 작업에 더 많이 의존한다.
- Microcode
- 복잡한 명령어를 프로세서에서 내부적으로 처리하는 간단한 단계로 분해한다.
[장점]
- High-Level 작업 : (고급)명령어가 많아 고수준 작업이 가능하다.
- 프로그램 크기의 효율성 : 명령어 많음 → 복잡한 명령어를 사용하면 프로그램을 작성하는 데 더 적은 명령어가 필요함 → 프로그램 크기가 더 가벼워짐 → 컴파일러 단순화 가능
[단점]
- 전력 소비 : 복잡한 명령에는 더 많은 계산 능력이 필요하므로 더 많은 전력을 소비한다.
- 복잡한 구조
- 느린 클럭 속도 : CPU구조가 복잡해지기에 상대적으로 클럭 속도가 느릴 수 있다.
#1-2. RISC(Reduced Instruction Set Computer)
- 간단한 명령어
- RISC 프로세서는 한 클록 사이클 내에서 실행될 수 있는 작은 간단한 명령어 세트를 사용한다. 이러한 단순성은 프로그램을 보다 효율적이고 효율적으로 실행할 수 있게 해준다.
- → CISC에서 많이 사용하는 명령어들로만 구성
- 명령어가 적기 때문에 RISC에 존재하지 않는 명령을 구현하기 위해 소프트웨어적으로 더 무거워짐
- Load/Store 아키텍처
- 일반적으로 레지스터 간에 작업이 수행되며 특정 로드 및 저장 명령어를 통해 메모리에 액세스합니다. 산술/논리 연산에서 메모리 액세스를 분리하면 명령어 설계가 단순화된다.
- 고정 명령어 길이
- RISC 명령어는 일반적으로 길이가 고정되어 명령어 디코딩 프로세스를 단순화한다.
- 레지스터 많음:
- 메모리 액세스를 최소화하기 위해 더 많은 수의 레지스터를 갖는다.
[장점]
- 속도 : 명령 길이가 일정하고 명령 세트가 간단하여 대부분의 명령이 하나의 클록 주기에서 실행되므로 처리 속도가 더 빠르다.
- 단순한 구조
- 전력 소비 효율
- 최적화 : 단순한 명령에 대해서 컴파일러를 단순화 할 수 있다.
[단점]
- 적은 명령어 : 각 명령어의 작업이 적으므로 CISC 프로세서가 더 적은 수의 복잡한 명령어로 수행할 수 있는 작업을 수행하려면 더 많은 명령어가 필요할 수 있다. → 이로 인해 코드 크기가 커짐
- 호환성 : 단순함은 속도와 전력 측면에서 이점이 있지만 RISC 아키텍처가 기본적으로 지원하지 않는 복잡한 명령어가 필요한 경우 호환성이 떨어지게 된다.
- 컴파일러에 대한 의존성 : 고급 명령어를 RISC의 적은 명령어로 구현하기에 컴파일러에 크게 의존한다. → SW가 무거워 질 수 있음
#1-3. 폰 노이만 구조와 하버드 구조
- 폰노이만 구조 : 메모리 1개
- 일반적인 PC
- 프로그램 구동 명령어를 외부 메모리(SSD, HDD)에 저장한다.
- 외부 메모리에 저장된것을 RAM으로 가져오는 Loading 작업이 필요하다.
- 하버드 구조 : 메모리 2개(명령어 메모리 & 데이터 메모리)
- 임베디드
- Program memory : ROM, Flash
- Data memory : RAM
#1-4. RAM vs SSD vs Register
SSD
- 위와 같이 NAND Flash는 데이터를 저장하는 Floating Gate(부유 게이트)가 존재한다.
- 프로세스는 블록을 다시 쓰기 전에 지워야 하기 때문에 RAM보다 느리다.
RAM
- DRAM은 트랜지스터 1개와 캐패시터 1개로 구성(1T1C)되어 구조가 매우 간단하다.
- DRAM 셀에 액세스하려면 트랜지스터(Word Line)를 활성화하고, 커패시터(Bit Line)의 전하를 읽거나 쓴 후, 다음 작업을 위해 비트 라인을 사전 충전해야 한다.
- 이 프로세스는 플립플롭에 액세스하는 것보다 느리다.
- → SSD보다 속도 빠름
- CPU가 액세스하고 처리해야 하는 데이터 및 프로그램 명령 등 범용 저장 장소이다.
Register
- Flip-Flip 및 Latch로 구성
- CPU 내부에 위치하여 버스 전송 없이 즉시 엑세스 가능하다.
- → 속도 제일 빠름(한 클럭내에 엑세스 가능)
- 저장 용량이 제일 작다.
- ALU 연산에 필요한 데이터 및 임시 데이터 저장 장소이다.
#2. CPU 설계
위와 같은 형태로 RISC-V CPU 설계 + Peripheral
#2-1. counter 설계
Data Path 설계
- 데이터 처리 작업(연산)을 수행
- 데이터의 이동 경로는 Control Unit이 제어하고 Data Path는 Control Unit의 신호에 따라 연산과 데이터 이동 수행
- 구성요소 : ALU, 레지스터, 메모리, MUX, 버스 등
더보기
`timescale 1ns / 1ps
module DataPath(
input clk,
input reset,
input ASrcMuxSel,
input ALoad,
input OutBufSel,
output ALt10,
output [7:0] out
);
wire [7:0] w_AdderResult, w_MuxOut, w_ARegOut;
mux_2x1 U_MUX(
.sel(ASrcMuxSel),
.a(8'b0),
.b(w_AdderResult),
.y(w_MuxOut)
);
register U_A_Reg(
.clk(clk),
.reset(reset),
.load(ALoad),
.d(w_MuxOut),
.q(w_ARegOut)
);
comparator U_Comp(
.a(w_ARegOut),
.b(8'd10),
.lt(ALt10)
);
adder U_Adder(
.a(w_ARegOut),
.b(8'b1),
.y(w_AdderResult)
);
outBuff U_OutBuf(
.en(OutBufSel),
.a(w_ARegOut),
.y(out)
);
endmodule
module mux_2x1 (
input [7:0] a,
input [7:0] b,
input sel,
output reg [7:0] y
);
always @(*) begin
case(sel)
1'b0 : y = a;
1'b1 : y = b;
endcase
end
endmodule
module register (
input clk,
input reset,
input load,
input [7:0] d,
output [7:0] q
);
reg [7:0] d_reg, d_next;
assign q = d_reg;
always @(posedge clk , posedge reset) begin
if (reset) d_reg <= 0;
else d_reg <= d_next;
end
always @(*) begin
if (load) d_next = d;
else d_next = d_reg;
end
endmodule
module comparator (
input [7:0] a,
input [7:0] b,
output lt
);
assign lt = a < b;
endmodule
module adder (
input [7:0] a,
input [7:0] b,
output [7:0] y
);
assign y = a + b;
endmodule
module outBuff(
input en,
input [7:0] a,
output [7:0] y
);
assign y = en ? a : 8'bz; // en이 1 -> a, en이 0 -> high impedence
endmodule
Control Unit 설계
- 시스템 내 다른 장치의 작동을 지시하여 명령 실행을 관리하고 조정
- Instruction Fetch : 메모리에서 명령 검색
- Instruction Decode : 명령 해석
- Control Signal Generation : ALU, 레지스터, 메모리 및 I/O 장치와 같은 다른 구성 요소(Data Path)의 작동을 제어하는 제어 신호 생성
- Sequencing : 작업 순서 결정
- Synchronize : 클럭 동기화(클럭에 따라 동작)
⇒ Control Unit은 클럭에 따라 state를 결정하고 각 state마다 명령을 Data Path에 전송
더보기
`timescale 1ns / 1ps
module ControlUnit (
input clk,
input reset,
input ALt10,
output reg ASrcMuxSel,
output reg ALoad,
output reg OutBufSel
);
localparam S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;
reg [2:0] state, state_next;
always @(posedge clk, posedge reset) begin
if (reset) state <= S0;
else state <= state_next;
end
always @(*) begin
state_next = state;
case (state)
S0: state_next = S1;
S1: begin
if (ALt10) state_next = S2;
else state_next = S4;
end
S2: state_next = S3;
S3: state_next = S1;
S4: state_next = S4;
default: state_next = S1;
endcase
end
always @(*) begin
ASrcMuxSel = 1'b0;
ALoad = 1'b0;
OutBufSel = 1'b0;
case (state)
S0: begin
ASrcMuxSel = 1'b0;
ALoad = 1'b1;
OutBufSel = 1'b0;
end
S1: begin
ASrcMuxSel = 1'b1;
ALoad = 1'b0;
OutBufSel = 1'b0;
end
S2: begin
ASrcMuxSel = 1'b1;
ALoad = 1'b0;
OutBufSel = 1'b1;
end
S3: begin
ASrcMuxSel = 1'b1;
ALoad = 1'b1;
OutBufSel = 1'b0;
end
S4: begin
ASrcMuxSel = 1'b1;
ALoad = 1'b0;
OutBufSel = 1'b0;
end
default: begin
ASrcMuxSel = 1'b0;
ALoad = 1'b0;
OutBufSel = 1'b0;
end
endcase
end
endmodule
Dedicated Processor 설계(CU + DP)
더보기
`timescale 1ns / 1ps
module DedicatedProcessor (
input clk,
input reset,
output [7:0] out
);
wire w_ASrcMuxSel, w_ALoad, w_OutBufSel, w_ALt10;
ControlUnit U_CU (
.clk (clk),
.reset(reset),
.ALt10(w_ALt10),
.ASrcMuxSel(w_ASrcMuxSel),
.ALoad(w_ALoad),
.OutBufSel(w_OutBufSel)
);
DataPath U_DP (
.clk(clk),
.reset(reset),
.ASrcMuxSel(w_ASrcMuxSel),
.ALoad(w_ALoad),
.OutBufSel(w_OutBufSel),
.ALt10(w_ALt10),
.out (out)
);
endmodule
Test Bench
더보기
`timescale 1ns / 1ps
module tb_DedicatedProcessor ();
reg clk;
reg reset;
wire [7:0] out;
DedicatedProcessor dut (
.clk (clk),
.reset(reset),
.out(out)
);
always #5 clk = ~clk;
initial begin
clk = 0;
reset = 1;
#30 reset = 0;
end
endmodule
위 시뮬레이션 결과와 같이
outBufSel==1
일 때(state==2일 때) 출력ASrcMuxSel == 1 & ALoad == 1
일 때 (state==3일 때)+1 연산
⇒ 1클럭마다 state가 변하기 때문에 한 클럭만 출력하고 두 클럭은 ZZ상태
CLK 주기 변경 & LED로 출력
always @(posedge clk, posedge reset) begin // prescaler
if (reset) begin
counter <= 0;
end else begin
if (counter == 50_000_000 - 1) begin
counter <= 0;
r_clk <= 1'b1;
end else begin
counter <= counter + 1;
r_clk <= 1'b0;
end
end
end
클럭을 조절하여 LED ON/OFF가 보일 수 있도록 조정
각 LED가 3비트 출력의 각 비트이다. (연산 결과가 3이면 → 011 → LED0, LED1 ON)
⇒ 1클럭만 출력하고 다음 연산 결과까지 출력 안함
LED 꺼지지 않고 계속 ON
- Buffer 대신 Register 사용 (State 저장 용도)
module DataPath (
input clk,
input reset,
input ASrcMuxSel,
input ALoad,
input OutBufSel,
output ALt10,
output [7:0] out
);
wire [7:0] w_AdderResult, w_MuxOut, w_ARegOut;
mux_2x1 U_MUX (
.sel(ASrcMuxSel),
.a (8'b0),
.b (w_AdderResult),
.y(w_MuxOut)
);
register U_A_Reg (
.clk(clk),
.reset(reset),
.load(ALoad),
.d(w_MuxOut),
.q(w_ARegOut)
);
comparator U_Comp (
.a(w_ARegOut),
.b(8'd10),
.lt(ALt10)
);
adder U_Adder (
.a(w_ARegOut),
.b(8'b1),
.y(w_AdderResult)
);
// outBuff U_OutBuf (
// .en(OutBufSel),
// .a (w_ARegOut),
// .y(out)
// );
register U_Out_Reg (
.clk(clk),
.reset(reset),
.load(OutBufSel),
.d(w_ARegOut),
.q(out)
);
endmodule
위 시뮬레이션 결과와 같이 Z 상태로 변하지 않고 이전 상태가 유지되어 출력된다.
FND 출력
더보기
`timescale 1ns / 1ps
module top (
input clk,
input reset,
output [7:0] fndFont,
output [3:0] fndCom
);
wire [7:0] w_outcount;
DedicatedProcessor U_DP (
.clk (clk),
.reset(reset),
.out(w_outcount)
);
fndContorller U_FNDController (
.reset(reset),
.clk (clk),
.digit({6'b0, w_outcount}),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
0 ~ 9까지 증가하고 다시 0부터 시작
위와 같이 무한루프를 돌려 HALT state에 진입하지 않으면 된다.
최종 코드
GitHub - k1minseok/Verilog_0to9Counter_0528: 0 to 9 Counter(Control Unit & Data Path)
0 to 9 Counter(Control Unit & Data Path). Contribute to k1minseok/Verilog_0to9Counter_0528 development by creating an account on GitHub.
github.com
Made By Minseok KIM
'VerilogHDL > Study' 카테고리의 다른 글
[VerilogHDL] AXI-Lite 구현 (0) | 2024.06.18 |
---|---|
[VerilogHDL] RISC-V 기본, RV32I R-Type, IL-Type (0) | 2024.06.18 |
[VerilogHDL] FIFO, UART&FIFO (0) | 2024.05.30 |
[VerilogHDL] Verification(32bit register, BRAM) (0) | 2024.05.23 |
[VerilogHDL] System Verilog 기초 (0) | 2024.05.22 |
@민바Minba :: Minba's blog
Let's Be Happy!
도움이 되었으면 좋겠어요 :)