Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

번역 : 강웅빈 감수 : 프갤ㅤ횽들

15 메모리 접근(Memory Access) 명령

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_1.html 이 장에서는 데이터를 메모리로부터 레지스터로 또는 레지스터로부터 메모리로 복사하는 방법을 공부한다.

주제:

  • 로드와 스토어 (Load and store)
  • 데이터 정렬 (Data alignment)
  • 바이트의 순서, 리들 엔디언과 빅엔디언 Byte order (little endian and big endian).
  • lw와 sw 명령 (The lw and sw instructions)
  • 로드를 연기하는 슬롯 (The load delay slot)
  • 베이스 레지스터와 어드레스를 계산하는법 (Base registers and address calculation)
  • lui명령
  • 기호주소 또는 심볼릭 어드레스(Symbolic addresses)
질문: (복습) 주메모리로부터 레지스터로 데이터를 복사하는 동작은 무엇입니까?

로드와 스토어(Load and store)

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_2.html

답: 레지스터는 주 메모리로 부터 로드(load)됩니다

산술/논리 연산을 위한 피연산자들은 레지스터 안에 있어야만 한다. 주 메모리에 있는 데이터를 사용하려면 데이터가 레지스터로 먼저 복사되어야 한다. 로드(load)는 주 메모리로부터 데이터를 복사해온다. 스토어(store)는 레지스터의 데이터를 주 메모리로 복사한다.

워드(word-4바이트)가 로드되거나 스토어 될 때에 주 메모리의 주소는 항상 4의 배수여야 한다. 이 규칙을 정렬 제한-an alignment restriction-이라고 한다. 4의 배수의 주소들을 워드 정렬-word aligned-되었다고 한다. 이 제한은 하드웨어를 좀 더 간단하고 빠르게 만들어 준다.

lw명령은 주 메모리로부터 워드를 불러와 레지스터에 저장시킨다. sw명령은 워드를 주 메모리로 저장시킨다. 각각의 명령은 레지스터와 메모리 주소를 지정합니다.(따르는 장에서 이것에 대해 다룰 것이다).

질문: 다음중 어떤 주소들이 워드 정렬 되었습니까?
* 0x000AE430 
* 0x00014432 
* 0x000B0737 
* 0x0E0D8844 }}}
힌트: 이진수에서 어떻게 4를 곱합니까?

=== 빅 엔디언(Big Endian)과 리들 엔디언(Little Endian) ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_3.html

답: 4의 배수인 정수는 4*N의 꼴로 표현이 가능합니다

2진수에서 4를 곱하는 방법은? 왼쪽으로 2자리만큼 쉬프트하면 됩니다. 그러므로 4의 배수는 N이 왼쪽으로 두번 쉬프트 된 결과이고, 하위 2비트가 0이 되어야합니다.


* 0x000AE430   예. 
* 0x00014432   아니오. 
* 0x000B0737   아니오. 
* 0x0E0D8844   예. }}}

워드를 로드하거나 스토어하는 명령은 메모리의 주소 한개만 지정한다. 4개의 연속된 블록중 제일 낮은 주소를 가진 바이트가 4개의 연속된 바이트를 가리키기 위해 쓰인다.

32비트패턴이 메모리의 4바이트에 어떻게 저장될까? 4바이트엔 32비트가 있고 패턴에도 똑같이 32비트가 있지만, 패턴의 어떤부분이 어떤 바이트로 들어가야 할지 결정해야한다. 일반적으로 컴퓨터들은 아래의 두가지 방법중 하나를 사용한다

빅 엔디언 바이트 오더(Big Endian Byte Order): 데이터의 최상위 바이트(MSB 또는 the big end)가 가장 낮은 주소에 들어간다. 나머지 데이터도 순서대로 남은 3바이트에 들어간다.

리틀 엔디언 바이트 오더(Little Endian Byte Order): 데이터의 최하위 바이트(LSB 또는 the little end)가 가장 낮은 주소에 들어간다. 나머지 데이터도 순서대로 남의 3바이트에 들어간다

위의 정의에서 32비트 패턴-데이터- 는 32비트 부호 없는 정수로 간주할 때, '최상위 바이트'는2의 큰 제곱수들중의 하나이다: 2^31,...,2^24. 마찬가지로 '최하위 바이트'는 2의 작은 제곱수들중 하나이다: 2^7,...,2^0.

예를들어, 32비트패턴 0x12345678이 0x00400000 에 있다고 한다면, 최상위 바이트는 0x12가 되고 최하위 바이트는 0x78이 된다. 아래에 두 바이트 오더를 그려놓았다.

attachment:bigLittleEndianNew.gif

단 하나의 '''바이트'''안에서 비트의 순서는 항상 같다.

질문: 위의 32비트워드에서 최상위바이트를 가지고있는 비트 패턴을 써보세요.

역주:참조 [http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Network_Programing/Documents/endian 빅엔디언과 리틀엔디어]


=== MIPS와 SPIM의 바이트오더 ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_4.html

최상위 바이트는 0x12를 가지고 있는 바이트입니다. 비트패턴은 아래와 같습니다

0001 0010

바이트 안에서는 어떤 프로세서든지 7번재 비트가 최상위 비트이다. 그러므로 빅 엔드 바이트는 두 가지 바이트 순서에서 모두 똑같다.  일반적으로 표시할때에는 0001 0010처럼 최상위 비트가 가장 왼쪽에 있다. 참고: 바이트 순서에 대한 것이 아니라면 빅 엔드 바이트는 최상위 바이트(high-order byte 또는 Most Significant byte) 라고 부른다.

밉스 프로세서는 하드웨어의 설정을 통해 두 바이트 오더중 하나를 선택할 수 있다. 컴퓨터 시스템 디자이너가 나머지 컴퓨터 시스템의 구성요소들을 고려해 결정한다. SPIM시뮬레이터는 시뮬레이터가 실행되는 컴퓨터의 바이트 오더를 따른다.

인텔 80x86: 리틀엔디언
매킨토시: 빅엔디언 

아래의 예제들은 윈도우즈/인텔 컴퓨터에서 작성되었으므로 매킨토시 사용자의 결과와는 차이가 있을것이다.

질문: (일반적인 경우와 같이)최상위비트가 왼쪽에 쓰인 비트패턴 0xFF00AA11에 대해 빅 엔디언 과 스몰 엔디언 바이트 오더로 바이트들을 메모리로 복사해보세요.

|||| 리틀 엔디언 |||| 빅 엔디언 ||
|| 주소 || 내용 || 주소 || 내용 ||
|| 4003 || || 4003 || ||
|| 4002 || || 4002 || ||
|| 4001 || || 4001 || ||
|| 4000 || || 4000 || ||

=== 프로그램을 이식하는 문제(Portability Problems) === 

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_5.html

답:

|||| 리틀 엔디언 |||| 빅 엔디언 ||
|| 주소 || 내용 || 주소 || 내용 ||
|| 4003 || FF || 4003 || 11 ||
|| 4002 || 00 || 4002 || AA ||
|| 4001 || AA || 4001 || 00 ||
|| 4000 || 11 || 4000 || FF ||

다음 사항을 명심합시다.

1, 4개의 바이트의 묶음을 가장 작은 주소로 그 묶음의 주소를 지정합니다.  
 
2. 그 묶음에 바이트가 들어가는 방법은

   * 빅 엔디언(Big Endian): 끝이 MSB이다(the big end).
   * 리틀 엔디언(little end):  끝이 LSB이다(the little end).

3. 나머지 3 바이트를 순서대로 채운다.

워드를 메모리로부터 부를때 전자기기는 바이트들을 레지스터안에 올바른 오더로 집어넣는다. 프로세서안에서 덧셈과 같은 작동은 올려진 오더대로 덧셈을 한다. 레지스터가 메모리에 바이트들을 저장할때도 같은 오더로 저장을 한다. 동일한 전자기기안에서는 어떤 바이트 오더를 사용하든 상관이 없다. 대부분의 경우에 어떤 바이트 오더를 사용하든지 신경을 쓸 필요가 없다.
   
하지만 다른 컴퓨터의 데이터를 사용하는 경우에는 이런한 문제를 고려해 보아야한다. 옛날 메인프레임 컴퓨터가 작성한 정수 데이터 파일이 있다고 가정해보자. 이것을 올바르게 읽어내기 위해서는 여러가지 것들을 알아야 하겠지만 우선적으로 다음의 사항을 참고해야한다.

 * 몇개의 비트를 사용해서 각각의 정수를 표현하였는가.
 * 어떤 표현법을 사용하여 정수를 표현하였는가(2의 보수법 또는 다른 표현법)
 * 어떤 바이트 오더링을 사용하였는가(빅엔디언 또는 리틀엔디언)

질문:

데이터가 비트 패턴의 묶음으로 인터넷을 가로질러 전송됩니다. 이러한 인터넷에 전송되는 데이터들에서도 바이트의 전송순서가 중요합니까?

=== 밉스 주소 ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_6.html

답: 

네. 자세한 내용은 상당히 복잡합니다. 그러나 확실하게 이것에 대한 국제적 표준이 있습니다. 

워드를 레지스터로 로드하는 명령은 lw이다. 반대로 워드를 스토어하는 명령은 sw이다. 각각의 명령은 항상 레지스터와 메모리 주소를 지정해야한다. 밉스 명령은 32비트이다.  밉스 메모리 주소도 항상 32비트이다. 그러면 어떻게 lw나 sw같은 명령이 명령의 크기와 같은 32비트 크기의 주소를 지정할 수 있을까?   

메모리를 가리키는 명령은 베이스 레지스터와 오프셋을 사용한다. 베이스 레지스터는 32비트 주소를 가지고 있는 일반 레지스터이다. 오프셋은 명령에 포함되어있는 16비트의 부호있는(signed) 정수이다. 베이스 레지스터에 있는 주소와 (부호확장된)오프셋과의 합이 메모리 주소를 가리킨다.

아래가 어셈블리어로 된 로드 명령이다:


lw   d,off(b)       # $d <-- 메모리 주소 b+off에있는 워드
                    # b는 레지스터이고, off는 16비트 2의 보수식의 정수이다.}}}
실행시에는 2가지 일이 일어난다: 
첫째, 베이스 레지스터 b와 오프셋 off를 이용해 주소가 계산되고
둘째, 그 주소에 있는 데이터가 메모리로부터 읽혀진다.

질문:
0x00400060에 있는 워드를 읽어들여 레지스터 $8로 읽어들이는 명령을 써보세요. 레지스터 $10이 0x00400000을 가지고 있다고 가정하자

lw $8, _____(   )

=== 워드를 로드하는 명령 ===
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_7.html

답:

0x00400060 --- data 주소
0x00400000 --- $10에 저장된 베이스 주소
$8         --- 저장되는 레지스터

명령은 다음과 같다.

lw $8,0x60($10)

다음은 명령을 기계어로 쓴것이다. 기계명령은 베이스 레지스터와 저장되는 레지스터 그리고 오프셋(offset)을 지정하기만 하고 직접적인 메모리 주소를 담고 있지는 않다.

100011 01010 01000 0000 0000 0110 0000 -- 필드(field)로 나누어진 기계 명령

lw $10 $8 0060
opcode 베이스(base) 저장레지스터(dest) 오프셋(offset) -- 각 필드가 의미하는 바
lw      $8, 0x60($10)                   -- 어셈블리어로 표현한 것

다음과 같이 윗명령은 실행된다:

  1. 레지스터 10는 32 비트주소 0x00400000 을 담고 있다.
2. 오프셋은 32비트로 0x00000060으로 부호연장 된다 . 3. 1번 베이스 32비트 주소와 2번 오프셋 32비트의 합이 메모리 주소인 0x00400060이다: 4. 주메모리에서 이 주소에 담겨진 데이터를 가져오도록 요청한다. 5. 하나의 기계 사이클이 지연(delay)된 후 데이터는 레지스터 8에 올려진다. 레지스터 8에는 4바이트가 올려진다.

메모리로부터 불려진 데이터는 1 머신사이클 후 사용할 수 있다. 프로세서 칩 외부에 있는 메모리로부터 데이터를 불러 오는데 시간이 걸린다. 하지만 프로세서는 로드가 진행되는 동안 로드를 기다렸다가 명령을 하나더 실행하는것은 아니다. 이것을 로드 딜레이 슬롯(load delay slot)이라고 한다. lw명령 바로 다음에 오는 명령은 로드되는 레지스터를 사용하면 안된다. 때때로 lw 바로 다음 명령으로 무작동(no-operation) 명령을 사용하기도 한다.

질문:

메모리 주소
000 00005 00040014
000 00004 00040010
000 00003 0004000C
000 00002 00040008
000 00001 00040004
000 00000 00040000
12번과 13번 레지스터와 위의 메모리를 자세히보자. 0x00000004 값을 레지스터 12번에 저장하는 명령을 작성해보자.

  • 레지스터 12번은 0xFFFFFFFF를 담고 있다.
  • 레지스터 13번은 0x00040000을 담고 있다.

워드를 스토어하는 명령

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_8.html

답: lw $12, 0x10($13)

$12의 원래 내용은 버려지고 메모리에서 불러온 32비트로 교체됩니다.(메모리에는 아무 조작도 가해지지 않습니다)

워드를 스토어하는 명령 sw는 레지스터에서 데이터를 복사해서 메모리에 저장한다. 레지스터는 바뀌지 않는다. 메모리 주소는 베이스/오프셋 쌍을 이용해 지정한다.

sw   t,off(b)       # 메모리 주소의 워드 (b + off) <== $t
                    # b는 레지스터, off는 16비트 2의 보수식의 정수}}}
lw명령과 같이, 메모리 주소는 워드 정렬이 되어있어야 한다.(4의 배수)

질문:
attachment:lwProblem.gif
먼저 위에 있는 레지스터 $12와 $13과 메모리를 보세요. 워드 $0xFFFFFFFF 를 메모리 주소 0x0004000C로 옮기는 명령을 써보세요

* $12에는 0xFFFFFFFF가 있다
* $13은 0x00040014를 가지고 있다.

sw $_____ , _____($      )

힌트: 16비트 오프셋을 부호있는 10진수 정수로 써도 됩니다.

=== 베이스 레지스터 설정하기 ===
http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_9.html

답:

sw $12 , 0xFFF8($13)    or    sw $12 , -8($13)

attachment:lwProblem.gif

답에서 첫번째 명령은 2의 보수식으로 표현된 16비트를 사용하여 음수 8을 표현하였다. 이 16비트는 실제 기계 명령이 담고 있는 비트 패턴이다.이것을 실제로 읽고 계산하는 것이 어색할 수 있다. 2번째 명령에서는 부호있는 10진수 표현법으로 음수 8을 지정하였다.  어셈블러는 이 명령을 첫번째 어셈블러 명령과 똑같은 기계명령으로 어셈블리화한다.

32비트크기의 베이스 레지시터와 오프셋을사용하여 32비트 크기의 lw나 sw 명령은 메모리를 참조 할 수 있다. 그렇다면 어떻게 베이스 주소는 베이스레지스터로 올려질 수 있을까? lui(load upper immediate) 명령이 이런 경우에 사용된다. lui명령은 16비트 크기의 직접 피연산자를 지정된 레지스터의 윗쪽 2 바이트로(upper two bytes) 복사를 한다.


lui  d,const  #  d레지스터의 위쪽 2 바이트 <-- 2 바이트의 상수(const)
                 #  d레지스터의 아래쪽 2 바이트 <-- 0x0000

때때로 lui 명령만으로 베이스레지스터를 설정할 수 있다. 예를 들어 메모리가 위의 그림과 같고 0x0040010에 있는 워드를 레지스터 12번에 올리고자 한다고 가정해 보자. 이럴 경우 lui명령으로 베이스 레지스터를 설정할 수 있다.

질문:
lui $13, 0x________
lw  $12, 0x10($13)

lui 명령을 완성해보자

아래 2바이트 채워넣기

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_10.html

답:
lui $13, 0x0004
lw  $12, 0x10($13)

lui 명령이 실행된후 $13은 0x00040000을 담는다. 원하는 주소값을 얻기위해서 0x10을 오프셋으로 사용한다.

lui명령을 사용하여 베이스 레지스터에 0x00010000의 배수값들을 저장할 수 있다. 하지만 종종 베이스레지스터로 좀더 특정한 주소를 지정하는 경우가 있다. 이러한 경우 ori명령을 사용하여 아래쪽 16 비트를 채워 넣으면 된다. ori 명령을 다시한번 복습해보자.

ori d,s,imm

직접 피연산자 imm은 0으로 확장되어 32비트가 된다.32비트 0확장후 소스레지스터 $s의 내용물과 비트단위 OR 작동을 한다. 결과물은 목적레지스터 $d에 저장된다.

attachment:lwProblemTwo.gif

윗그림에 보여지는 메모리를 주목해 보자. 아래에 쓰여진 lw명령은 주소 0x0060500C에 있는 위드를 $12에 저장한다.

lui $13, 0x________
ori $13, $13, 0x________
lw  $12, 0xC($13)

질문:

빈칸을 채워 명령을 완성해보자.

다른 명령순서로 해보기

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_11.html

답:
lui $13, 0x0060
ori $13, $13, 0x5000
lw  $12, 0xC($13)

위에 보여진 ori 명령은 다음과 같이 13번 레지스터의 아래쪽 16비트를 채워넣는다.

lui 명령후 $13 : 0000 0000 0110 0000 0000 0000 0000 0000
영 확장된 직접 피연산자 imm : 0000 0000 0000 0000 0101 0000 0000 0000
비트단위 OR 작동의 결과 : 0000 0000 0110 0000 0101 0000 0000 0000
다른 순서의 명령들을 사용해서도 같은 주소결과를 얻을 수 있다. 주소의 위쪽 반은 16비트이고 lw명령의 오프셋도 16비트이다. 이 둘을 결합하여 메모리의 어떤 바이트도 주소를 지정할 수 있다.

이 전장의 문제는 주소 0x0060500C의 워드를 $12에 올리는 것이었다. 다음은 다른 방법을 사용하여 같은 문제를 풀고있다. 먼저 주소를 0x0060와 0x500C로 각기 반으로 나눈다. $13레지스터에 위쪽반을 올린다. 나머지 아래쪽 반쪽을 오프셋으로 사용한다.

lui $13, 0x0060
lw  $12, 0x500C($13)

앞으로 프로그램에서는 어떤방법이던 경우에 따라 최상의 방법을 사용해 보자.

ori명령은 피연산자들중 하나를 목표 레지스터(destination)로 자주 사용하기 때문에 좀더 간소화한 명령이 어셈블리어에 있다.

ori  $d,const  # ori $d,$d,const와 같은 의미의 명령이다.

질문:

다음 두 어셈블리 명령이 똑같은 기계명령을 만들어 낼까요?

ori  $10,$10,0x00C4
ori  $10,$0, 0x00C4

어셈블리 배열

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_12.html

답 : 아니오. 첫 명령은 $10의 윗쪽 반쪽을 놔둔채 아래쪽 반을 OR시킵니다.

두번째 명령은 0x00C4가 영으로 확장된 32비트값을 $10에 저장합니다.

ori  $10,$10,0x00C4

ori  $10,$0, 0x00C4}}}

정수의 배열은 워드 정렬된 연속된 워드의 값으로 구현된다. 아래의 다이어그램을 밑에 c 코드로 표현된 정수 배열을 구현한 것이라고도 볼 수 있다. 

int data[] = {0, 1, 2, 3, 4, 5};


attachment:lwProblemTwo.gif

위의 코드는 "C"라는 언어를 사용해 표현 되었지만 이 페이지를 이해하기위해 "C"를 알아야 할 필요가 전혀 없다. 위의 선언은 6개의 원소로 이루어진 배열을 만들고 각각의 값을 정수 0부터 5로 채운다.

질문:
이 배열을 가리키기 위해서 어떤 메모리 주소를 사용하는것이 가장 적당하겠습니까?

=== 예제 프로그램 ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_13.html

답: data[0]의 주소인 0x00605000. 실제로 ANSI C 에서 배열을 가리키는 심볼(이 경우 data)은 배열의 첫 원소의 주소를 가리킵니다. 보통 실행시에  베이스 레지스터가 이 주소값을 담고 있습니다.

메모리로부터 레지스터를 로드할 때 좀 더 쉬운 방법이 있을까? 기계어수준에서는 없다. 그러나 어셈블러는 lw와 sw명령을 쉽게 사용할수 있는 기능들을 가지고 있다. 뒷부분에서 다룰것이다.

예제프로그램작성을 시작해보자. 이 프로그램은 메모리의 x값을 불러들여 5x^2 - 12x + 97의 값을 구할 것이다. 결과를 메모리의 poly 라는 곳에 저장한다.

질문: 예제프로그램에서 

lw 명령과 sw 명령을 몇 번이나 사용할까요?

=== 심볼릭 주소 ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_14.html

답: 각각 1번이 필요합니다. x값을 불러들일때 lw, poly값을 저장시킬 때 sw를 한번씩 사용합니다.

이 프로그램에서 메모리의 위치를 각각 x와 poly로 불렀다. 당연히 실행시에 주소들은 32비트의 패턴이다. 그러나, 어셈블리 소스코드에서는 특정한 메모리의 위치를 위해 이름을 지어주는것이 편하다. 그러한 이름을 '''심볼릭 주소(Symbolic Address-기호로 된 주소)''' 라고 한다. 어셈블러의 중요한 기능중 하나가 심볼릭 주소의 지원이다. 아래의 예제에서는, 그러나, 하드웨어 명령이 어떻게 작동하는지를 설명하기 위해 일부 기능을 사용하지 않을 것이다.

아래는 예제 프로그램이다:



## poly.asm
##
## 5x^2 -12x + 97 값을 구한다.
##

        .text
        .globl  main

main: 

        # . . . . 각종 명령들

        .data
                             # SPIM에서 데이터를 위한 섹션은
                             # 주소 0x10000000에서 시작한다.
x:      .word   17           # 베이스 레지스터가 여기를 가리킨다
poly:   .word   0

## 파일의 끝}}}

어셈블러 지정자인 .data는 메모리의 데이터를 저장하는 부분이 시작된다는 것을 의미한다. .word는 32비트의 2의 보수식으로 표현된 정수라는 뜻이다. 정수는 기본적으로 10진수로 표현되어 있다.

위에서 .word 17은 십진수 "17"이 표현하고 있는 수를 32비트 2의 보수 표현식으로 표현된 패턴을 말한다. 어셈블러가 적당한 비트 패턴으로 변환 시킨다.

16진수를 사용할 수도 있다. .word 0x11은 .word 17을 의미한다.

질문:
SPIM에 있는 어셈블러는 자동적으로 .data섹션을 0x10000000에서 시작하도록 한다.
1. x의 주소는 무엇일까요?
2. poly의 주소는 무엇일까요?

=== 예제 계속 ===

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_15.html

답: SPIM의 어셈블러는 자동적으로 주소 0x10000000에서 시작하는 코드를 어셈블합니다.

1. x의 주소는 무엇일까요? '''0x10000000'''
2. poly의 주소는 무엇일까요? '''0x10000004'''

아래의 그림은 SPIM실행시의 이 부분을 나타낸 것입니다:
attachment:polyDataSect.gif

프로그램의 중요한 부분이다. 어떤 레지스터가 무엇에 쓰일 것인지 결정해야한다. 그리고 어떤 레지스터를 사용하기로 결정 했는지 써 넣어 보자. 정확한 결과를 얻기위해서 어떤 레지스터를 사용할 지 분명히 하는 것이 매우 중요하다.


## poly.asm  
##
## evaluate  5x^2 -12x + 97 
##
## Register Use:
##
## $10 베이스 레지스터, x의 주소
## $11 x
## $12 다항식의 결과
## $13 임시저장소

        .text
        .globl  main

main: 
        lui   $10,______     #  베이스 레지스터 초기화
        lw    $11,0($_____)  #  x를 로드

        ori   $12,$0,_____   #  누산기 초기화를
                             #  "load delay slot"기간중 한다

        #. . .  기타 명령들

        sw    $12,___($___)  #  결과를 poly에 저장한다

        .data
                             # 스핌에서는 데이터 섹션이
                             # 주소 0x10000000 에서 시작한다
x:      .word   17           # 베이스 레지스터가 여기를 가리킨다
poly:   .word   0

계산의 결과를 저장하고 메모리로 옮길 수 있는 레지스터를 누산기(accumulator)라고 부른다 (오래된 프로세서들은 누산기를 위한 특별한 하나의 레지스터를 가지고 있는 경우도 있지만, MIPS는 이 기능을 할 수 있는 일반 레지스터를 많이 가지고 있다 - 역주: 누산기는 오래된 용어이다. 현대의 마이크로 프로세서에서 대부분의 레지스터는 누산기 기능을 겸한다).

로드명령을 사용한 직후 바로 다음 명령에서는 그 값을 바로 사용 할 수 없다는 것을 기억하자. lw명령 다음에 있는 "로드가 지연되는 구간 또는 로드 딜레이 슬롯(load delay slot)" 에서는 로드되는 데이터를 사용하려고 시도해선 안된다.

질문: 빈 칸을 채우십시오. lui명령을 복습하고 싶다면 이 전의 을 보십시오. 베이스 레지스터의 윗쪽 반을 첫 데이터 주소의 윗쪽 반으로 로드하기위해 이 명령을 사용하십시오..

이차항(second term)

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_16.html

답: 아래를 보자.

SPIM의 데이터 영역이 0x10000000에서 시작하기 때문에 $10에 lui명령을 사용하여 데이터 영역의 첫번째 주소를 저장할 수 있다. 주소의 아래쪽 16비트는 모두 0이된다. x의 주소는 베이스 주소로부터 0을 오프셋한 주소가 된다. 결과 값의 장소는 베이스 주소로부터 4 오프셋한 주소가 된다.

이제 빈칸을 채워서 2차항 값을 구해서 누산기(accumulator)에 더해보자.

## poly.asm  
##
## 5x^2 -12x + 97 계산한다 
##
## 사용하는 레지스터:
##
## $10 베이스 레지스터, x의 주소
## $11 x
## $12 다항식의 결과
## $13 임시저장소

        .text
        .globl  main

main: 
        lui   $10,0x1000      #  베이스 레지스터 초기화
        lw   $11,0($10)    #  x를 로드

        ori   $12,$0,97  #  누산기 초기화를
                             #  "load delay slot"기간중 한다

          ori   $13,$0,12      #  2차항을 계산 한다.
        mult  $__,$__        #  12x
        ____  $13            #  32비트라고 가정한다
        subu  $__,$__,$__    #  누산기(accumulator) = -12x +97

        #. . .  기타 명령들

        sw     sw    $12,4($10) #  결과를 poly에 저장한다

        .data
                             # 스핌에서는 데이터 섹션이
                             # 주소 0x10000000 에서 시작한다
x:      .word   17           # 베이스 레지스터가 여기를 가리킨다
poly:   .word   0

질문: 빈칸을 채워보자.

3차항(Third Term)

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_17.html 답: 아래를 보자.

이제 x를 거듭제곱한후 5를 곱해서 결과를 누산기에 더하면 된다. x를 거듭제곱을 한후 x의 값은 더이상 필요가 없다. x의 거듭제곱값은 레지스터 11에 다시 저장된다.

## poly.asm  
##
## 5x^2 -12x + 97 계산한다 
##
## 사용하는 레지스터:
##
## $10 베이스 레지스터, x의 주소
## $11 x
## $12 다항식의 결과
## $13 임시저장소

        .text
        .globl  main

main: 
        lui   $10,0x1000      #  베이스 레지스터 초기화
        lw   $11,0($10)    #  x를 로드

        ori   $12,$0,97  #  누산기 초기화를
                             #  "load delay slot"기간중 한다

          ori   $13,$0,12      #  2차항을 계산 한다.
        mult  $11,$13        #  12x
        mflo  $13            #  32 비트라고 가정한다.
        subu  $12,$12,$13    #  accumulator = -12x +97

                             #  3차항 값을 구한다.
        mult  $__,$__        #  x^2
        mflo  $__            #  32비트라고 가정한다.

        . . . 기타 명령들

        sw    $12,4($10)     #  결과를 poly에 저장한다

        .data
x:      .word   17            # 베이스 레지스터가 여기를 가리킨다
poly:   .word   0

## 파일의 끝

질문: 빈칸을 채워보자.

3차항 구하기 계속

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_18.html

답: 아래를 보자

남은 부분의 프로그램을 채워 넣어 완성해보자

## poly.asm  
##
## 5x^2 -12x + 97 계산한다 
##
## 사용하는 레지스터:
##
## $10 베이스 레지스터, x의 주소
## $11 x
## $12 다항식의 결과
## $13 임시저장소

        .text
        .globl  main

main: 
        lui   $10,0x1000      #  베이스 레지스터 초기화
        lw   $11,0($10)    #  x를 로드

        ori   $12,$0,97  #  누산기 초기화를
                             #  "load delay slot"기간중 한다

          ori   $13,$0,12      #  2차항을 계산 한다.
        mult  $11,$13        #  12x
        mflo  $13            #  32 비트 결과로 가정한다.
        subu  $12,$12,$13    #  accumulator = -12x +97

                                      #  3차항 값을 구한다.
        mult  $11,$11        #  x^2
        mflo  $11            #  32 비트 결과로 가정한다.
        ori   $13,$0,___     #  5
        mult  $___,$___      #  5x^2
        mflo  $13            #
        addu  $12,$___,$___  #  누산기 = 5x^2-12x+97

        sw    $12,4($10)     #  결과를 poly에 저장한다.

        .data
x:      .word   17 
poly:   .word   0

## 파일의 끝

빈칸을 채워넣어 프로그램을 완성해 보자.

질문: 빈칸을 채워넣어 보자.

완성된 프로그램

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_19.html

답: 아래를 보세요.

완성된 프로그램이다. 클립보드를 이용해 복사하고, 텍스트 에디터에 붙여넣고 저장하면, SPIM으로 실행 시킬 수 있다.

## poly.asm  
##
## 5x^2 -12x + 97 계산한다 
##
## 사용하는 레지스터:
##
## $10 베이스 레지스터, x의 주소
## $11 x
## $12 다항식의 결과
## $13 임시저장소

        .text
        .globl  main

main: 
        lui   $10,0x1000      #  베이스 레지스터 초기화
        lw   $11,0($10)    #  x를 로드

        ori   $12,$0,97  #  누산기 초기화를
                             #  "load delay slot"기간중 한다

          ori   $13,$0,12      #  2차항을 계산 한다.
        mult  $11,$13        #  12x
        mflo  $13            #  32 비트 결과로 가정한다.
        subu  $12,$12,$13    #  accumulator = -12x +97

                                      #  3차항 값을 구한다.
        mult  $11,$11        #  x^2
        mflo  $11            #  32 비트 결과로 가정한다.
        ori   $13,$0,5     #  5
        mult  $11,$13      #  5x^2
        mflo  $13            #
        addu  $12,$12,$13  #  누산기 = 5x^2-12x+97

        sw    $12,4($10)     #  결과를 poly에 저장한다.

        .data
x:      .word   17 
poly:   .word   0

## 파일의 끝

당연히 프로그램은 올바른 x값들로 테스트 되어야 한다. 실제 상용 프로그램에서는 x의 상한값과 하한값을 문서로 남기는 것이 좋다.

질문: 테스트에 사용할 x값 3개를 추천해 보세요.

실행

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_20.html

답:

0, 1, -1. 물론 여러가지 값들을 테스트 할 수 있다. 하지만 종종 이 3가지 값으로 테스트해볼 때 여러가지 문제점을 찾아낼 수 있다.

다음 그림은 x의 값이 -1로 바뀌 후 프로그램 실행 결과를 보여준다. 결과는 0x72 = 114<10>로 정확한 값이다. 항상 그렇지만 스핌에서 실행은 F10을 눌러서 한 단계씩 할 수 있다. PC는 0x00400000로 초기화 되었다.

attachment:polyRun.gif

소스파일을 만들어서 프로그램을 가지고 실행해 보자. 프로그램에 버그를 집어넣었을때 어떠한 일이 생길 수 잇는지 관찰해 보자. 적절한 x값이 가질 수 있는 범위를 찾아보자.

질문: 적절한 x값의 범위를 어떻게 결정할 수 있겠습니까?

15장 끝

http://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_21.html

답: 결과 값 poly는 2의 보수로 표현된 32비트의 범위 안에 있어야 한다. 그러므로 -231 <= 5x^2 -12x + 97 <= 231 - 1 범위안에 있어야 한다. 직접 산수를 풀어서 x값의 영역을 구해보자.

이 장에서 논의된 것

워드 정렬 바이트 오더:리틀엔디언과 빅엔디언 믹스와 스핌 바이트 오더 주소값 구하기 lw 명령 lw 명령의 작동 load가 지연되는 구간(load delay slot) sw 명령 lui 명령 심볼 주소 .word 지정자 .data 지정자 레지스터 사용 테이블 누산기

퀴즈 프로그램과제를 해봅시다.