32비트 수치와 주소를 위한 MIPS의 주소 지정 방식
MIPS명령어의 길이를 32비트로 고정한 덕에 하드웨어가 간단해지기는 했지만, 명령어 내에 32비트 상수나 32비트 주소를 표시할 수 없어 불편한 점도 있다. 이 절에서는 32비트 상수 처리를 위한 일반적 해법을 제시하고, 이어서 32비트 명령어 주소를 분기나 점프 명령어 내에 표시하기 위한 최적화 방안을 보입니다.
32비트 수치 피연산자
대부분 16비트 필드면 충분하지만 대에 따라서는 더 큰 상수가 필요합니다. 이럴 때를 위해 MIPS는 레지스터의 상위 16비트에 상수를 넣은 lui(load upper immediate)명령어를 제공합니다. 하위 16비트는 그 다음에 나오는 다른 명령으로 채울 수 있습니다.
32비트 상수의 로딩 예
레지스터 $s0에 다음 32비트 상수를 채우는 MIPS어셈블리 코드를 작성하라.
0000 0000 0011 1101 0000 1001 0000 0000
먼저 lui를 이용해서 상위 16비트를 채운다. 상위 16비트의 값은 십진수로 61입니다.
lui $s0, 61 # 61 decimal = 0000 0000 0011 1101 binary
이 명령을 실행한 후 레지스터 $s0의 값은 다음과 같습니다.
0000 0000 0011 1101 0000 0000 0000 0000
다음에는 하위 16비트를 채우면 됩니다. 하위 16비트의 값은 십진수로 2304입니다.
ori $s0, $s0 , 2304
원하는 대로 레지스터 $s0에는 다음 값이 들어갑니다.
분기와 점프 명령에서의 주소지정
MIPS에서 가장 간단한 주소지정 방식은 점프 명령에서 사용하는 것이다. 점프 명령은 6비트의 op코드와 26비트의 주소 필드로 구성되는 J타입 명령어 형식을 사용한다. 그러므로
j 10000 # go to location 10000을 어셈블 하면 다음과 같아진다.
여기서 점프의 op코드는 2이고 분기 주소는 10000입니다.
점프와 달리 조건부 분기 명령에는 분기 주소 외에 2개의 피연산자가 더 있습니다. 그러므로
bne $0, $s1, Exit # go to Exit if $s0 != $s1 은 다음과 같이 어셈블리되어 분기주소로 16비트만 쓸 수 있습니다.
5 | 16 | 17 | Exit |
6bits | 5bits | 5bits | 16bits |
만일 프로그램에서 사용하는 모든 주소가 이 16비트 필드에 들어가야 한다면 어떤 프로그램도 2**16보다 더 커질 수는 없다. 그러나 이것은 현실적으로 너무 작은 크기입니다. 이 문제를 해결할 수 있는 대안은 어떤 레지스터를 지정해서 그 값을 분기주소와 더하도록 하는 것입니다. 이렇게 했을 때 분기 주소는 다음과 같이 구해집니다.
PC = 레지스터 + 분기 주소
이 방식은 프로그램 크기가 2**32까지 커지는 것을 허용하면서 조건부 분기도 지원함으로써 분기 주소의 크기 제한을 극복합니다. 그러면 남은 문제는 어떤 레지스터를 사용하느냐 입니다.
조건부 분기가 어떻게 사요오디는지를 살펴보면 해답을 알 수 있습니다. 조건부 분기는 주로 순환문이나 if문에서 사용되므로 가가이 있는 명령어로 분기하는 경향이 있습니다. 예를 들면 SPEC벤치마크에서 사용된 조건부 분기의 절반가량이 16개 명령어 이상 떨어지지 않은 위치로 분기합니다. PC는 현 명령어의 주소를 가지고 있으므로 분기 주소를 더할 레지스터로 PC를 선택하면 현 위치에서 +-2**15워드 이내 떨어진 곳은 어디든지 분기할 수 있다. 거의 모든 순환문과 if문의 분기 범위가 2**16워드 이내이므로 PC는 이상적인 선택이다.
이런 분기 주소지정 방식을 PC상대 주소지정(PC-relative addressing)방식이라 합니다. 하드웨어 입장에선느 PC를 일찍 증가시켜 다음 명령어를 가리키게 하는 것이 편리합니다. 그러므로 실제MIPS주소는 현재 명령어 주소PC를 기준으로 하는 것이 아니라 다음 명령어 주소 PC+4를 기준으로 하게 됩니다. PC상대 주소지정 방식은 자주 생기는 일을 빠르게라는 원칙의 또다른 예인데 이 경우 자주 생기는 일은 가까이 있는 명령어들의 주소지정입니다.
기계어에서의 분기 변위
전의 예제 while 순환문을 컴파일 하면 다음과 같은 MIPS 어셈블리 코드가 도출됩니다.
Loop : s11 $t1, $s3, 2 # Temp reg $t1 = i * 4
add $t1, $t1, $s6 # $t1 = address of save[i]
lw $t0, 0($t1) # Temp reg $t0 = save[i]
bne $t0, $s5, Exit # go to Exit if save[i] != k
addi $s3, $s3, 1 # i = i + 1
j Loop # go to Loop
Exit:
Loop의 주소가 80000번지라고 할 때 위 프로그램에 해당하는 MIPS기계어 코드는 무엇인가?
어셈블된 명령어와 그 주소는 다음과 같습니다.
MIPS명령어는 바이트 주소를 사용하므로 이웃한 워드의 주소는 4씩 차이가 남습니다. 네 번째 줄의 bne명령은 다음 명령어 주소 80016에 8을 더해서 목적지 주소를 구합니다. 현재 명령어 기준의 상대적 위치(12 + 800012)나 목적지 주소 전체80024가 아니라 다음 명령어를 기준으로 한 상대적 위치(8+80016)로 분기 주소를 나타내기 때문입니다. 마지막 줄의 점프 명령어는 Loop에 해당하는 주소 전체(20000*4=80000)을 사용합니다.
거의 모든 조건부 분기의 목적지는 가까운 곳이지만, 가끔은 16비트로 나타낼 수 없는 먼 곳으로 분기하는 경우도 있습니다. 이런 경우 어셈블러는 큰 주소나 상수를 처리할 때와 같은 방법으로 해결합니다. 분기 목적지로 가는 무조건 점프를 삽입한 후, 분기 조건을 반대로 만들어서 이 점프를 건너뛸 것인지 말 것 인지를 결정하게 됩니다.
아주 먼 거리로의 분기 예
레지스터 $s0가 레지스터 $s1과 같으면 분기하는 코드
beq $s0, $s1, L1
을 L1이 아주 멀어도 분기가 가능하도록 바꾸되 명령어 2개를 사용하라
다음과 같이 바꿀 수 있습니다.
bne $s0, $s1, L2
j L1
L2 :
MIPS주소지정 방식 요약
여러 형태의 주소 표현을 일반적으로 주소지정 방식(addressing mode)라 합니다. 다음 그림을 보면 각각의 주소지정 방식이 피연산자를 어떻게 찾아내는지 알 수 있습니다. MIPS에서 사용되는 주소지정 방식은 다음과 같습니다.
1. 수치(immediate)주소지정 : 피연산자는 명령어 내에 있는 상수이다.
2. 레지스터 주소지정 : 피연산자는 레지스터이다.
3. 베이스(base) 또는 변위(displacement)주소지정 : 메모리 내용이 피연산자이다. 메모리 주소는 레지스터와 명령어 내의 상수를 더해서 구한다.
4. PC 상대 주소지정 : PC값과 명령어 내 상수의 합을 더해서 주소를 구합니다.
5. 의사직접(pseudodirect)주소지정 : 명령어 내의 26비트를 PC의 상위 비트들과 연접하여 점프 주소를 구한다.
'Computer Architecture > 컴퓨터 구조' 카테고리의 다른 글
[15] CH2 명령어:컴퓨터 언어 < ARMv7 > (0) | 2022.01.19 |
---|---|
[14] CH2 명령어:컴퓨터 언어 < MIPS 버전 6 > (0) | 2022.01.19 |
[12] CH2 명령어:컴퓨터 언어 < Arm 버전 2 > (0) | 2022.01.19 |
[11] CH2 명령어:컴퓨터 언어 < MIPS 버전 4 > (0) | 2022.01.19 |
[10] CH2 명령어:컴퓨터 언어 < MIPS 버전 3 > (0) | 2022.01.19 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!