minhui study

week4 - 명령어 분류와 형식 본문

컴퓨터 구조/Swing study

week4 - 명령어 분류와 형식

minhui 2020. 5. 26. 16:01

 

1. 분기 명령어 

분기명령어란?

실행의 흐름을 변경하거나 어떤 루틴을 호출하는 데 사용하는 것

 

□ 분기의 형태

 

BRZ(branch if zero) 211

조건 코드가 0이면 211로 분기하라는 명령어

 

BR 202 : 무조건 202번지로 분기하라는 명령어

 

BRE(branch if equal) R1, R2, 235 :

레지스터 R1과 레지스터 R2의 내용이 같다면 235번지로 분기하라는 명령어

 

 

2. 서브루틴의 호출과 복귀과정

 

위의 그림과 같이 main에서 CALL SUB1명령어를 읽으면 서브루틴 SUB1을 수행하게 된다.

SUB1수행 중 CALL SUB2명령어를 만나게 되면 서브루틴 SUB2를 수행하게 되고 SUB2에서 RET명령어를 읽으면 다시 SUB1으로 돌아오게 되는데 이때 CALL SUB2의 명령어가 있는 260이 아닌 CALL SUB2의 다음 주소인 261로 복귀하게 된다.

두 번의 CALL SUB2명령어를 다 수행하고 SUB1의 수행을 다 마치면서 RET명령어를 읽게 되면 다시 main 프로그램으로 복귀하게 되는 데 이때 역시 CALL SUB1의 다음 주소인 211로 복귀한다. 

그리고 이 때 중요한 건 CALL, RET 명령어들이 실행될 때에는 스택이 사용됨에 따라 스택이 변화한다.

여기서 SP는 스택 포인터이다. 그럼 스택이란 무엇일까? 스택에 대해서 알아보자

 

 

스택(Stack)이란?

FILO(First In Last Out)형태로 데이터를 액세스하는 데이터 구조이다. 즉, 가장 나중에 들어온 것부터 차례로 액세스하는 것이다.

Heap은 Stack과 반대로 FIFO(First In First Out)형태로 데이터를 액세스한다. 

스택은 한 곳으로만 액세스할 수 있으며, 이부분을 스택의 탑(top)이라고 한다. 

 

https://hyem2.tistory.com/entry/%EC%8A%A4%ED%83%9D%ED%8F%AC%EC%9D%B8%ED%84%B0

 

스택포인터(SP)란?

 

중앙처리 장치 안에는 스택에 데이터가 채워진 위치를 가리키는 레지스터인 스택 포인터(SP)를 갖고 있다. 스택포인터가 가리키는 곳까지가 데이터가 채워진 영역이고, 그 이후부터 스택 끝까지는 비어있는 영역이다. 

스택에 새로운 항목이 추가되거나 스택에서 데이터가 제거되면, 스택 포인터의 값이 증가하거나 감소한다. 

 

https://hyem2.tistory.com/entry/%EC%8A%A4%ED%83%9D%ED%8F%AC%EC%9D%B8%ED%84%B0



 

그럼 이제 서브 루틴에 따른 스텍의 변화를 살펴보자

 

SUB 1이 호출된 후에는 스텍에 복귀할 주소 211를 저장해 놓는다. 그리고 또 SUB 2가 호출되면 그 위로 SUB2가 종료되고 복귀할 주소인 261이 저장된다. 그리고 SUB 2가 종료되어 복귀하면 복귀 주소가 저장되어 있던 주소가 사라진다.

이런 과정을 반복하다가 SUB1까지 다 복귀하면 스택에는 아무것도 남아있지 않게 된다.

 

 

 

3. 명령어 분류

□ 오퍼랜드에 저장되는 데이터 형태

 

  - 주소 : 주기억장치의 주소나 레지스터의 주소

  - 수 : 정수, 고정-소수점 수, 부동-소수점 수

  - 문자 : ASCII 코드

  - 논리 데이터 : bit 혹은 flag

 

 

□ 오퍼랜드가 주소를 나타내는 경우

   : 오퍼랜드 수에 따라 3,2,1,0 주소 방식 존재

 

 

 

 

0주소 명령어(0-address instruction)

   : 연산 코드만 있고 주소를 지정하는 자료부(Operand 부)가 없는 명령어

 

   - 모든 연산은 Stack 메모리의 TOP(Stack 포인터)가 가리키는 Operand를 이용하여 명령을 수행하고, Stack Machine이라고 부른다.

   - 명령 수행 시간이 짧고 기억 공간 효율이 높다.
   - Postfix 방식으로 수식을 표현해야 합니다.
   - 피연산자는 PUSH, 연산자를 만나면 연산에 사용할 피연산자를 POP한 후에 연산 결과를 PUSH합니다.

 

   * Postfix 방식이란?

     연산자를 피연산자의 뒷쪽에 표시하는 방법이다.

     변형 방법은 괄호로 묶어서 괄호를 하나씩 지우면서 연산자를 뒤로 빼내면 된다.

      ex)    (a + b) * c / d + e

           = (((a + b) * c) / d) e +

           = ((a + b) * c ) d / e +

           = (a + b) c * d / e +

           = a b + c * d / e +

 

 

 

1주소 명령어(1-address instruction)

  : 오퍼랜드 한 개만 포함하는 명령어로서, 오퍼랜드 형태는 주소이다.

  - 주소를 지정하는 Operand가 1개가 있고 누산기(AC, Accumulator)를 이용하여 처리하며 수행 결과도 누산기에 저장한다.

  - 1-주소 명령어 형식의 예

  - 어셈블리 언어로 1-주소 명령어를 표현한 예

 

      LOAD X            ;AC ←  M[X] (X번지의 데이터를 누산기에 저장)

     (LOAD는 연산 코드, X는 기억장치 주소)

 

 

 

2주소 명령어(2-address instruction)

   : 오퍼랜드 2개를 포함하는 명령어 형식으로 오퍼랜드 2개 모두 주소를 저장하는데 사용된다.

 

   - 가장 일반적인 명령어 방식이고, 실행 속도가 빠르다.
   - 수행 결과를 기억장치에 저장하고 중앙처리장치에도 남아 있어서 결과를 테스트할 때 시간을 절약할 수 있습니다.
   - 전체 프로그램 길이가 길어지는 단점이 있다.


   - 2-주소 명령어 형식의 예

         * 명령어의 총 길이 : 16비트 (연산코드 : 5비트)

  - 어셈블리 언어로 2-주소 명령어를 표현한 예

 

       MOV  X, Y             ; M[X] ← M[Y]

       ( X, Y의 두 개의 변수가 주소 / Y번지의 기억장치 데이터를 X번지의 기억장치로 이동시킨다. )

 

 

 

3주소 명령어(3-address instruction)

   : 오퍼랜드 3개가 존재하며, 레지스터의 주소를 저장하는 명령어 형식이다.

   - 프로그램 길이를 짧게 할 수 있다.

   - 명령 인출에 필요한 주기억장치 접근 횟수가 적다.

   - 3-주소 명령어 형식의 예

         * 명령어의 총 길이 : 16비트 (연산코드 : 4비트, 레지스터 : 4비트)

   - 어셈블리 언어로 3-주소 명령어를 표현한 예

 

          ADD  X, Y, Z               ; M[X] ← M[Y] + M[Z]

       ( X, Y, Z가 주소를 나타낸다. / Y와 Z번지의 데이터를 덧셈해서 X번지에 저장한다. )

 

 

4. 명령어 형식 비교

▷ 4가지 주소 형식으로 다음의 수식 연산 프로그램을 구현 후 비교해보자

 

                   X = B * (C + D * E - F / G)

▷ 수식 연산 프로그램에서 사용되는 어셈블리 명령어

 

< 0주소 명령어를 사용한 프로그램 >

 

 

※ 스택에서 0-주소 명령어 프로그램의 동작

 

 

 

<1주소 명령어를 사용한 프로그램>

 - M[A] : 기억장치 A번지에 저장된 데이터 내용

 - T : 기억장치 내의 임시 저장장소의 주소

 

ex) LOAD F  -> 기억장치 F번지에 저장된 데이터 내용을 누산기로 전송한다.

      DIV G ->기억장치 G번지에 저장된 데이터러 누산기 값을 나누어 누산기로 전송한다.

      STOS T -> 누산기의 값을 기억장치 내의 임시 저장장소로 전송한다. 

 

 

 

<2주소 명령어를 사용한 프로그램>

 - M[A] : 기억장치 A번지에 저장된 데이터 내용

 - R1, R2 : CPU 내의 위치한 레지스터

ex) MOV R1, D -> 기억장치 D번지에 저장된 데이터 내용을 R1레지스터에 넣는다.

      MUL R1, E -> 기억장치 E번지에 저장된 데이터에 R1레지스터에 있는 값을 곱한 후 R1 레지스터에 넣는다.

     

- 연산의 결과는 주로 Operand1에 저장되므로 Operand1에 있던 원래의 자료가 파괴된다.

 

 

<3주소 명령어를 사용한 프로그램>

 - 세 개의 오퍼랜드 모두 주소를 나타낸다.

 - R1, R2 : CPU 내의 위치한 레지스터

ex) MUL D, E, R1 -> 기억장치 D번지에 저장된 데이터와 E번지에 저장된 데이터를 곱하여 R1 레지스터에 저장한다. 

      ADD C, R1, R1 -> 기억장치 C번지에 저장된 데이터와 R1레지스터에 있는 값을 더한 후 R1 레지스터에 저장한다. 

 

- 3주소 명령은 데이터 10, 20(A, B)을 더하여 결과값을 C 기억장소에 기억시키기 때문에 자료 10,20은 그대로 유지된다. 즉, 연산 시 원래의 자료를 파괴하지 않는다. 

- 다른 형식의 명령어를 이용하는 것보다 프로그램 전체의 길이를 짧게 할 수 있다. 

- 또한 한 개의 명령어로 여러 명령을 수행하므로 전체 명령어를 읽어오는 시간을 단축되지만 기억 장소 접근 횟수 때문에 전체적인 수행시간 면에서는 수행시간이 길어지는 단점이 있다.

 

 

 

※ 명령어 주소 개수에 따른 장단점

▷ 주소 개수가 많은 경우

    - 저장할 오퍼랜드의 수가 많아지기 때문에 명령어가 더 복잡해진다.

    - 레지스터 수가 많아져서 연산 속도가 빨라진다.

    - 프로그램이 짧아져서 프로그램 당 명령어 수 가 감소한다.

 

▷ 주소 개수가 적은 경우

    - 오퍼랜드의 수가 적어서 간단하므로 명령어 인풀과 실행 속도가 높아진다.

    - 프로그램의 길이가 증가한다.


< 출처 >

강의노트, 디지털논리와 컴퓨터 설계, Harris et al. (조영완 외 번역), 사이텍미디어, 2007, 컴퓨터 구조와 원리 (비주얼 컴퓨터 아키텍처), 신종홍 저, 한빛미디어, 2011

 

 

문제▼

더보기

1. 다음 중 무조건 분기해야하는 것을 고르시오

① BRZ 210

② BR 202 

③ BRE R1, R2, 230

 

 

 

2. 다음 그림에서 280번지에 있는 CALL SUB2가 실행되어 SUB2가 호출된다면  스택에는 복귀를 위한 주소가 저장되는데 이때 저장되는 주소는?

 

 

3. 다음 설명 중 틀린 것을 고르시오

 

① 0주소 명령어는 연산 코드만 있고 주소를 지정하는 자료부(Operand 부)가 없는 명령어이다.

② 0주소 명령어는 누산기를 이용하여 연산을 수행한다.

③ 2주소 명령어의 총 길이는 16비트로 그 중 연산코드는 5비트이다.

④ 3주소 명령어는 프로그램 길이를 짧게 할 수 있다.

 

 

 

4. 기억장치 C번지에 저장된 데이터와 E번지에 저장된 데이터을 더한 후 R1레지스터에 저장하는 명령어를 고르시오

 

① ADD C, E, R1

② ADD R1, E, C

③ ADD R1, C, E

ADD C, R1, E

 

 

 

5. 다음은 0-주소 명령어 방식으로 이루어진 프로그램이다. 레지스터 X의 내용은? (단, 레지스터 A=1, B=2, C=3, D=3, E=2 이며, ADD는 덧셈, MUL은 곱셈을 의미한다.)

PUSH A
PUSH B
PUSH C
ADD
PUSH D
PUSH E
ADD
MUL
POP X

① 15  ② 20  ③ 25 ④ 30

 

 

 

답안▼

더보기

1.

BRZ(branch if zero) 210 :  조건 코드가 0이면 210로 분기하라는 명령어
BR 202 : 무조건 202번지로 분기하라는 명령어
BRE(branch if equal) R1, R2, 230 : 레지스터 R1과 레지스터 R2의 내용이 같다면 230번지로 분기하라는 명령어

위의 설명처럼 1번은 조건 코드가 0이면 분기하고 3번은 R1과 R2가 같다면 분기하는 것이다. 하지만 2번은 조건없이 무조건 분기해야 한다.

 

 

2. 281

 280번지에 있는 CALL SUB2가 실행되어 SUB2가 호출된다면 스택은 왼쪽 그림과 같은 모습이 된다. 

스택은 FIFO구조로 맨 위에 있는 것이 가장 최근에 넣어진 값이라고 할 수 있으므로 SUB2가 호출된 후 281이 저장되어 있는 것을 알 수 있다.

이는 CALL SUB2명령어 다음 주소로 복귀를 할때 280번지가 아닌 바로 다음 주소로 복귀한다는 것을 의미한다. 

 

 

 

 

 

3.

0주소 명령어에서의 모든 연산은 Stack 메모리의 TOP(Stack 포인터)가 가리키는 Operand를 이용하여 명령을 수행한다. 누산기를 이용하여 연산을 처리하는 것은 1주소 명령어로 1주소 명령어는 주소를 지정하는 Operand가 1개가 있고 누산기(AC, Accumulator)를 이용하여 처리하며 수행 결과도 누산기에 저장한다.

 

 

4.

 ADD C, E, R1 -> 기억장치 C번지에 저장된 데이터와 E번지에 저장된 데이터을 더한 후 R1레지스터에 저장

 ADD R1, E, C -> 레지스터 R1에 있는 값과 E번지에 저장된 데이터을 더한 후 기억장소 C에 저장

 ADD R1, C, E -> 레지스터 R1에 있는 값과 C번지에 저장된 데이터을 더한 후 기억장소 E에 저장

 ADD C, R1, E -> C번지에 저장된 데이터와 레지스터 R1에 있는 값을 더한 후 기억장소 E에 저장

 

 

5.

1단계 : a = 1, 연산자가 없는 상태라 바닥에 깔린다.

2단계 : 첫 번째 add 연산자를 만나면, c, b를 출력해 연산한다. 3 + 2 = 5

3단계 : 두 번째 add 연산자를 만나면, e, d를 출력해 연산한다. 2 + 3 = 5

4단계 : mul 연산자를 만나면, 첫 번째 add 값과, 두 번째 add 값을 연산한다. 5 * 5 =25

5단계 : pop을 만나면 스택에 1과 25가 남아 있는 상태가 되어 top가 25이므로 25가 출력된다. 1과 25는 다음 연산자가 들어오길 기다리는 상태가 된다.

※ 변수, 변수, 연산자 형태의 후위식을 연산한다는 것에 주의를 하자

 

 

 

Comments