RISC-V에서 조건에 따른 결괏값을 boolean으로 돌려주는 instructions들은 총 4가지가 있다.
slt ( set less than )
sltu ( set less than unsigned )
slti ( set less than immediate )
sltiu ( set less than immediate unsigned )
slt & sltu
R-type으로 의미는 ~보다 작으면 1, 아니라면 0으로 결괏값을 반환한다. slt t0, s0, s1 이렇게 돼 있는 명령어를 해석하면 if (s0 < s1) then t0 =1; else t0 = 0처럼 해석할 수 있다. R-type이니 extension도 필요 없다. 그대로 들어가서 s0와 ALU에서 연산 후에 결과가 나와 t0로 들어가는 것이다.
slt는 overflow check 할 때도 사용한다.
먼저 overflow가 뭔지 알아보자, 3bit 컴퓨터라고 했을 때, unsigned라면 0~7까지 나타낼 수 있다. 이때 2+3을 하면 컴퓨터는 2에서 3 step 떨어진 5를 반환한다. 만약 2+6을 하면 어떻게 될까?? 우린 8을 예상하지만, 컴퓨터는 010 + 110을 했을 때 1000이라 3bit로는 표현 불가능하여 1을 버리고 000을 반환하여 결과가 0으로 나온다. 이게 overflow다.
즉 표시할 수 있는 범위를 넘어간 것이다. 이때 버려진 1은 어떻게 될까?? 여러 cpu에는 특별한 레지스터가 있는데 상태 레지스터라고도 한다. 이 레지스터에 C, V가 있는데 C는 unsigned에서의 overflow를 확인할 수 있고, V는 signed에서의 overflow를 확인할 수 있다.
하지만 RISC-V cpu는 status register가 없다. 그러니 sit를 이용하여 직접 확인해야 한다.
unsigned 일 때는 add t0 , t1, t2 : bltu t0, t1, overflow. 를 이용하고
signed 일 때는
add t0, t1, t2
slti t3, t2, 0
slt t4, t0 , t1
bne t3, t4, overflow
이렇게 하면 된다.
slti & sltiu
I-type으로 imm가 12bit 들어가 있다. 예를 들어 slti t0, t1, 4라고 하면 4를 sign extension 하여 t1과 비교한다.
sign extension 하는 건 sltiu도 마찬가지다. 하지만 이때 중요한 것이 있다. sing extension 하는데 imm는 12bit다. 그래서 명시해줄 때, slt t0, t1, 0x7FF하면 MSB가 0이니 괜찮지만 0 xFFF처럼 하면 에러 뜬다.
이유는 컴파일러가 우리는 0000_0FFF를 예상했는데 실제로는 FFFF_FFFF로 돼 연산하는 것에 있어 에러를 반환하여 정확히 명시하라는 의미다. 그렇기 때문에 0x FFFFFFFF 이렇게 해야 한다. 이렇게 하여 들어간 결과를 보자
slti t0, t1, 0xFFFFFFFF
4: fff32293 slti t0,t1,-1
앞에 12bit에 fff가 들어간 걸 볼 수 있다.
전체 예시
하나하나 실제 코드를 돌렸을 때, 어떻게 동작하는지 보자
int a, b;
unsigned int d, e;
_Bool test1, test2, test3, test4, test5;
test1 = a < b; // slt a5,a4,a5 2c: 00f727b3 slt a5,a4,a5
test2 = a > b; // sgt a5,a4,a5 3c: 00e7a7b3 slt a5,a5,a4
test3 = a < 7; // slti a5,a5,7 48: 0077a793 slti a5,a5,7
test4 = a < d; // sgtu a5,a4,a5 58: 00e7b7b3 sltu a5,a5,a4
test5 = d < e; // sltu a5,a4,a5 68: 00f737b3 sltu a5,a4,a5
sgt는 set great then이다. 즉 더 클 경우를 의미한다. unsigned일 때는 u가 들어가서 동작하는 걸 볼 수 있다.
Endianness
endianness은 레지스터의 데이터를 메모리에 어떻게 적재하냐 에서의 문제로 시작된다.
Big-endianness과 little-endianness가 있다. 쉽게 보자면 big-endianness는 레지스터의 MSB를 제일 아래에서부터 쌓고, little-endianness는 LSB를 제일 아래서부터 쌓는다
예를 들어, s0에 0x12345678이 있다고 하고 sw s0, 0(zero) lb s0, 1(zero)의 동작을 수행했을 때, big-endianness는 s0에 0x0000_0045가 저장될 것이고, little-endianness일 때 s0에는 0x0000_0067이 저장될 것이다.
댓글