+ 한국항공대학교 길현영 교수님의 컴퓨터구조론 과목 내용을 정리한 글입니다.
피연산자 수와 명령어 집합
명령어 구성
- 연산 부호(opcode): 어떤 연산을 수행할 것인가
- 피연산자(operand): 연산의 대상이 되는 데이터(들)의 위치 또는 값 등의 정보
피연산자 수에 따른 컴퓨터구조 종류 (시스템 가정)
1) 스택(Stack) 컴퓨터의 0-주소 명령어
ex) ADD
=> S[top--] + S[top--] -> S[top]
2) 누산기(Accumulator) 컴퓨터의 1-주소 명령어
ex) ADD X
=> Acc <- Acc + M[X]
3) 범용 레지스터(General Purpose R) 컴퓨터의 2-주소 혹은 3-주소 명령어
ex) ADD R1 R2
=> R1 <- R1 + R2
ex) ADD R1 X
=> R1 <- R1 + M[X]
ex) ADD R1 R2 R3
=> R1 <- R2 + R3
스택 컴퓨터
스택 컴퓨터의 특징
1. CPU 내의 데이터 저장소로 스택을 사용한다. (M-M과 달리)
- 다수의 데이터가 저장 가능하다. (최대 스택 원소 개수만큼 저장이 가능하다.)
- 저장할 데이터의 개수가 스택 원소보다 큰 경우, 삭제(policy)가 필요하다.
2. 대부분의 연산(수리, 논술) 명령어의 피연산자가 명시되지 않는다.
- 스택의 top이나 top-1에 위치한 데이터를 사용하고 연산 결과를 스택의 top에 저장한다.
=> 명령어의 길이가 짧다.
3. 스택 안의 데이터를 접근하려는 경우, 스택 내 데이터의 위치에 따라 데이터 접근 시간이 다르다.
- 위에 있는 데이터들을 Pop하고, 원하는 데이터를 꺼낸 후, 다시 위에 있었던 데이터들을 Push한다.
4. Push / Pop 명령어를 사용한다.
Push: 메모리의 특정 위치에 있는 데이터를 스택 S[top]으로 이동시킨다. (Load)
Pop: S[top]의 데이터를 메모리로 이동시킨다. (Store)
스택 컴퓨터 가정
시스템은 아래 조건을 따른다고 가정한다.
- 연산 부호 비트는 8Bit (1Byte)이다.
- 연산마다 0개 또는 1개의 피연산자를 사용한다. (피연산자 1개는 2Byte이다.)
- 메모리 주소는 16Bit (2 Byte)이고, 데이터의 크기는 32 Bit(4 Byte)이다.
스택 컴퓨터: y = ax^2 + bx + x
1. ax^2를 스택에 저장하기
1) Stack: {M[a]}
push a
=> S[top] <- M[a]: 메모리 주소 a의 데이터를 S[top]에 저장한다.
2) Stack: {M[a], M[x]}
push x
=> S[top] <- M[x]: 메모리 주소 x의 데이터를 S[top]에 저장한다.
3) Stack: {M[a], M[x], M[x]}
push x
=> S[top] <- M[x]: 메모리 주소 x의 데이터를 S[top]에 저장한다.
4) Stack: {M[a], M[x]^2]}
mul x
=> S[top] <- S[top--] × S[top--]: TOS에 해당하는 데이터를 두 번 꺼내서 둘을 곱하고 다시 TOS에 저장한다.
5) Stack: {M[a] × M[x]^2]}
mul x
=> S[top] <- S[top--] × S[top--]: TOS에 해당하는 데이터를 두 번 꺼내서 둘을 곱하고 다시 TOS에 저장한다.
2. bx를 스택에 저장하기
6) Stack: {M[a] × M[x]^2], M[b]}
push b
=> S[top] <- M[b]: 메모리 주소 b의 데이터를 S[top]에 저장한다.
7) Stack: {M[a] × M[x]^2], M[b], M[x]}
push x
=> S[top] <- M[x]: 메모리 주소 x의 데이터를 S[top]에 저장한다.
8) Stack: {M[a] × M[x]^2], M[b] × M[x]}
mul
=> S[top] <- S[top--] × S[top--]: TOS에 해당하는 데이터를 두 번 꺼내서 둘을 곱하고 다시 TOS에 저장한다.
3. c를 스택에 저장하기
9) Stack: {M[a] × M[x]^2], M[b] × M[x], M[c]}
push c
=> S[top] <- M[c]: 메모리 주소 c의 데이터를 S[top]에 저장한다.
4. ax^2 + bx + c 만들기
10) Stack: {M[a] × M[x]^2], M[b] × M[x] + M[c]}
add
=> S[top] <- S[top--] + S[top--]: TOS에 해당하는 데이터를 두 번 꺼내서 둘을 더하고 다시 TOS에 저장한다.
11) Stack: {M[a] × M[x]^2] + M[b] × M[x] + M[c]}
add
=> S[top] <- S[top--] + S[top--]: TOS에 해당하는 데이터를 두 번 꺼내서 둘을 더하고 다시 TOS에 저장한다.
5. 메모리 주소 y에 ax^2 + bx + c 저장하기
12) Stack: {}
pop y
=> M[y] <- S[top--]: TOS에 해당하는 데이터를 꺼내서 메모리 주소 y에 저장한다.
< 명령어 인출 트래픽 >
1. push, pop 연산
- 연산 부호(1Byte) + 피연산자(2Byte) = 한 명령어당 3 Byte 트래픽 발생
=> 7개 × 3 Byte = 21 Byte 트래픽 발생
2. mul, add 연산
- 연산 부호(1Byte) = 한 명령어당 1 Byte 트래픽 발생
=> 5개 × 1 Byte = 5 Byte 트래픽 발생
=> 26 Byte 트래픽 발생
< 데이터 이동 트래픽 >
1. push, pop 연산
- 데이터 크기(4Byte) × 1회 이동 = 한 명령어당 4 Byte 트래픽 발생
=> 7개 × 4 Byte = 28 Byte 트래픽 발생
2. mul, add 연산
- 데이터 크기(4Byte) × 0회 이동 = 한 명령어당 0 Byte 트래픽 발생
(CPU 내에서 연산하므로 데이터가 CPU와 메모리사이를 이동하지 않는다.)
=> 5개 × 0 Byte = 0 Byte 트래픽 발생
=> 28 Byte 트래픽 발생
따라서, 26 Byte + 28 Byte = 총 54 Byte의 트래픽이 발생한다.
누산기 컴퓨터
누산기 컴퓨터의 특징
1. Acc 레지스터를 연산 관련 데이터를 저장할 수 있는 유일한 저장소로 사용한다.
- 적재 / 저장 명령어가 아니면, Acc는 피연산자의 source & destination 이다. (a + b -> a)
- CPU 내 하나의 레지스터(Acc)만 존재한다.
2. CPU 내 Acc 레지스터를 묵시적 피연산자 필드로 사용한다.
- 명령어 내 피연산자를 명시하지 않아도 Acc 내 데이터를 피연산자로 사용한다.
- 메모리에 있는 데이터를 갖고 오는 경우는 피연산자에 명시한다.
3. 단순한 구조로 개발 비용이 저렴하다.
4. M - M 컴퓨터보다 CPU - M 트래픽 감소 효과가 발생한다.
누산기 컴퓨터 가정
시스템은 아래 조건을 따른다고 가정한다.
- 연산 부호 비트는 8Bit (1Byte)이다.
- 연산마다 1개의 피연산자를 사용한다. (피연산자 1개는 2Byte이다.)
- 메모리 주소는 16Bit (2 Byte)이고, 데이터의 크기는 32 Bit(4 Byte)이다.
누산기 컴퓨터: y = ax^2 + bx + x
1. ax^2를 y에 저장하기
1) Acc: {M[a]}
lda a
=> Acc <- M[a]: 메모리 주소 a의 데이터를 Acc에 저장한다.
2) Acc: {M[a] × M[x]}
mul x
=> Acc <- Acc × M[x]: Acc의 데이터를 꺼내서 메모리 주소 x의 데이터와 곱하고 Acc에 저장한다.
3) Acc: {M[a] × M[x]^2}
mul x
=> Acc <- Acc × M[x]: Acc의 데이터를 꺼내서 메모리 주소 x의 데이터와 곱하고 Acc에 저장한다.
4) Acc: {}
sta y
=> M[y] <- Acc: Acc의 데이터를 메모리 주소 y에 저장한다.
2. ax^2 + bx + c를 y에 저장하기
5) Acc: {M[b]}
lda b
=> Acc <- M[b]: 메모리 주소 b의 데이터를 Acc에 저장한다.
6) Acc: {M[b] × M[x]}
mul x
=> Acc <- Acc × M[x]: Acc의 데이터를 꺼내서 메모리 주소 x의 데이터와 곱하고 Acc에 저장한다.
7) Acc: {M[b] × M[x] + M[c]}
add c
=> Acc <- Acc + M[c]: Acc의 데이터를 꺼내서 메모리 주소 c의 데이터와 더하고 Acc에 저장한다.
8) Acc: {M[a] × M[x]^2 + M[b] × M[x] + M[c]}
add y
=> Acc <- Acc + M[y]: Acc의 데이터를 꺼내서 메모리 주소 y의 데이터와 더하고 Acc에 저장한다.
9) Acc: {}
sta y
=> M[y] <- Acc: Acc의 데이터를 메모리 주소 y에 저장한다.
< 명령어 인출 트래픽 >
모든 명령어의 길이가 같다.
- 연산 부호(1Byte) + 피연산자(2 Byte) = 한 명령어당 3 Byte 트래픽 발생
=> 9개 × 3 Byte = 27 Byte 트래픽 발생
< 데이터 이동 트래픽 >
모든 명령어가 데이터를 1번 이동시킨다.
- 데이터 크기(4Byte) × 1회 이동 = 한 명령어당 4 Byte 트래픽 발생
=> 9개 × 4Byte = 36 Byte 트래픽 발생
따라서, 27 Byte + 36 Byte = 총 63 Byte의 트래픽이 발생한다.
범용 레지스터 컴퓨터
범용 레지스터 컴퓨터의 특징
1. 명령어의 피연산자로서 특정 레지스터(레지스터 번호)를 명시하여 사용한다.
- 다수의 레지스터가 존재하며, 스택 / 누산기처럼 암묵적 피연산자 R을 갖고 있지 않다.
- 스택과 달리 모든 레지스터의 접근 시간이 동일하다.
2. 두 종류의 명령어를 사용한다.
2-주소 명령어: 피연산자가 2개로 그 중 하나는 Source & Destination으로 사용한다.
- Source & Destination으로 사용되는 레지스터 값은 연산 후 Source값이 사라진다.
- 명령어의 길이가 짧아 메모리 사용이 감소한다.
ex) add r1 r2 : r1 <- r1 + r2
3-주소 명령어: 피연산자가 3개로, Source 2개, Destination 1개가 사용된다.
ex) add r1 r2 r3 : r1 <- r2 + r3
- 연산 후 Source 값이 보존된다. (Destination 값은 Overwrite되어진다.)
- 명령어의 길이가 상대적으로 길어 메모리 사용이 증가한다.
3. 적재-저장 명령어만 메모리에 접근하도록 제한한다. (적재-저장 명령어 모델)
- 적재 명령어 (load): 데이터를 메모리에서 CPU 레지스터로 전송한다.
- 저장 명령어 (store): 데이터를 CPU 레지스터에서 메모리로 전송한다.
=> 연산 명령어의 피연산자로 메모리 주소를 사용할 수 없다.
- 피연산자를 load한 이후에 연산이 가능하다.
- 레지스터 주소 길이는 메모리 주소보다 짧기 때문에, M - M 컴퓨터 명령어 길이보다 짧다.
(레지스터의 크기가 메인 메모리의 크기보다 훨씬 작기 때문이다.)
- 자주 쓰는 데이터를 CPU 내 레지스터 안에 두고 쓰므로, CPU-Memory 간 데이터 트래픽이 줄어든다.
범용 레지스터 컴퓨터 가정
시스템은 아래 조건을 따른다고 가정한다.
- 연산 부호 비트는 8Bit (1Byte)이다.
- 연산마다 최대 2개의 피연산자, 즉 2-주소 명령어를 사용한다. (피연산자 1개는 2Byte이다.)
- 0 ~ 15까지 총 16개의 레지스터를 사용한다. => 레지스터 주소는 4 bit이다.
- 메모리 주소는 16Bit (2 Byte)이고, 데이터의 크기는 32 Bit(4 Byte)이다.
범용 레지스터 컴퓨터: y = ax^2 + bx + x
1. x, a, b, c를 각 레지스터에 저장하기
1) r1: {M[x]}
load r1 x
=> r1 <- M[x]: 메모리 주소 x의 데이터를 r1 레지스터에 저장한다.
2) r1: {M[x]}, r2: {M[a]}
load r2 a
=> r2 <- M[a]: 메모리 주소 a의 데이터를 r2 레지스터에 저장한다.
3) r1: {M[x]}, r2: {M[a]}, r3: {M[b]}
load r3 b
=> r3 <- M[b]: 메모리 주소 b의 데이터를 r3 레지스터에 저장한다.
4) r1: {M[x]}, r2: {M[a]}, r3: {M[b]}, r4: {M[c]}
load r4 c
=> r4 <- M[c]: 메모리 주소 c의 데이터를 r4 레지스터에 저장한다.
2. r2 레지스터에 ax^2 저장하기
5) r1: {M[x]}, r2: {M[a] × M[x]}, r3: {M[b]}, r4: {M[c]}
mul r2 r1
=> r2 <- r2 × r1: r2 레지스터의 데이터와 r1 레지스터의 데이터를 곱하여 r2 레지스터에 저장한다.
6) r1: {M[x]}, r2: {M[a] × M[x] × M[x]}, r3: {M[b]}, r4: {M[c]}
mul r2 r1
=> r2 <- r2 × r1: r2 레지스터의 데이터와 r1 레지스터의 데이터를 곱하여 r2 레지스터에 저장한다.
3. r3 레지스터에 bx 저장하기
7) r1: {M[x]}, r2: {M[a] × M[x] × M[x]}, r3: {M[b] × M[x]}, r4: {M[c]}
mul r3 r1
=> r3 <- r3 × r1: r3 레지스터의 데이터와 r1 레지스터의 데이터를 곱하여 r3 레지스터에 저장한다.
4. r4 레지스터에 ax^2 + bx + c 저장하기
8) r1: {M[x]}, r2: {M[a] × M[x] × M[x] + M[b] × M[x]}, r3: {M[b] × M[x]}, r4: {M[c]}
add r2 r3
=> r2 <- r2 + r3: r2 레지스터의 데이터와 r3 레지스터의 데이터를 더하여 r2 레지스터에 저장한다.
9) r1: {M[x]}, r2: {M[a] × M[x] × M[x] + M[b] × M[x] + M[c]}, r3: {M[b] × M[x]}, r4: {M[c]}
add r2 r4
=> r2 <- r2 + r4: r2 레지스터의 데이터와 r4 레지스터의 데이터를 더하여 r2 레지스터에 저장한다.
5. r2 레지스터의 데이터를 y에 저장하기
10) M[y]: {M[a] × M[x] × M[x] + M[b] × M[x] + M[c]}
store r4 y
=> M[y] <- r4: r4 레지스터의 데이터를 메모리 주소 y에 저장한다.
+ 피연산자의 순서는 명령어 집합마다 다르다.
< 명령어 인출 트래픽 >
1. load, store 연산
- 연산 부호(1 Byte) + 피연산자(3 Byte) = 한 명령어당 4 Byte 트래픽 발생
- 피연산자 크기 = 레지스터 주소 (4 Bit) + 메모리 주소 (2 Byte) = 3 Byte
(명령어의 기본 단위가 Byte이기 때문)
=> 5개 × 4 Byte = 20 Byte 트래픽 발생
2. mul, add 연산
- 연산 부호(1 Byte) + 피연산자(1 Byte) = 한 명령어당 2 Byte 트래픽 발생
- 피연산자 크기 = 레지스터 주소 (4 Bit) + 레지스터 주소 (4 Bit) = 1 Byte
=> 5개 × 2 Byte = 10 Byte 트래픽 발생
=> 30 Byte 트래픽 발생
< 데이터 이동 트래픽 >
1. load, store 연산
- 데이터 크기(4Byte) × 1회 이동 = 한 명령어당 4 Byte 트래픽 발생
=> 5개 × 4 Byte = 20 Byte 트래픽 발생
2. mul, add 연산
- 데이터 크기(4Byte) × 0회 이동 = 한 명령어당 0 Byte 트래픽 발생
(CPU 내에서 연산하므로 데이터가 CPU와 메모리사이를 이동하지 않는다.)
=> 5개 × 0 Byte = 0 Byte 트래픽 발생
=> 20 Byte 트래픽 발생
따라서, 20 Byte + 30 Byte = 총 50 Byte의 트래픽이 발생한다.
'Computer Science > Computer Architecture' 카테고리의 다른 글
[Computer Architecture] CISC & RISC (49) | 2023.10.08 |
---|---|
[Computer Architecture] 주소 지정 방식 (0) | 2023.10.07 |
[Computer Architecture] 명령어 집합 (2) (0) | 2023.09.23 |
[Computer Architecture] 명령어 집합 (1) (0) | 2023.09.22 |
[Computer Architecture] 명령어 집합 구조 (0) | 2023.09.18 |