오래 못 할 짓 하지 않기

[ 컴퓨터 구조 ] 8. Procedure 본문

2학년 2학기/컴퓨터 구조

[ 컴퓨터 구조 ] 8. Procedure

쫑알bot 2023. 10. 2. 00:21
728x90

Procedure

 

Fucntion이라고 생각하면 됨.

 

 

●  Procedure call step

 

1. 함수를 접근할 수 있는 곳에 파라미터를 넣어준다.
2. 함수로 이동( Transfer control )
3. 함수에 필요한 정보들을 메모리에서 가져온다.
4. 함수에 있는 동작 실행  
5. 접근(함수 call)한 부분에 값을 놓는다.
6. 원래 흐름대로 다시 진행

 

 

●  Procedure call 에 사용되는 Register

 

- $a0 ~ $a3 : Arguments 전달하는데 사용되는 레지스터 4개

- $v0 ~ $v1 : 결과값 return하는데 사용되는 레지스터 2개

- $ra            : 원래 PC주소로 돌아가기 위해 주소를 저장하는 레지스터 1개 ( 살작 르블랑 w 느낌임 )

 

 

 

●  Procedure call 에서 흐름

 

- JAL  (주소) 명령어가 실행된다면    [ 원래 흐름(메인 함수)에서 특정 함수로 넘어갈 때 사용 ]
  1) PC  ←  JAL가 가라고 한 주소

  2) $ra  ← JAL없었으면 원래 가려고 했던 주소:  PC   or  PC+4 

 

- JR $ra 명령어가 실행된다면          [ 실행된 함수에서 Main함수로 돌아갈 때 사용 ] 

  1) PC ← $ra

 


 

 

위에 있는 그림으로 보면,

h=f(3) < PC = 100
g=h+1   < PC 104

f (int i ) << 200

이라고 했을 때, f(3)으로 함수가 call됐을 때
PC는 그 다음 값을 104로 하지 않고 200으로 한다.
PC값을 바꾼 뒤에 원래 가려고 저장해둔 104는 ra register에 저장해둠..

함수의 실행이 끝나고는 다시 PC값에 ra 값을 넣는다.

 


Procedures use More Registers by Stack

: Stack 구조로 Register에 있는 데이터를 다루어야 값이 섞이지 않는다.

 

주로 메인이 가장 아래, 그 위에 호출되는 순으로 간다.

 

**( 이 부분은 더 알게되는 거 있으면 업데이트 하는 걸로 ) **

 

 

예) 

1. 레지스터들을 스택에 넣는다.

  -  새로 호출된 f는 $s0 레지스터에 할당함.

  -  $t0 레지스터에 (g+h) 를 넣고, $t1 레지스터에 (i+j) 를 넣는다.

 

2. 명령어대로 작동하여 SUB s0 t0 t1 를 실행한다.

3. 그 값은 $s0에 남아있다.

4. Return 을 위해서 $v0에 $s0 값을 넣는다.

5. Return 하고 돌아가기 위해 JR $ra.

 

 

ㅡㅡㅡㅡㅡㅡㅡㅡ

 

 

새로 올라오는 강의에 필요한 자료

 

https://ezeun.tistory.com/155

 

이거 양쪽 다 파란색 add부분이 잘못되어있음

*그림 오타: 파란색 add부분 옆 주석에 $s1 -> $t0  / $s2 -> $t1

 

 

(이전)

 

1. 스택은 word크기로 3개 addi해서 만들어 놓는다.  ( 1번줄 )

2. 각각의 register들을 1word 에 하나씩 스택에 넣어준다.  (  2 ~ 4번줄 )

3. 연산을 하고, return을 위해 v0 register에 옮겨준다.( 5~7번줄 + 8번줄 )

4. 다 load한 뒤에 sp값을 원래대로 다시 돌아오면서 12bytes = 3words ,3개를 pop한다. 

5. JR을 이용하여 원래 PC값으로 돌아온다.

 

(이후)  -- > return은 $s0만 할 거임. 나머지는 휘발성 정보들이라 t레지스터에 넣을 예정

 

1. 스택을 word단위로 1칸을 만든다. 

2. 하나의 register ($s0) 을 넣어준다. 나머지 것들은 굳이 stack에 안 넣어도 됨

3. 연산을 하고, return을 위해 v0 register에 옮겨준다.( 파란색 + 노란색 )

4. load하고 pop

5. JR을 이용하여 원래 PC값으로 돌아온다.

 

 

 

그냥 연산할 때만 필요해서 잠깐 만드는 register = > $t0 ~ $t9 

(지역변수 tmp라고 이해함) ( 함수 들어갔다가 나오면 값이 안 남아있음) 

 

계속 보존되어 쓰일 register = > $s0 ~ $s7   (전역변수라고 이해함) (주로 메인에서 계속 쓸 것) 

 

이렇게 하는 이유 )  regisetr spilling을 줄이기 위해 

* register spilling : 레지스터에 값을 가져오고 저장하고 하는 것

 

 

*** Exercise ***

각 명령어 별로 ra에 뭐가 들어가는지, 어떻게 흘러가서 어디로 돌아오고 어디로 넘어가는지 알아야함

 

- main에서 진행하다가 PC = 200일 때 sub1 함수로 간다. ( 그 순간에 PC = 204 , Ra = X )

- sub1함수로 넘어가고 PC = 300이 된다. ( 그 순간에 PC =300, Ra는 이전에 가르키고 있는 PC값인 204)

- PC = 400인 곳에서 sub2함수를 만나서 PC=404 에서 600 으로 되고 넘어간다. ( PC=600, Ra = 404 )  

- sub2 에서 ra값을 저장하고 다시 lw하고 POP을  한 뒤에 JR을 이용하여 돌아가게된다. 그럼 이전에 불렸던 함수인 sub1으로 감 ( PC = 404 , Ra = 204 ) 

- sub1에서 돌아갈 곳을 Load하여 POP하고 JR ( PC = 204 , Ra =X ) 

 

 

* Ra는 스택 형태로 저장됨 

* sw $ra 4   : 돌아갈 주소를 ra register에 스택 형태로 저장함. 

* lw $ra 4  -> addi $sp,$sp, 4 --> jr $ra      : 돌아갈 주소 가져오고 > POP하고 > Jump 

* $sp : stack pointer , $fp : frame pointer

 

 

 

 

그냥 이건 이해정도만 해라~ 하심

참고만 하기

 

 

 

Exercise

이거 MIPS Inst로 풀어보기

 

 

 

 

(출처)

 

한동대학교 용환기교수님 - 컴퓨터구조