CPU 구조

junyojeo·2025년 3월 26일
0

목차

1. CPU 구조

  • 레지스터
  • 연산 장치
  • 제어 장치
  • 캐시

2. CPU 작동 원리

  • CPU 연산 과정
  • 명령어 체계
  • 어셈블리어
  • CPU 시뮬레이터

3. 성능 최적화

  • 캐시 메모리
  • CPU 파이프라인
  • 분기 예측

1. CPU 구조

레지스터

  • PC (Program Counter): CPU가 다음에 실행할 명령어의 주소를 가리키는 Register.
  • MAR (Memory Address Register): 메모리에서 읽거나 쓸 주소를 담는 레지스터.
  • MBR (Memory Buffer Register): 메모리에서 읽거나 쓸 데이터를 임시 저장하는 레지스터.
  • IR (Instruction Register): 현재 처리 중인 명령어를 저장하는 레지스터.
  • 범용 레지스터: 연산에 필요한 데이터나 연산 결과 임시 저장
  • 특수 목적 레지스터:
    • AC (Accumulator): 연산 결과 임시 저장
    • CIR (Current Instruction Register): 현재 처리 중인 명령어 저장
    • SR (Status Register): 연산 결과 상태 저장

연산 장치

  • ALU (Arithmetic Logic Unit): 모든 계산과 논리 연산을 수행하는 장치
    • 산술: +, -, ×, ÷
    • 논리: AND, OR, NOT, XOR 수행

제어 장치

  • CU (Control Unit): CPU의 모든 작업을 지휘하는 지휘자 역할
    • 명령어를 순서대로 실행할 수 있도록 함
    • 명령어 해독
    • 필요한 제어 신호를 다른 장치로 전송

정리

1. 레지스터

명령어:

  • PC (Program Counter) → 다음 실행할 명령어 주소
  • IR (Instruction Register) → 현재 명령어

메모리:

  • MAR (Memory Address Register) → 메모리 주소
  • MBR (Memory Buffer/Data Register) → 메모리 버퍼

연산:

  • AC(Accumulator) → 연산 결과
  • SR/FR (Status/Flag Register) → 연산 결과 상태

다목적:

  • IX/IDX (Index Register) → 인덱스
  • VR (Vector Register) → 병렬 처리(SIMD)
  • 범용 레지스터 → 범용 레지스터 다목적

스택:

  • SP (Stack Pointer) → 스택 최상단
  • BP (Base Pointer) → 스택 기준점

2. 연산 장치

  • ALU (Arithmetic Logic Unit) → 연산(산술, 논리)

3. 제어 장치

  • CU (Control Unit) → 명령어 해석 및 제어 신호 생성

4. 캐시:

  • 캐시 메모리(Cache Memory) → 임시 저장소(고속)
  • MMU (Memory Management Unit) → 가상 주소를 물리 주소로 변환

2. CPU 작동 원리

1. 인출(Fetch)

  • PC → MAR → 메모리 → MBR → IR, PC 증가
  1. PC에서 주소를 가져옴
  2. MAR에 저장
  3. MAR의 주소를 사용해 명령어를 읽음
  4. 명령어를 MBR에 저장
  5. MBR에 저장된 명령어를 IR에 저장
  6. PC 값 증가. 다음 명령어 준비

2. 해독(Decode)

  • IR → 제어장치
  1. IR에 저장된 명령어를 제어장치로 전달
  2. 제어장치가 명령어 분석(해독)
  3. 필요한 제어 신호 생성

3. 실행(Execute)

  • 제어장치 → ALU → 임시 결과 저장
  1. 제어장치가 명령어에 따라 필요한 제어 신호 보냄
  2. 필요한 데이터를 레지스터에서 가져옴
  3. ALU에서 연산
  4. 연산 결과 저장

4. 메모리(Memory Access)

  • 필요시 수행
  • 읽기: MAR에 주소 지정 → 메모리에서 데이터 읽기 → MBR에 저장
  • 쓰기: MAR에 주소 지정 → MBR에 데이터 저장 → 메모리에 기록

5. 쓰기(Write Back)

  • 결과를 레지스터에 저장
  • MBR/ALU → 목적지 레지스터

3. 명령

구성

  • 연산 코드(Operation Code) + 피연산자(Operand)로 구성.
    ADD a, b
  • 연산 코드: 수행할 작업(ADD, SUB, MOV 등)
    ADD
  • 피연산자: 작업 대상 데이터 또는 주소(보통 레지스터 이름으로 eax, ebx 처럼 사용.)
    eax, ebx

기본 명령어 유형

  • 데이터 이동: MOV -> 저장, 복사 MOV eax, ebx (ebx 값을 eax에 복사)
  • 산술 연산: ADD(+), SUB(-), MUL(×), DIV(÷), INC(++), DEC(--)
  • 논리 연산: AND, OR, XOR, NOT, SHL, SHR
  • 분기문: JMP(레지스터로 점프), JZ(0이면 점프(return (0))), JNZ(0이 아니면 점프),
  • 메모리 접근: LOAD(메모리 -> 레지스터), STORE(레지스터 -> 메모리)

(명령어)

  • 데이터 이동:
    • MOV eax, ebx (ebx 값을 eax에 복사)
    • MOV eax, [mem] (메모리 값을 eax에 복사)
    • MOV [mem], eax (eax 값을 메모리에 저장)
  • 산술 연산:
    • ADD eax, ebx (eax = eax + ebx)
    • SUB eax, 5 (eax = eax - 5)
    • MUL ebx (eax = eax * ebx)
    • DIV ecx (eax = eax / ecx)
    • INC eax (eax 값 1 증가)
    • DEC eax (eax 값 1 감소)
  • 논리 연산:
    • AND eax, ebx (eax = eax & ebx, 비트 AND)
    • OR eax, 0xFF (eax = eax | 0xFF, 비트 OR)
    • XOR eax, eax (eax = 0, 자기 자신과 XOR하면 0)
    • NOT eax (eax의 모든 비트 반전)
    • SHL eax, 2 (eax를 왼쪽으로 2비트 시프트)
    • SHR eax, 1 (eax를 오른쪽으로 1비트 시프트)
  • 분기문:
    • JMP label (label로 점프)
    • JZ/JE label (결과가 0/같으면 label로 점프)
    • JNZ/JNE label (결과가 0이 아님/같지 않으면 점프)
    • JG/JA label (크면 점프)
    • JL/JB label (작으면 점프)
    • CALL function (함수 호출)
    • RET (함수에서 복귀)
  • 메모리 접근:
    • PUSH eax (eax 값을 스택에 저장)
    • POP eax (스택 값을 eax에 저장)
    • LEA eax, [ebx+4] (ebx+4 주소를 eax에 로드)
  • 비교 연산:
    • CMP eax, ebx (eax와 ebx 비교, 결과는 플래그 설정)
    • TEST eax, ebx (eax와 ebx의 비트 AND 테스트)
  • 기타:
    • NOP (아무 동작 안함)
    • INT 0x80 (시스템 콜, 리눅스)
    • SYSCALL (시스템 콜, 최신 x64)

4. 어셈블리어

C 코드

// C 코드
int main() {
    int a = 1;
    int b = 2;
    int c = a + b;
    return c;
}

어셈블리 버전

main:
    push ebp              ; 스택 프레임 설정
    mov ebp, esp          ; 새 베이스 포인터 설정
    sub esp, 12           ; 변수 공간 확보

    mov dword [ebp-4], 1  ; a = 1
    mov dword [ebp-8], 2  ; b = 2

    mov eax, [ebp-4]      ; eax = a
    add eax, [ebp-8]      ; eax = eax + b
    mov [ebp-12], eax     ; c = eax

    mov eax, [ebp-12]     ; 반환값 설정

    mov esp, ebp          ; 스택 정리
    pop ebp               ; 이전 프레임 복원
    ret                   ; 반환

어셈블리어 명령과 CPU 동작 관계

어셈블리어 명령CPU 작동 과정관련 구성 요소
push ebp스택에 값 저장메모리 쓰기, 스택 포인터 감소
mov ebp, esp레지스터 간 데이터 복사범용 레지스터
sub esp, 12스택 공간 확보를 위한 뺄셈ALU(뺄셈 연산)
mov [ebp-4], 1메모리에 즉시값 저장MAR, MBR, 메모리 쓰기
mov eax, [ebp-4]메모리에서 레지스터로 데이터 로드MAR, MBR, 레지스터
add eax, [ebp-8]덧셈 연산 수행ALU(덧셈 연산), 범용 레지스터
ret실행 흐름 복귀PC 업데이트

CPU 구성 요소와 실제 레지스터 매핑 (x86)

  • 범용 레지스터: eax, ebx, ecx, edx
  • 스택 관리: esp(스택 포인터), ebp(베이스 포인터)
  • 프로그램 카운터: eip(명령어 포인터)
  • 상태 레지스터: eflags

CPU 시뮬

  • 레지스터, 메모리, ALU, 제어장치를 클래스로 구현
  • 명령어 세트 정의
  • 인출-해독-실행 과정을 함수로 구현

실행 과정 (ADD 명령어)

  • 시간 단계(T0, T1, T2) 표현
인출 사이클:
T0: MAR ← PC
T1: MBR ← M[MAR], PC ← PC+1
T2: IR ← MBR

실행 사이클:
T0: MAR ← IR(Addr)
T1: MBR ← M[MAR]
T2: AC ← AC + MBR

x86 어셈블리어 버전:

메모리의 값을 누산기에 더하는 연산

mov eax, [addr1]    ; 누산기(eax)에 첫 번째 값 로드
add eax, [addr2]    ; 두 번째 값을 누산기에 더함
mov [result], eax   ; 결과를 메모리에 저장

; 각 어셈블리 명령어가 CPU 내부에서 처리될 때 일어나는 마이크로 연산:
; 'mov eax, [addr1]'이 실행될 때:
;   1. CPU는 addr1 주소를 MAR에 로드
;   2. 메모리에서 해당 값을 읽어 MBR에 저장
;   3. MBR의 값을 eax 레지스터로 전송

; 'add eax, [addr2]'가 실행될 때:
;   1. addr2 주소를 MAR에 로드
;   2. 메모리에서 해당 값을 읽어 MBR에 저장
;   3. ALU가 eax와 MBR 값을 더해 eax에 저장

3. 성능 최적화 방식

5. 캐시 메모리

  • 자주 쓰는 데이터를 CPU 가까이 두는 빠른 임시 저장소
  • 메모리(RAM)는 느림 → 캐시로 속도 개선

구조

  • L1 캐시: CPU 내부의 가장 빠른 캐시 (크기 작음)
  • L2 캐시: L1보다 크지만 조금 느린 캐시
  • L3 캐시: 여러 CPU 코어가 공유하는 더 큰 캐시

작동 원리

  • 캐시 히트: CPU가 찾는 데이터가 캐시에 있으면 바로 사용
  • 캐시 미스: 캐시에 없으면 메모리에서 가져와 캐시에 저장 후 사용

비유

  • 책상(캐시) 위 자주 쓰는 책 vs 책장(메모리)에서 책 가져오기
  • 가까이 있는 책상 위 책을 보는 게 훨씬 빠름

6. CPU 파이프라인

  • 명령어 실행을 여러 단계로 나누어 동시에 여러 명령어 처리

5단계 파이프라인

  1. 인출(Fetch): 메모리에서 명령어 가져오기
  2. 해독(Decode): 명령어 해석
  3. 실행(Execute): 연산 수행
  4. 메모리(Memory): 필요시 메모리 접근
  5. 쓰기(Write Back): 결과 저장

동작

       T1    T2    T3    T4    T5    T6    T7    T8    T9
명령1: [인출]→[해독]→[실행]→[메모리]→[쓰기]
명령2:       [인출]→[해독]→[실행]→[메모리]→[쓰기]
명령3:              [인출]→[해독]→[실행]→[메모리]→[쓰기]

문제점

  • 데이터 의존성: 이전 명령어 결과가 필요한 경우
  • 제어 의존성: 분기문으로 실행 경로 변경 시
  • 구조적 의존성: 같은 하드웨어 자원 필요 시

해결

  • 데이터 포워딩: 결과를 바로 다음 단계로 전달
  • 분기 예측: 실행 경로 미리 예측
  • 명령어 재배치: 의존성 없는 명령어 먼저 실행

7. 분기 예측

개념

  • CPU 파이프라인에서 조건문(if/else) 만날 때 다음 실행 경로 미리 예측
  • 예측 성공 시 파이프라인 계속 진행, 실패 시 파이프라인 초기화로 성능 저하

성능 영향

  • 예측 실패: 15-20 사이클 지연 발생
  • 반복 실행되는 코드에서 큰 성능 차이 유발

최적화 방법

  • 분기 없는 코드 작성: 조건부 연산자 활용
    • if(a>b) x=a; else x=b;x = (a>b) ? a : b;
  • 가능성 높은 코드 먼저: 자주 실행되는 경로 우선 배치
  • 패턴 예측성 높이기: 일관된 조건 사용
  • 데이터 정렬: 정렬된 데이터는 예측 성공률 향상

예시

// 분기 있는 코드
if (value > threshold) {
    result += value;
}

// 분기 없는 코드
result += (value > threshold) * value;

https://porolog.tistory.com/15

https://rangvest.tistory.com/entry/CPU%EC%9D%98-%EA%B5%AC%EC%A1%B0-%EB%B0%8F-%EC%9B%90%EB%A6%AC-CPU%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83

https://gyoogle.dev/blog/computer-science/computer-architecture/%EC%A4%91%EC%95%99%EC%B2%98%EB%A6%AC%EC%9E%A5%EC%B9%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.html

https://namu.wiki/w/CPU/%EA%B5%AC%EC%A1%B0%EC%99%80%20%EC%9B%90%EB%A6%AC

https://namu.wiki/w/CPU

  • 시뮬레이터 코드
    #include <iostream>
    #include <vector>
    #include <map>
    #include <string>
    #include <functional>
    #include <cstdint>
    
    using namespace std;
    
    // 메모리 클래스
    class Memory {
    private:
        vector<uint8_t> data;
    
    public:
        Memory(size_t size = 65536) : data(size, 0) {}
    
        uint8_t read8(uint16_t address) const {
            return data[address];
        }
    
        uint16_t read16(uint16_t address) const {
            return static_cast<uint16_t>(data[address]) | (static_cast<uint16_t>(data[address + 1]) << 8);
        }
    
        void write8(uint16_t address, uint8_t value) {
            data[address] = value;
        }
    
        void write16(uint16_t address, uint16_t value) {
            data[address] = value & 0xFF;
            data[address + 1] = (value >> 8) & 0xFF;
        }
    
        void load_program(const vector<uint8_t>& program, uint16_t start_address = 0) {
            for (size_t i = 0; i < program.size(); i++) {
                data[start_address + i] = program[i];
            }
        }
    };
    
    // 레지스터 클래스
    class Registers {
    public:
        uint16_t PC;    // 프로그램 카운터
        uint16_t IR;    // 명령어 레지스터
        uint16_t MAR;   // 메모리 주소 레지스터
        uint16_t MBR;   // 메모리 버퍼 레지스터
        uint16_t AC;    // 누산기
        uint16_t SP;    // 스택 포인터
        uint16_t BP;    // 베이스 포인터
        
        // 범용 레지스터
        uint16_t R0, R1, R2, R3;
        
        // 상태 플래그
        bool Z;    // 제로 플래그
        bool C;    // 캐리 플래그
        bool N;    // 네거티브 플래그
        bool V;    // 오버플로우 플래그
    
        Registers() : PC(0), IR(0), MAR(0), MBR(0), AC(0), SP(0), BP(0),
                     R0(0), R1(0), R2(0), R3(0),
                     Z(false), C(false), N(false), V(false) {}
    
        void reset() {
            PC = IR = MAR = MBR = AC = SP = BP = R0 = R1 = R2 = R3 = 0;
            Z = C = N = V = false;
        }
    };
    
    // ALU 클래스
    class ALU {
    private:
        Registers& registers;
    
    public:
        ALU(Registers& regs) : registers(regs) {}
    
        uint16_t add(uint16_t a, uint16_t b) {
            uint32_t result = static_cast<uint32_t>(a) + static_cast<uint32_t>(b);
            
            // 상태 플래그 업데이트
            registers.Z = (result & 0xFFFF) == 0;
            registers.C = (result > 0xFFFF);
            registers.N = (result & 0x8000) != 0;
            registers.V = ((a & 0x8000) == (b & 0x8000)) && ((result & 0x8000) != (a & 0x8000));
            
            return static_cast<uint16_t>(result);
        }
    
        uint16_t sub(uint16_t a, uint16_t b) {
            return add(a, ~b + 1);  // 2의 보수를 이용한 뺄셈
        }
    
        uint16_t mul(uint16_t a, uint16_t b) {
            uint32_t result = static_cast<uint32_t>(a) * static_cast<uint32_t>(b);
            registers.Z = (result & 0xFFFF) == 0;
            registers.C = (result > 0xFFFF);
            return static_cast<uint16_t>(result);
        }
    
        uint16_t div(uint16_t a, uint16_t b) {
            if (b == 0) {
                // 0으로 나누기 시도 (실제로는 예외처리 필요)
                cout << "Error: Division by zero" << endl;
                return 0;
            }
            
            uint16_t result = a / b;
            registers.Z = result == 0;
            return result;
        }
    
        uint16_t logical_and(uint16_t a, uint16_t b) {
            uint16_t result = a & b;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            return result;
        }
    
        uint16_t logical_or(uint16_t a, uint16_t b) {
            uint16_t result = a | b;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            return result;
        }
    
        uint16_t logical_xor(uint16_t a, uint16_t b) {
            uint16_t result = a ^ b;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            return result;
        }
    
        uint16_t logical_not(uint16_t a) {
            uint16_t result = ~a;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            return result;
        }
    
        uint16_t shift_left(uint16_t a, uint16_t count) {
            uint16_t result = a << count;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            // 마지막으로 밀려나간 비트가 캐리
            registers.C = (count > 0) && ((a & (1 << (16 - count))) != 0);
            return result;
        }
    
        uint16_t shift_right(uint16_t a, uint16_t count) {
            uint16_t result = a >> count;
            registers.Z = result == 0;
            registers.N = (result & 0x8000) != 0;
            // 마지막으로 밀려나간 비트가 캐리
            registers.C = (count > 0) && ((a & (1 << (count - 1))) != 0);
            return result;
        }
    };
    
    // 명령어 집합 정의 (Op codes)
    enum OpCode {
        // 데이터 이동
        MOV = 0x10,
        LOAD = 0x11,
        STORE = 0x12,
        PUSH = 0x13,
        POP = 0x14,
        
        // 산술 연산
        ADD = 0x20,
        SUB = 0x21,
        MUL = 0x22,
        DIV = 0x23,
        INC = 0x24,
        DEC = 0x25,
        
        // 논리 연산
        AND = 0x30,
        OR = 0x31,
        XOR = 0x32,
        NOT = 0x33,
        SHL = 0x34,
        SHR = 0x35,
        
        // 분기
        JMP = 0x40,
        JZ = 0x41,
        JNZ = 0x42,
        JG = 0x43,
        JL = 0x44,
        
        // 시스템 & 특수 명령어
        CALL = 0x50,
        RET = 0x51,
        NOP = 0x00,
        HALT = 0xFF
    };
    
    // CPU 클래스
    class CPU {
    private:
        Memory& memory;
        Registers registers;
        ALU alu;
        bool running;
        
        // 명령어 핸들러 맵
        map<OpCode, function<void(uint8_t)>> instruction_handlers;
    
    public:
        CPU(Memory& mem) : memory(mem), registers(), alu(registers), running(false) {
            initialize_instruction_handlers();
        }
    
        void initialize_instruction_handlers() {
            // 각 명령어 타입별 실행 함수 등록
            instruction_handlers[NOP] = [this](uint8_t operand) { /* 아무것도 하지 않음 */ };
            
            instruction_handlers[MOV] = [this](uint8_t operand) {
                uint8_t dest = (operand >> 4) & 0x0F;
                uint8_t src = operand & 0x0F;
                uint16_t value = get_register_value(src);
                set_register_value(dest, value);
            };
            
            instruction_handlers[LOAD] = [this](uint8_t operand) {
                uint8_t reg = (operand >> 4) & 0x0F;
                uint16_t address = memory.read16(registers.PC);
                registers.PC += 2;
                uint16_t value = memory.read16(address);
                set_register_value(reg, value);
            };
            
            instruction_handlers[STORE] = [this](uint8_t operand) {
                uint8_t reg = (operand >> 4) & 0x0F;
                uint16_t address = memory.read16(registers.PC);
                registers.PC += 2;
                uint16_t value = get_register_value(reg);
                memory.write16(address, value);
            };
            
            instruction_handlers[ADD] = [this](uint8_t operand) {
                uint8_t dest = (operand >> 4) & 0x0F;
                uint8_t src = operand & 0x0F;
                uint16_t a = get_register_value(dest);
                uint16_t b = get_register_value(src);
                uint16_t result = alu.add(a, b);
                set_register_value(dest, result);
            };
            
            instruction_handlers[SUB] = [this](uint8_t operand) {
                uint8_t dest = (operand >> 4) & 0x0F;
                uint8_t src = operand & 0x0F;
                uint16_t a = get_register_value(dest);
                uint16_t b = get_register_value(src);
                uint16_t result = alu.sub(a, b);
                set_register_value(dest, result);
            };
            
            instruction_handlers[JMP] = [this](uint8_t operand) {
                uint16_t address = memory.read16(registers.PC);
                registers.PC = address;
            };
            
            instruction_handlers[JZ] = [this](uint8_t operand) {
                uint16_t address = memory.read16(registers.PC);
                registers.PC += 2;
                if (registers.Z) {
                    registers.PC = address;
                }
            };
            
            instruction_handlers[JNZ] = [this](uint8_t operand) {
                uint16_t address = memory.read16(registers.PC);
                registers.PC += 2;
                if (!registers.Z) {
                    registers.PC = address;
                }
            };
            
            instruction_handlers[HALT] = [this](uint8_t operand) {
                running = false;
            };
            
            // 나머지 명령어 핸들러들 추가...
        }
    
        // 레지스터 값 가져오기 헬퍼 함수
        uint16_t get_register_value(uint8_t reg_code) {
            switch (reg_code) {
                case 0: return registers.R0;
                case 1: return registers.R1;
                case 2: return registers.R2;
                case 3: return registers.R3;
                case 4: return registers.PC;
                case 5: return registers.SP;
                case 6: return registers.BP;
                case 7: return registers.AC;
                default: 
                    cout << "Error: Invalid register code: " << (int)reg_code << endl;
                    return 0;
            }
        }
    
        // 레지스터 값 설정 헬퍼 함수
        void set_register_value(uint8_t reg_code, uint16_t value) {
            switch (reg_code) {
                case 0: registers.R0 = value; break;
                case 1: registers.R1 = value; break;
                case 2: registers.R2 = value; break;
                case 3: registers.R3 = value; break;
                case 4: registers.PC = value; break;
                case 5: registers.SP = value; break;
                case 6: registers.BP = value; break;
                case 7: registers.AC = value; break;
                default: 
                    cout << "Error: Invalid register code: " << (int)reg_code << endl;
            }
        }
    
        // 인출-해독-실행 사이클
        void fetch_decode_execute() {
            // 인출 단계
            registers.MAR = registers.PC;
            registers.MBR = memory.read8(registers.MAR);
            registers.PC++;
            registers.IR = registers.MBR;
            
            // 해독 단계
            uint8_t opcode = registers.IR;
            uint8_t operand = memory.read8(registers.PC);
            registers.PC++;
            
            // 실행 단계
            if (instruction_handlers.find(static_cast<OpCode>(opcode)) != instruction_handlers.end()) {
                instruction_handlers[static_cast<OpCode>(opcode)](operand);
            } else {
                cout << "Error: Unknown opcode: 0x" << hex << (int)opcode << endl;
                running = false;
            }
        }
    
        void reset() {
            registers.reset();
            running = false;
        }
    
        void run() {
            running = true;
            
            while (running) {
                fetch_decode_execute();
                
                // 디버깅을 위한 상태 출력
                print_state();
            }
        }
    
        // CPU 상태 출력을 위한 디버그 함수
        void print_state() {
            cout << "PC: 0x" << hex << registers.PC << " ";
            cout << "IR: 0x" << hex << registers.IR << " ";
            cout << "AC: 0x" << hex << registers.AC << " ";
            cout << "SP: 0x" << hex << registers.SP << " ";
            cout << "BP: 0x" << hex << registers.BP << endl;
            
            cout << "R0: 0x" << hex << registers.R0 << " ";
            cout << "R1: 0x" << hex << registers.R1 << " ";
            cout << "R2: 0x" << hex << registers.R2 << " ";
            cout << "R3: 0x" << hex << registers.R3 << endl;
            
            cout << "Flags - Z: " << registers.Z << " C: " << registers.C;
            cout << " N: " << registers.N << " V: " << registers.V << endl;
            cout << "------------------------------------------" << endl;
        }
    };
    
    // 샘플 프로그램 예제 (간단한 어셈블리 프로그램을 실행)
    int main() {
        // 메모리 생성
        Memory memory;
        
        // 샘플 프로그램 작성
        // 이 프로그램은 R0에 10을 로드하고, R1에 20을 로드한 다음, 두 값을 더해 R2에 저장합니다.
        vector<uint8_t> program = {
            // R0 = 10
            MOV, 0x70,  // Acc에 값을 로드 (7: AC)
            0x0A, 0x00, // 값: 10
            MOV, 0x07,  // R0 = Acc
            
            // R1 = 20
            MOV, 0x70,  // Acc에 값을 로드
            0x14, 0x00, // 값: 20
            MOV, 0x17,  // R1 = Acc
            
            // R2 = R0 + R1
            MOV, 0x70,  // Acc = R0
            ADD, 0x71,  // Acc += R1
            MOV, 0x27,  // R2 = Acc
            
            // 프로그램 종료
            HALT, 0x00
        };
        
        // 프로그램 로드
        memory.load_program(program);
        
        // CPU 생성 및 실행
        CPU cpu(memory);
        cpu.reset();
        cpu.run();
        
        return 0;
    } 
profile
치킨강정

0개의 댓글