논리 연산 명령어
초기의 컴퓨터는 워드 전체에 대한 처리에만 관심을 가졌으나, 워드 내 일부 비트들에 대한 연산, 각각의 비트에 대한 연산도 필요하다는 것이 명백해졌습니다. 비트들을 워드로 묶는 패키징 작업과 워드를 비트 단위로 나누는 언패키징 작업을 간단하게 하는 명령어들이 프로그래밍 언어와 명령어집합에 추가되었습니다. 이러한 논리 연산 명령어라 지칭합니다. 이번시간에는 MIPS의 논리 연산을 보여줍니다.
1. shift 연산
워드 내의 모든 비트를 왼쪽 또는 오른쪽으로 이동시키고, 이동 후 빈 자리는 0으로 채웁니다. MIPS 자리이동 명령어의 실제 이름은 s11(shift left logical)과 sr1(shift right logical)입니다. 다음은 위의 연산을 수행하는 MIPS명령어이고 단 원래 값은 $s0에 있고 결과는 $t2레지스텅에 저장된다고 가정합시다.
s11 $t2, $s0, 4 # reg $t2 = reg $s0 << bits
이제 R형식 명령어의 shamt필드에 대해 말해 봅시다. 이것은 자리이동(shift amount)을 나타내는 것으로 자리이동 명령어에서 사용됩니다. 따라서 위 명령어의 기계식 형식은 다음과 같습니다.
op | rs | rt | rd | shamt | funct |
0 | 0 | 16 | 10 | 4 | 0 |
2. AND, OR, NOT
판단을 위한 명령어
컴퓨터가 단순한 계산기와 다른점은 판단기능이 있다는 것입니다. 입력 데이터나 연산 결과에 따라 다른 명령어를 실행할 수 있습니다. 처음 볼 명령어는 다음과 같습니다.
beg register1, register2, L1
인데 register1과 register2의 값이 같으면 L1에 해당하는 문장으로 가라는 뜻입니다. beg는 branch if equal 의미
bne register1, register2, L1
으로 register1, register2의 값이 같지 않으면 L1으로 가라는 뜻입니다. bne는 branch if not equal 의미하고 beq와 bne 두 명령어는 조건부 분기(conditional branch)라 부릅니다.
if then else를 조건부 분기로 번역 예
다음 코드에서 f,g,h,i,j는 변수이고, 각각 레지스터 $s0부터$s4까지에 해당한다. 아래의 C언어 if문장을 컴파일한 코드는?
if( i == j) f = g + h; else f = g - h;
그림을 살펴보면 첫번재 부분은 beq로 변역하면 될 것처럼 보인다. 그러나 실제로는 조건을 반대로 검사해서 then부분을 건너뛰게 하는 것이 더 효율적이므로 bne을 사용합시다.
bne $s3, $s4, Else # go to Else if i != j
다음 치환문은 연산 하나를 실행하는 것이므로 피연산자가 모두 레지스터에 있다면 명령어 하나로 번역된다.
add $s0, $s1, $s2 # f = g + h ( skipped if i!=j )
이 명령을 실행한 후에는 if문장 끝으로 가야된다. 이것은 무조건 분기(unconditional branch)라는 새로운 종류의 분기 명령으로 해결한다. MIPS에서는 이 같은 명령어에 jump라는 이름을 붙이고 간략하게 j로 사용한다.
j Exit # go to Exit
else 부분의 치환문도 역시 명령어 하나로 번역된다. 단 이 명령어에는 Else라는 레이블을 붙여야 한다. 그리고 이 명령어 뒤에는 if then else문장의 끝을 표시하는 Exit란 레이블을 둔다.
Else: sub $s0, $s1, $s2 # f = g - h (skipped if i = j)
Exit:
컴파일러가 소스 프로그램에는 없는 분기 명령이나 레이블을 만들어 내는 경우가 많이 있습니다. 필요한 레이블과 분기 명령을 일일이 표시하지 않아도 되는 것이 상위 수준 프로그래밍 언어의 장점 중 하나이며, 상위 수준 언어를 사용하면 코딩이 더 빨라지는 이유이기도 합니다.
순환문
판단 기능은 둘 중의 하나를 선택하는 데도 중요하지만 계산의 반복에도 중요합니다. 두 경우에 모두 같은 어셈블리 명령어가 사용됩니다.
while 순환문의 번역 예
아래에 전형적인 C순환문이 있습니다.
while (save[i] == k) i += 1;
i와 k가 레지스터 $s3와 $s5에 할당되었고 배열 save의 시작 주소가 $s6에 저장되어 있다고 할 때 C문장에 해당하는 MIPS 어셈블리 코드를 보여라.
첫번째로 할 일은 save[i]를 임시 레지스터로 가져오는 것이다. save[i]를 임시 레지스터에 적재하려면 먼저 그 주소를 알아야된다. 바이트 주소를 사용하므로 인덱스 i에 4를 곱해서 save의 시작 주소에 더해야 주소가 만들어진다. 2비트씩 왼쪽 자리이동을 하면 4를 곱한 것과 같으므로 s11연산을 사용할 수 있습니다. 순환의 끝에서 처음 명령어로 되돌아갈 수 있도록 L:oop라는 레이블을 추가합시다.
Loop : s11 $t1, $s3, 2 # Temp reg $t1 = i * 4
save[i]의 주소를 계산하기 위해서 $t1 값에다 $s6에 있는 save의 시작 주소값을 더합니다.
add $t1, $t1, $s6 # $t1 = address of save[i]
이제 이 주소를 이용해서 save[i]를 임시 레지스터에 넣을 수 있다.
lw $t0, 0($t1) # Temp reg $t0 = save[i]
다음은 반복 검사를 수행해서 save[i] != k이면 순환에서 빠져나가는 부분이다.
bne $t0, $s5, Exit # go to Exit if save[i] != k
다음은 i에 1을 더하는 명령어이다.
addi $s3, $s3, 1 # i = i + 1
순환문의 끝에서는 맨 앞의 while조건으로 되돌아가야 한다. 그리고 이 명령의 다음에 Exit레이블을 두면 번역이 끝난다.
j Loop # go to Loop
Exit:
같은지 다른지 비교하는 것이 가장 흔한 검사이겠지만, 경우에 따라서는 두 변수 간의 대소 비교가 필요할 때도 존재합니다. MIPS에서는 slt(set on less than)명령어로 이런 일을 처리합니다. slt는 두 레지스터값을 비교한 후, 첫번째 레지스터 값이 두 번째 레지스터의 값보다 작으면 세 번째 레지스터 값을 1, 아니면 0으로 하는 명령어 입니다.
slt $t0, $s3, $s4 #$t0 = 1 if $s3 < $s4
상수 피연산자는 비교에서도 많이 이용된다. 따라서 상수 피연산자를 갖는 slt명령어가 필요합니다. 레지스터 $s2가 상수 10보다 작은지 검사하려면 다음과 같이 쓰면 됩니다.
slti $t0, $s2, 10 # $t0 = 1 if $s2 < 10
MIPS컴파일러는 slt, slti, beq, bne와 레지스터 $zero에 있는 상수 0을 이용해서 모든 비교조건(같다 다르다 작다 작거나 같다 크다 크거나 같다)을 만들 수 있습니다.(레지스터 $zero는 0번 레지스터를 지칭합니다.)
Case / Switch 문장.
switch를 구현하는 가장 간단한 방법은 연속적인 조건 검사를 통해 switch를 일련의 if the else문장으로 바꾸는 것입니다. 그러나 여러 코드의 시작 주소를 표로 만들면 더 효율적으로 구현할 수 있습니다. 이 때 프로그램은 점프 주소 테이블(jump address table)의 인덱스만 계산해서 해당 루틴으로 점프할 수 있습니다. 점프 테이블은 프로그램상의 레이블에 해당하는 주소를 저장하고 있는 배열입니다. 프로그램은 점프 테이블에서 적당한 주소를 레지스터에 적재한 후 이 주소를 사용하여 점프합니다. 이런 작업을 위해 MIPS는 jr(jump register)이라는 명령어를 제공합니다. 이 명령어는 레지스터에 저장된 주소로 무조건 접프합니다.
'Computer Architecture > 컴퓨터 구조' 카테고리의 다른 글
[12] CH2 명령어:컴퓨터 언어 < Arm 버전 2 > (0) | 2022.01.19 |
---|---|
[11] CH2 명령어:컴퓨터 언어 < MIPS 버전 4 > (0) | 2022.01.19 |
[9] CH2 명령어:컴퓨터 언어 < MIPS 버전 2 > (0) | 2022.01.16 |
[8] CH2 명령어:컴퓨터 언어 < MIPS 버전 > (0) | 2022.01.16 |
[9] CH2 명령어:컴퓨터 언어 < Arm 버전 > (0) | 2022.01.13 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!