함수에서 4개의 $a랑 $v외에도 추가적으로 argument가 필요하면 $t 와 $s를 쓴다.
$s
함수를 콜링하기 전에 함수가 끝나고 나서도 기억해야 하는 변수를 저장. 함수가 끝나고 메인으로 돌아왔을 때도 값이 유지되어 있음.
-> DRAM의 stack
공간에 저장
✅ stack
register를 저장하는 메모리상의 공간
$sp : 스택 공간을 관리하기 위한 포인터
가장 마지막에 저장된 값을 가리키고 있음.
다음 값을 나타내려면 4를 빼야함 (stack은 위에서 아래로 저장되기 때문)
함수가 끝나서 메모리를 비우면 원래의 곳을 가리키게 됨.
함수 안에 또 다른 함수가 없는 경우를 말함
-> 따로 return address를 스택 공간에 저장할 필요가 없음. return address가 바뀔 염려가 없으니깐.
addi ,sw랑 lw, addi는 세트!
leaf_example:
addi $sp,$sp,-4 # 데이터를 저장할 스택공간 확보
sw $s0,0,$sp # $s0의 값을 확보한 스택공간에 미리 저장해둔다
add $t0,$a0,$a1
add $t1,$a2,$a3
sub $s0,$t0,$t1
add $v0,$s0,$zero # return값을 $v0에 저장해둔다
lw $s0,0,$sp # 메모리에서 기존 $s0값을 cpu로 불러오기
addi $sp,$sp,4 # 스택 값 원상복귀 시키기
jr $ra #return address로 돌아가기
함수 내에 또 다른 함수가 존재하는 경우
-> jal하여 다른 함수로 갈 때 return address가 다른 함수로 업데이트 되기 때문에, 반드시! 스택 공간에 return address를 저장해두어야 한다.
(dynamic data-stack, heap)
1. Stack
위에서 아래로 저장됨
$fp
항상 첫 시작점을 (stable한 base register) 가지고 있고, return하면 원래의 위치로 돌아간다.
스택 공간에 값이 많이 쌓이면 초반에 저장한 데이터를 불러올 때 offset값이 너무 커지게 됨. 그래서 초반값을 불러오기 위한 용도로 $fp
를 사용한다.
⬇️
⬆️
값을 저장하면 위로 쌓이게 됨. malloc()을 이용해서 저장, free()를 이용하여 데이터 없애기
!꼭 free()를 해주어야 함. 안 하면 memory leak 발생
1. Heap
2. Static data
상수값, static variable
저장
$gp
static data의 특정 데이터에 접근하기 위한 포인터. 상수값, static variable의 값을 $gp
를 이용해서 lw
를 통해 불러온다.
3. Text
우리가 짠 코드를 assembler가 binary까지 바꾼 값들이 저장됨. 실제 프로그램을 수행할 때 text의 값들이 cpu로 load됨.
4. Reserved
우리가 건드릴 수 없는 영역
1번 register : $at
assembler가 사용하도록 예약되어 있음
26-27번 reigser : $k0-$k1
운영체제에 의해서 예약되어 있음
character를 표현하기 위해 8bit (1 byte)를 할당한다. 캐릭터는 byte 단위임!
$lb (load byte)
메모리에서 바이트를 불러와서 register의 rightmost 8 bit
에 저장
$sb (store byte)
register의 rightmost 8 bit에서 바이트를 가져와서 메모리에 쓴다
$lh (load half)
32bit / 2 = 16bit
halfword 만큼을 메모리에서 불러와서 register의 rightmost 16 bit
에 저장
$sh (store half)
register의 halfword 16 bit에서 바이트를 가져와서 메모리에 쓴다
메모리 주소값 32bit자체를 표현하고 싶을 때, 명령어가 32bit인데 앞에 opcode, rs, rtㄷ 때문에 32bit 메모리 주소 전체를 넣는 것이 불가능
$lui (load upper immediate)
$ori (or immediate)
아주 큰 상수를 define하거나 사용하기 위함
$lui
를 사용해서 i-format의 앞쪽 16bit를 합치고 본래 상수값을 앞쪽 16bit (left most shifting bit)로 이동시키고, 기존 16bit를 0으로 채운다.$ori
를 사용해서 0으로 두었던 부분인 하위부분을 합쳐준다.<i-format>
$bne
는 둘이 같은지 비교해서 정해진 주소값으로 가는 (레이블로 가는) instruction이다. 이때 정해진 주소값이 2^-15 ~ 2^15의 범위 밖에 있으면, j-format을 쓰게 된다.
<j-format>
앞에 6bit를 제외한 뒤의 26bit를 모두 주소값으로 사용할 수 있음. i-format에서 이동하지 못할 크기의 주소일 경우 j-format을 쓰면 됨.
-> 이제 j-format보다 더 크면 (26bit 보다 더 큰 주소값일 경우) $lui
를 사용해서 32bit로 만드는 것임!
PC (Program Counter)
register중 하나로 현재 프로그램에서 수행중인 instruction의 주소를 가리킴
-> 다음에 수행해야 할 instruction을 가리키기 위해 PC + 4를 기준으로 동작!
ex) $jal
할 때 돌아올 값인 $ra
를 저장하게 되는데, 이때 현재 Instruction인 PC가 아닌 다음 instruction인 PC+4를 저장하게 됨.
ex) $bne
에서 jump할 lable Exit의 주소값을 계산할 때 현 instruction의 PC값이 아닌 다음 instruction의 값인 PC+4를 기준으로 계산하여 주소가 '2'로 쓰여있음.
맨 앞 4bit를 PC에서 가져와서 채우고
offset 26bit를 복사해서 붙이고
남은 2bit는 00으로 채운다
4bit를 PC에서 가져와서 채우는 이유는 근방의 명령어로 점프하기 쉽게 하기 위해서
offset을 복사해서 붙이는 것은 sll하는 것과 같음!
00으로 채우는 이유는 alignment restriction에 의해 4비트 단위이므로
operand가 register인 경우
operand가 메모리에 있어서 메모리에서 값을 불러와야 하는 경우 (lw, ls)
immediate addressing - i format instruction
op /rs/ rt/ immediate
register addressing
op/ rs/ rt /rd/ --- / funct
base addressing
op / rs / rt / address
pc-relative addressing - branch instruction
op / rs / rt / address
// pc + 4를 기준으로 주소값의 offset을 계산하고 4
// address 4 + PC + 4
Pseudodirect addressing - j format instruction
op / address
PC의 왼쪽 4비트 , address, 00 구성
machine code 16진수 -> binary code 2진수 -> assembler code
왼쪽 6비트를 보고 op코드 판별, 그 외 해석