본문 바로가기

컴퓨터 구조론( MIPS )

명령어 : 컴퓨터 언어 6 ( feat. 주소 지정 및 방식 )

728x90
반응형
반응형

안녕하세요. WH 입니다.

이번 글에서는 32비트 상수를 지원하는 방법과 분기 명령어나

점프 명령서에서 사용되는 명령어 주소의 최적화에 대허서 알아볼게요.

아니 그걸 왜 알아야 되요? 편한 경우가 많으니까요!

불편함 속에서 편함을 찾아보자구요

 

32비트 수치 피연사자

프로그램에서 사용되는 상수는 대체로 작죠. 뭐 쓰는 숫자는 대게 2^16승 정도면 대략 표현이 될거에요. 그런데 그보다 큰 수를 쓸 때는 상위 16비트에 lui( load upper immediate ) 명령어에 ori ( 논리 연산자 )를 사용하면 쉽게 만들수 있답니다. 논리 연산자에 대해 기억이 나지 않는다면 아래 글을 참조해 주세요.

2022.02.07 - [컴퓨터 구조론( MIPS )] - 명령어 : 컴퓨터 언어 3

 

명령어 : 컴퓨터 언어 3

안녕하세요. WH 입니다. 지난 번 글까지해서 산술 연산자에 대한 내용까지 알아보았는데요, 내용이 기억나지 않으시면 아래 글을 참조하시길 바랍니다. 2022.02.07 - [컴퓨터 구조론( MIPS )] - 명령어

developer-wh.tistory.com

 

예시> $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

 

명령어 : 컴퓨터 언어 2

안녕하세요. WH 입니다. 지난 글에 이어서 다시 정리해보도록 할게요 지난 글 내용이 기억나지 않으신다면, 아래 내용을 참조해주세요 2022.02.07 - [컴퓨터 구조론( MIPS )] - 명령어 : 컴퓨터 언어 1

developer-wh.tistory.com

 

분기와 점프 명령에서 분기 지정

  가장 간단한 주소 지정 방식은 바로 점프 명령에서 사용하는 거랍니다. 점프 명령은 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였습니다.

728x90
반응형