Arithmetic Example
f = (g + h) - (i + j);
// MIPS code
add $t0,g,h #temp to = g + h
add $t1,i,j #temp t1 = i + j
sub f,$t0,$t1 #temp f = (g + h) - (i + j)
MIPS는 32개의 register로 구성되며, 각 register는 32 bit이다.
register에 data를 올려 놓으면, 메모리에 접근할 필요가 없어서 data에 접근하기가 빠르다.
registersms 0~31까지 있다.
32비트의 data를 "word"라고 부른다.
Assembler
arithmetic operation을 하기위해서
메모리에서 register로 값을 가져온다.
register에서 memory로 결과값을 저장한다.
c code
g = h + A[8];
여기서 g는 변수를 저장하는 레지스터인$s1 안에 h는 $s2안에 &A[0]는 $s3안에 저장된다.
A[8]에 해당하는 메모리를 확보하기 위해서는
lw $t0,32($s3) // load word
이렇게 해줘야 한다. $s3 레지스터로 부터 32만큼 떨어진 주소를 t0에 load 하겠다는 뜻이다. 이후에는 이렇게 식을 만들어 준다.
add $s1, $s2, $t0 // g = h + A[8]
c code
A[12] = h + A[8];
이러한 경우, h는 $s2에 base adress인 A는 $s3에 저장된다.
MIPS code
lw $t0, 32($s3) // load word
add $t0, $s2, $t0 // s2와 t0를 더해서 다시 t0에 덮어쓴다.
sw $t0, 48($s3) //t0를 s3으로부터 48 떨어진 주소에 저장한다.
위로 올라갈수록, 접근성이 좋아 빠르고 공간은 적다.
상수와 함께 계산하는 instruction 타입, I타입이라고 한다.
addi $s3, $s3, 4 // constant data인 4를 s3와 더해서 s3에 저장
I 타입에는 sub가 없다.
addi $s2, $s2, -1 이런식으로 사용
상수 연산을 사용하면 메모리에서 데이터를 로드해오는 것보다 빠르다.
n- bit number 범위 ~
맨 왼쪽 비트가 1이면 negative 아니면 positive이다.
32비트 binary에서
0: 0000 0000 ... 0000
-1: 1111 1111 ... 1111
Most-negative: 1000 0000 ... 0000
Most-positive: 0111 1111 ... 1111
이러한 결과가 나오는이유는
1111 1111 ... 1111 = 1 + 1 +....+1 으로 계산하기 때문
비트 음수 만들기
보수 취해준뒤 +1
x + = 1111 1111 ... 1111 = -1
+ 1 = -x
예를들어
+2 = 0000 0000 ... 0010
보수 취해주면
1111 1111 ... 1101
여기다 +1
-2 = 1111 1111 ... 1110
I타입이 만들어진이유는 R타입에서 만약에 lw같은 메모리 로드 instruction을 쓴다고 생각해보자. lw는 두개의 레지스터와 상수가 필요하다. 만약에 상수자리에 R-format에 있는 레지스터중 하나를 사용한다고 했을때 32보다 작은 값만 사용할 수 있다. 메모리가 큰 배열에서는 32비트는 부족하다. 따라서, 16비트를 사용할 수 있는 I 타입이 생긴것이다.
address 에는 절대주소 대신 word 단위로 바꾼다.
예를들어
Loop:sll $t1, $t3, 2
add $t1, $t1, $s6
.....
j Loop
가 있는데 Loop 레이블의 절대주소가 80000이라고 하면
j instruction의 Loop에는 20000이 들어가야한다.
둘다 1이면 1 아니면 0을 t0에 넣어준다.
하나라도 1이면 1 아니면 0을 넣어준다.
값이 같으면 0 다르면 1을 넣어준다.
0과 1을 서로 바꾼다.
if(i == j) f = g + h; else f = g- h;
f,g,h,i,j를 각각 $s0~4에 할당되었다면 컴파일한 코드는??
i = j 라서 beq를 쓰면 될 것 같지만 실제로는 bne가 더 효율적이다.
bne $s3, $s4 Else // go to Else if(i != j)
add $s0,$s1,$s2 // f = g + h
j Exit
Else: sub $s0,$s1,$s2 // f = g - h(skipped if i != j)
Exit:
while (save[i] == k)
i += 1;
컴파일하면,
i -> s3, k->s5, save->s6에 할당되었다면
Loop: sll $t0, $s3, 2 // t0 = i*4
add $to,$to,$s6
lw $t1, 0($t0) // t1 = save[t0]
bne $t1, $s5, Exit // save[i] != k ->Exit
$addi $s3,$s3,1 // i += 1
j Loop // go to Loop
Exit:
컴퓨터에서 곱하기 연산은 오래 걸리기 때문에 bit shift 연산이 더 효율적
slt(set on less than)와 slti는 조건이 참이면 1 아니면 0을 반환한다.
보통 beq bne랑 같이 쓰인다.
두 변수 간의 대소 비교가 필요할때가 있다. 예를들어서, for문에서 인덱스 변수 값이 0 보다 작은지를 검사할 때가 있다. 인덱스 변수가 0 보다 작으면 0을 반환하고 bne가 0과 다르기 때문에 루프를 빠져나가도록 해준다.
blt(branch less than),bge(branch bigger than)을 잘안쓰는이유
큰지 작은지 비교하는 것은 모든 비트를 살펴봐야해서, 같은지만 살펴보는 bne,beq보다 오래걸린다.
따라서 bne,beq를 쓰는게 보통이다.