Computer_Architecture_Week_5
CPU가 수행하는 일
명렁어 집합 구조에서의 명령어는 CPU를 위한 명령어임.
=> CPU가 명령어를 처리할 때 어떤 메카니즘으로 하는지에 대해 알아볼 것임.
- CPU는 주 메모리에서 명령어를 하나 가져와서 처리하고, 그 다음에 또 가져오고 하나씩 처리함.
- 명령어 인출과 해독(Instruction Fetch & Decode)
-> 기억장치로부터 명령어를 읽어오고, 읽어온 명령어가 무엇인지 해독
-> 명령어가 어떤 형식에 맞춰서 봉투에 담겨온다고 쳤을 때, 봉투를 다 열기 전까지는 모름 - 데이터 인출(Data Fetch, Load)
-> 기억장치나 I/O 장치에서 데이터를 읽어옮. - 데이터 처리(Data Process)
-> 산술적 혹은 논리적 연산을 수행 - 데이터 저장(Data Store)
-> 수행한 결과를 저장 (=쓰기, write)
=> 인출/처리/저장 등은 명령어 종류에 따라 선택적으로 수행
CPU의 기본 구성
ALU: 각종 산술/논리연산들을 수행하는 회로들로 이루어진 HW 모듈
-> 산술, 논리 연산등을 함.
레지스터(register): CPU 안의, 엑세스 속도가 가장 빠른 기억장치
-> 다른 주 기억장치, 보조 기억장치보다 빠름. CPU와 가까이 있을수록 가장 빠르기 때문에(CPU가 제일 빨라서)
-> CPU 내부에 둘 수 있는 레지스터의 수는 제한적
- Program Counter: 다음 명령어의 주소 보관
-> 각 명렬어가 인출된 후에는 자동적으로 일정 크기(한 명령어 길이)만큼 증가
-> 분기 명령어가 실행되는 경우에는 목적지 주소로 갱신 - Instruction R: 가장 최근 가져온 명령어 보관
- ACCumlator: 데이터의 일시적 보관(ALU와 붙어 있음)
- Memory Address R: CPU가 접근하려는 메모리 주소 보관
- Memory Buffer R: CPU가 메모리에서 읽거나 저장할 데이터 자체를 보관
대부분의 시스템에서 레지스터의 크기는 CPU가 한 번에 처리할 수 있는 데이터 비트 수(word 길이)와 동일
-> 만약 CPU가 한번에 처리할 수 있는 데이터가 8 bit이면 레지스터의 크기 또한 8 bit이다. => 이 컴퓨터는 8 bit 인 것임.
-> 요즘 64bit 컴퓨터는, 레지스터의 크기가 64bit이고, CPU가 한번에 처리할 수 있는 데이터의 비트 수도 8bit이다.
데이터 적재/저장 명령어 실행과정
-
적재(load): CPU가 메모리에 있는 데이터를 읽어옴
-> 프로세서는 데이터가 있는 메모리 주소를 MAR에 보낸다.
-> MAR이 지정하는 메모리 주소에 있는 데이터를 읽어와 MBR에 저장한다. -
저장(store): CPU가 메모리에 데이터를 기록
-> 프로세서는 데이터를 저장할 메모리 주소를 MAR에 보낸다.
-> 프로세서는 데이터를 MBR에 저장한다.
-> 메모리는 MAR이 저장하는 위치에 MBR의 내용을 저장한다. -
명령어 사이클(instruction cycle): 명령어를 수행하는 일련의 과정
-> 컴퓨터마다 명령어 실행과정이 동일하지는 않으나, 일반적으로 거치는 최소 과정을 포함
명령어 사이클
-
CPU가 한 개의 명령어를 실행하는 데 필요한 전체 처리 과정
-> CPU가 프로그램 실행을 시작하는 순간부터 전원을 끄거나 회복 불가능한 오류가 발생하여 중단될 때까지 반복
-> 2개의 부사이클로 분리 -
인출 사이클(fetch cycle)
-> CPU가 기억장치로부터 명령어를 읽어오는 단계
-> MAR <- PC => 현재 PC가 가리키는 내용(메모리 주소)을 MAR로 전송
-> MBR <- M[MAR], PC <- PC + 1 => 메모리는 MAR이 지시하는 메모리의 내용인 명령어를 MBR로 보내고, PC가 다음 명령어를 가리키도록 PC의 내용을 갱신한다.(여기서 1은 명령어의 길이로 가정)
-> PC가 이미 MAR로 넘겨줬기 때문에, 1을 더함으로써 다음 명령어를 가리킬 수 있도록 한다.
-> IR <- MBR => MBR에 있는 명령어를 IR에 저장. MBR 과 IR는 메모리간의 통신? Buffer 역할을 한다.
여기서 질문! 왜 데이터 값이랑, 주소를 저장하는 공간이 2개씩 있는거지..?
- 실행 사이클(execution cycle)
-> 명령어를 해독하고 실행하는 단계
-> 인출 사이클때보다 작업량이 더 많기 때문에, 오늘날 컴퓨터는 실행 사이클을 다수의 단계로 분할
-> 전송 연산: CPU내 레지스터와 메모리 사이에 데이터를 교환
-> 처리 연산: 산술논리장치를 사용하여 데이터를 조작(데이터형식 변환(int -> float))
-> 제어 연산: 프로그램의 실행 순서를 제어(순차, 무조건 분기, 조건 분기 등등)
-> 입출력 연산: CPU 내 레지스터와 I/O 장치 간에 데이터를 이동
Fake Simple 컴퓨터 명령어 집합
-
명령어 형식
-> 16bit로 구성
-> 연산부호가 4 bits 혹은 16 bits
-> 0부터 15번까지 n번 째 비트가 있음 -
명령어
-> LDA: 메모리의 내용을 누산기에 적재(메모리에서 CPU로 가져오는 일)
-> STA(store): 누산기의 내용을 메모리에 저장(CPU의 내용을 메모리로 가져오는 일)
-> ADD: 누산기의 내용과 메모리의 내용을 덧셈
-> SUB: 누산기의 내용과 메모리의 내용을 뺄셈
-> JMP: 지정한 주소로 분기
-> CAL: 프로시저 호출
-> HLT: 프로그램 종료
-> CPL: 누산기의 내용을 보수화
-> IAC: 누산기의 내용을 하나 증가
-> RET: 프로시저 복귀 -
데이터 형식
-> 16bit로 구성하고 정수만 취급
-> 15번 bit는 부호를 의미하고, 0~14번 bit는 정수 크기를 의미. 15번 bit => 0: 양수, 1: 음수 -
다음과 같은 메모리 상태를 가정
-> 명령어는 메모리 0100 번지부터 시작
-> 데이터는 메모리 0500 번지와 0502번지에 숫자 0001, 0002이 저장
-> 1 Byte 단위로 주소를 매김.
-> 0100이 a의 주소이면, 0101은 a를 가리키고 0102가 그 다음 b의 주소이다.
-> 메모리에서는 대부분 주소를 Byte 단위로 표시. -
이런 일을 하고 싶다면?
-> 메모리 0500번지와 0502번지 숫자를 더해 0502 번지에 저장하고
-> 0300번지 명령어로 분기하라
=> 수식으로 표현하자면 M[502] <- M[500] + M[502]
=> PC <- 300 요정도 된다.
LDA 500 => 1500
ADD 502 => 3502
STA 502 => 2502 //누산기의 내용과 메모리의 내용을 더해서 누산기에 저장했으니, 다시 이 값을 메모리에 돌려줘야함. 따라서 STA를 써야함.
JMP 300 => 5300
조건분기 명령어
- 조건 생성, 비교 명령과 분기 명령
-> 비교와 분기작업을 하나로 융합된 명령어 구조도 있음
-> 비교 - 산술, 논리 연상 - 결과에 따라 분기 결정 - 연산 결과를 저장하는 플래그(flag) 레지스터
-> 상태(Status) 레지스터/비트, 조건 코드(Condition code) 레지스터/비트 라고 부름
-> 플래그 레지스터는 1 bit를 씀
-> 올림수(Carry): 연산 결과에 올림수가 있으면 1, 없으면 0
-> 오버플로우(overflow): 연산 결과에 오버플로우가 있으면 1, 없으면 0
-> 부호(Sign)/음수(Negative): 연산 결과가 음수면 1, 양수 혹은 이면 0
-> 영(Zero): 연산 결과가 0이면 1, 0이 아니면 0
프로시저의 호출/복귀 과정
-
cal proc: #proc은 프로시저 이름, 어셈블리 -> 기계어 과정 후 프로시저 시작주소로 변환
-
인출 사이클은 모든 명령어들이 똑같음.
-
실행 사이클: TOS(top of stack) <- PC; PC <- proc
-> 실행 사이클에서, 복귀 후 수행할 명령어 주소(복귀주소)를 TOS(Top of Stack)에 저장 -
인수(argument) 사용시 좀 더 복잡한 과정 필요
-
Q. 복귀주소 저장시, Stack이 아닌 그냥 register에 저장한다면?
-> 조건 분기같은 것을 할 때, stack이 아니라면, 순서가 꼬일 것 같음. 먼저 끝내고 나와야 하는 루프? 나 과정이 있을 텐데.. 그,, 우리 막 파이썬이나, 객체지향에서도 코딩할 때, 어느 클래스에서 다른 클래스의 메소드를 쓰고, 그 메소드에서 또 다른 클래스의 메소드를 쓸 때, 이게 하나씩 하나씩 끝내고 돌아오는 것처럼, 이것도 마찬가지일듯 ㅇㅇ -
ret #proc 프로시저 종료 후 호출 프로그램으로 복귀
-
인출 사이클은 역시 똑같음.
-
실행 사이클: PC <- TOS (아까 넣어놨던 Stack에서 꺼내옴)
아아아 알겠다. cal로 다른 프로시저에 가기전에 stack에 주소를 약간 백업? 을 하는거고, ret시 아까 cal 때 백업해놨던 프로시저로 돌아가는 거 ㅇㅇ
기말에 무조건 나옴!
왜 CPU 내 기억장치(Register)가 필요한가?
-
CPU 내부에 기억장치가 없는 가상의 컴퓨터를 가정해보자
-> M-M(메모리-메모리) 컴퓨터: CPU 내부에 데이터 저장 불가( 모든 데이터는 메모리에서 CPU를 경유하여 메모리로 전송)
-> 데이터가 필요한 경우, 명령어의 피연산자 필드에 메모리 전체 주소를 명시 -
폰 노이먼 모델에서 발생 가능한 (최소한의) 데이터 트래픽 추정
-> 시스템은 아래 조건을 따른다고 가정
-> 연산 부호 크기는 8비트(바이트)
-> 연산마다 최대 2개의 피연산자 사용(첫번 째 피연산자는 source & destination)
-> 메모리 주소는 2바이트
-> 데이터 크기는 4바이트 -
명령어 인출 트래픽
-> 한 명령어당 5바이트 * 명령어 개수 -
데이터 이동 트래픽(1)
-> a번지의 데이터를 메모리에서 CPU로 갖고 왔다가 다시 메모리 y번지로 저장. => 한 mov 명령어당 2회 이동 * 4바이트 -
데이터 이동 트래픽(2)
-> mul y,x
-> y번지와 x번지의 데이터를 CPU로 갖고 와 곱셈 수행 후, 결과 데이터를 y번지에 저장(한 명령어당 2개 데이터 4바이트 + 1개 결과데이터4바이트 => 34바이트
-> mul과 add 연산시 트래픽양 동일하므로, subtoal_mul/add = 명령어당 34바이트*n개 mul/add 명령어 -
다 더한게 총 메모리 트래픽
만약 CPU에 기억장치가 있다면?
-
데이터 트래픽 감소
-> 반복적으로 사용되는 피연산자를 CPU 내부의 기억장치에 보관
-> 메모리를 다시 참조할 필요성 제거 -
명령어 트래픽 감소
-> 대용량 메모리를 위한 긴 주소 대신에 소규모 기억장치(레지스터)의 짧은 주소 사용
-> 레지스터 개수 = 레지스터 주소 bit 수
-> 레지스터 개수 << 메모리 enty 수
-> 피연산자 필드가 짧아지면 명령어의 길이가 축소
Author And Source
이 문제에 관하여(Computer_Architecture_Week_5), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@shintaewon/ComputerArchitectureWeek5저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)