안녕하세요. WH 입니다.
이번 글에서는 32비트 상수를 지원하는 방법과 분기 명령어나
점프 명령서에서 사용되는 명령어 주소의 최적화에 대허서 알아볼게요.
아니 그걸 왜 알아야 되요? 편한 경우가 많으니까요!
불편함 속에서 편함을 찾아보자구요
32비트 수치 피연사자
프로그램에서 사용되는 상수는 대체로 작죠. 뭐 쓰는 숫자는 대게 2^16승 정도면 대략 표현이 될거에요. 그런데 그보다 큰 수를 쓸 때는 상위 16비트에 lui( load upper immediate ) 명령어에 ori ( 논리 연산자 )를 사용하면 쉽게 만들수 있답니다. 논리 연산자에 대해 기억이 나지 않는다면 아래 글을 참조해 주세요.
2022.02.07 - [컴퓨터 구조론( MIPS )] - 명령어 : 컴퓨터 언어 3
예시> $s0 에 0000 0000 0011 1101 0000 1001 0000 0000 32 비트 상수를 채우는 코드는?
1. 먼저 lui로 상위 16비트를 채웁니다. ( 위에서 16 비트를 가져오면 0000 0000 0011 1101 = 3*2^4 + 15 = 61 ) 여러분 61을 계산한 과정을 잘봐주세요. 3*2^4 바로 이 방식에 익숙해 지시길 바랍니다. 쉬프팅 연산자를 활용하는 법이거든요!
lui $s0, 61
( 명령어 실행시 0000 0000 0011 1101 0000 0000 0000 0000 ) 가 됩니다.
2. 하위 16비트는 0000 1001 0000 0000 이죠? 이는 1001 = 9 이고 뒤에 0이 8개 있으므로 9*2^8 = 2034 가 됩니다.
1이 있는 것들만 가져오면 되겠네요?
ori $s0, $s0, 2034
여기까지가 상수를 32비트 상수를 만드는 방법이었는데요. 쉽죠? 앞의 내용만 인지하고 있다면야 매우 쉬운 내용입니다. 알고가셔야 할 사실은 lui는 상위 16비트를 지정한 숫자로 채우고 하위 16 비트는 0 으로 채운다는 겁니다. 그런데 여기서 생각을 하나 해봅시다. 우리가 만든 상수는 32비트 입니다. 그런데, 이런 32 비트의 상수는 크기 때문에 또 문제가 됩니다. 뭐가 문제냐구요? 우리는 명령어를 총 32 비트에 나눠서 놓거든요. op rs rt rd shamt fuct 필드와 같이 말이죠? 그럼 이 상수를 한번에 못담잖아요? 그래서 MIPS 에서는 큰 숫자를 몇 조각으로 나눈 다음 재조립하여 다시 합친답니다. 이 조각들을 보관할 임시 레지스터가 있어야겠죠? $at 이 이용도로 사용된답니다. 필드에 관란 내용이 기억나지 않는다면 아래 글을 참조해 주세요.
2022.02.07 - [컴퓨터 구조론( MIPS )] - 명령어 : 컴퓨터 언어 2
분기와 점프 명령에서 분기 지정
가장 간단한 주소 지정 방식은 바로 점프 명령에서 사용하는 거랍니다. 점프 명령은 6비트의 op 필드와 26 비트의 주소 필드로 구성되는 J 타입 명령어 형식을 사용( 명령어로는 j 등이 있죠 )합니다.
가장 먼저 조건부 분기 명령은 op 필드 6 비트, rs 5 비트, rt 5 비트, target address 16 비트로 구성됩니다. ( 명령어로는 bne , beq 등이 있구요 ) 그런데 2^16은 현실적으로 너무 작은 크기랍니다. 그래서 어떤 레지스터를 지정해서 그 값을 분기 주소와 더해서 이 문제를 해결합니다.
즉, PC( program counter ) = 레지스터 + 분기 주소 이렇게 말이죠. 이렇게 하면 프로그램 크기가 2^32까지 커지는 것을 허용하면서 조건부 분기도 지원하기 때문에 분기 주소의 크기 제한을 극복할 수 있습니다. 그럼 어떤 레지스터를 사용할까요? PC( program counter )는 현 명령어의 주소를 가지고 있고 분기 주소를 더할 레지스터로 PC를 선택하면 2^16 워드 이내 떨어진 곳은 어디든지 분기가 할 수 있답니다. 그런데 보통 순환문이나 if문에서 분기는 2^16 워드 이내이므로 PC를 선택하는 것이 좋겠지요. 이런 분기 주소지정 방식을 PC 상대 주소 지정 방식이라고 해요. 뭐 차차 설명드리겠지만 MIPS 주소는 현재 명령어 주소 PC 가 아닌 PC + 4을 기준으로 하는데 이는 자주 생기는 일을 빠르게 처리하기 위함이에요.
참고 PC : 현재 실행 중인 명령어의 주소를 기억하는 레지스터
이번에는 프로시저들을 볼까요? 조건문과 순환문에서는 PC를 선택했어요. 그런데 프로시저들은 붙어 있을 필요가 있나요? 때문에 프로시저에서 사용되는 jal 명령은 다른 주소지정 방식을 사용한답니다. 물론 jal 명령 역시 J 타입을 사용합니다. 어떤 방식을 사용하냐, PC 상대 주소지정 방식은 MIPS가 4바이트 임으로 분기할 거리를 바이트 수로 나타내잖아요? 바이트 주소 대신 워드 주소를 사용한다면 똑같은 4라도 4*4 = 16 즉 4배의 거리를 점프할 수 있게 되겠죠.
예시를 통해 보겠습니다.
예시 1>
순환문을 하나 컴파일 했다고 합시다. 아래와 같이 나왔어요. LOOP의 주소가 80000번이라 가정해봅시다. 기계어 코드는 어떻게 될까요?
LOOP : sll $t1, $s3, 2
add $t1, t1, $s6
lw t0, 0($t1)
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit:
80000 0 0 19 9 2 0
80004 0 9 22 9 0 32
80008 35 9 8 0
80012 5 8 21 2
80016 8 19 19 1
80020 2 20000
80024
이 기계어 코드를 알아보라는 게 아닙니다. 여러분이 기억하셔야 할 첫 번째 일은, 워드의 주소는 4씩 차이가 난다는 사실입니다. 그리고 LOOP 2000*4 를 사용하여 돌아간다는 점, bne 의 목적지 주소는 현재 주소가 아닌 다음 주소 + 목적지 주소( 80016 + 8 = 80024 )를 통해 목적지 주소를 구한다는 점을 기억하시면 됩니다.
예시 2>
아주 먼거리로 분기를 표시하기 위한 방법
두 레지스터가 같으면 분기하는 코드
beq $s0, $s1, L1
먼 거리 분기가 가능하도록 바꾼다면
bne $s0, $s1, L2
j L1
L2:
로 바꿀 수 있습니다. beq는 16비트 j는 주소 필드가 26비트를 사용함으로 더 먼 곳 까지 분기가 가능하겠죠
참고 기계어 필드 값
이번 글도 짧지는 않았네요 뭔가 머리 아픈 내용이 나오나요?? 사실 오랜만에 보는 저도 그럽니다
언제 봐도 머리를 써야하는 부분이 슬슬 다가오네요. 이번 글은 여기까지 입니다.
그럼 다음에 뵈요. 이상 WH였습니다.
'컴퓨터 구조론( MIPS )' 카테고리의 다른 글
명령어 : 컴퓨터 언어 8 ( feat. MIPS 어셈블리 코드 예시 ) (0) | 2022.02.09 |
---|---|
명령어 : 컴퓨터 언어 7 ( feat. 동기화, 번역, 실행) (0) | 2022.02.08 |
명령어 : 컴퓨터 언어 5 (0) | 2022.02.07 |
명령어 : 컴퓨터 언어 4 (0) | 2022.02.07 |
명령어 : 컴퓨터 언어 3 (0) | 2022.02.07 |