본문 바로가기
시스템 반도체/컴퓨터 구조 (RISC-V)

컴퓨터 구조 Branch instruction ( beq, jal, jump 범위, RISC-V )

by 전컴반 2022. 3. 1.
반응형

Branch instruction을 왜 쓰냐 하면 조건에 따른 동작을 하기 위해서 사용한다. 즉, 이동하기 위해서이다.

 

PC 레지스터가 동작을 하며 계속 증가하다가 branch 명령어를 만나면 조건에 따라 PC의 값을 바꾼다. 그리고 바뀐 주소로 이동하여 동작을 수행한다. 이렇게 branch 명령어는 PC와 밀접한 관계가 있다.

branch 명령어는 크게 2가지로 나뉠 수 있다. 조건에 따른 branch와 조건과 상관없이 동작하는 branch가 있다. 하나씩 보자.

 

1. Conditional Branch

 

조건에 따른 명령어이다. 조건이라 함은 비교를 말한다. 조건은 ==, <, >, !=, <=, >= 이렇게 6가지가 있다.

아래 명령어를 보자

 

- beq (branch if equal) ( a == b )

- bne (branch if not equal) ( a != b )

- blt (branch if less than) ( a < b )

- bge (branch if greater than or equal) ( a >= b ) 

- bltu (branch if less than for unsigned) ( a < b )

- bgeu (branch if greater than or equal for unsigned) ( a >= b)

 

unsigned를 구분했다. 근데 보니 <=, > 조건을 비교하는 명령어는 없다. 그렇다면 어떻게 해야 할까? 이때 pseudo 명령어를 사용한다.

 

'>'는 pseudo 명령어, bgt(u) a, b , label을 사용한다. 하지만 실제 동작은 blt(u) b, a , label을 한다. a와 b의 위치를 바꿔 동작한다.

 

'<='는 pseudo 명령어, ble(u) a, b, label인데 실제로는 bge(u) b, a, label을 한다. 역시 a, b의 위치를 바꿔서 동작한다.

(+ (u)를 한 이유는 unsigned일 때 사용한다)

 

 

가장 대표적인 beq를 보자. a == b일 때 동작한다. B-type이다. 바로 예를 보자,

 

 

beq s0, s1, skip

sub ...

lw ...

skip : add t0, t1, t2

 

위 코드에서 pc가 beq s0, s1, skip를 가리켰을 때, s0 == s1이라면 sub, lw 명령어를 건너뛰고 skip label이 있는 곳부터 다시 동작을 수행한다. 이때 skip label은 메모리 주소와 같은 역할이라 지정 label을 만날 때까지 한다. label은 imm(offset) + PC으로 정한다.

 

위의 예에서 offset은 12이다. 왜냐면 beq - sub - lw - skip 이렇게 3번의 명령어 이동이 일어나는데 하나당 4byte씩 크기를 가지고 있기 때문에 12를 imm에 넣는다. 

 

 

B-type의 imm을 보니 뭔가 이상하다. 4byte씩 증가하면 12비트 [11:0] 중 마지막 2비트는 어차피 변하지 않는다. 

 

..0000_0000 = 0

..0000_0100 = 4

..0000_1000 = 8

...

 

이렇기 때문에 [13:2]를 사용하여 마지막 2비트는 버리고 보면 더 좋을 텐데 왜 [12:1]을 사용할까??

이유는 extention에 있다. 다른 extension들은 똑같이 4byte를 기준으로 구분 짓지만  C extension은 2byte를 기준으로 구분 짓는다.

이렇기 때문에 2byte씩 증가한다면 마지막 1비트만 변하지 않고 나머지는 변한다. 이런 extension과 호환성을 고려하여 [12:1]으로 했다.

 

..0000_0000 = 0

..0000_0010 = 2

..0000_0100 = 4

 

정리하면, 12라고 하면 0000_0000_1100인데, 실제로 인코딩 되는 비트는 0000_0000_110-로 마지막 0은 인코딩 되지 않는다.

offset과 PC를 더하는데 이때 offset이 12bit라 sign extension 한 후에 PC와 더하고 결과는 다시 PC에 저장된다.

 

근데 문제가 있다. 이동하는데 제한이 있다. 만약 skip이 imm의 범주를 벗어난 곳에 있다면 어떻게 해야 할까??

그때는 ". align x"라고 적어줘서 2^x만큼 이동시킬 수 있다. 

 

2. Unconditional Branch

 

어떠한 조건을 따르지 않고 그냥 바로 branch 하는 명령어이다. RISC-V에선 2가지 밖에 없다.

 

- jal (jump and link)

- jalr (jump and link register)

 

 

jal 명령어를 알아보자, J-type으로 사용법은 간단하다. 그냥 내가 지정한 곳으로 jump 하여 동작한다.

 

 

예를 들면 jal rd foo라고 한다면, PC 레지스터에 foo가 위치한 주소를 집어넣는다. 이와 동시에 PC + 4한 값을 rd에 집어넣는다. 즉 병렬적으로 일어난다. 

- PC = foo 

- rd = PC + 4 (리턴 주소이다)

 

foo는 함수의 이름을 의미한다고 볼 수 있다. 코드를 실행하다가 foo함수를 만나면, foo함수가 있는 위치로 이동하면서 메인 코드도 계속 진행돼야 하니 +4를 하여 다음 주소로 넘어가는 동작이다. 

 

여기서 또 궁금한 게 생긴다. 어디까지 jump 할 수 있을까? imm이 20bit이니, 2^20만큼 건너갈 수 있는가?

아니다. 예를 들어보자, 아래와 같다고 보자, imm은 4bit다.

 

0x : call foo

0x4: sub..

0x8: add

0xc: lw

foo : 0x10: sw

 

이때 foo가 0x10이라면 갈 수 있을까? 4bit이니 0~15까지 표현 가능하다. 그러니 0x10까지는 못 간다. 즉, 4bit일 때, 최대로 갈 수 있는 범위는 (2^4 - 4 = 12(0xc))까지 인 것이다. 

 

 

추가적으로 jalr는 jal과 다르게 어디든 jump 할 수 있다. 만약 jump 해야 할 곳이 너무 멀리 있다면 jal은 imm에 제한이 있지만 jalr은 레지스터에 값을 더하는 것이기 때문에 어디든 jump 가능하다. 이때 auipc로 레지스터를 정하고 jalr로 점프한다

반응형

댓글