본문 바로가기
컴퓨터/컴퓨터구조

[UCB CS61C] Lec11, 12 RISC-V Instruction Formats

by 봄여름가을 2024. 1. 10.
  • (Memory address) Instruction과 data 모두가 메모리에 저장되게 되면서, 모든 것이 memory address를 갖게 되었다.
  • (Binary compatibility) 프로그램이 binary의 형태로 배포되며, 특정한 instruction set에 bind됨. instruction set들은 과거의 프로그램도 실행할 수 있는 방식으로 만들어지고 있음.
  • RISC-V에서는 instruction도 32-bit word size에 맞게 만들고 있음. 이를 위해 instruction word를 "field"들로 나누어 줌. 단순화를 위해 6 basic types of instruction formats을 정의함.

R-Format(register간 arithmetic 연산)

|500

  • opcode(0-6 bit): instruction이 무엇인지를 나타내는 역할
  • funct3(12-14 bit), funct7(25-31 bit): opcode와 합쳐져서, 어떤 Operation을 할 지를 설명
  • register specifiers: 5-bit unsigned integer(0-31)를 갖고 있음. 이는 32개의 레지스터에 해당(x0-x31)
    • rs1(source register 1): first operand
    • rs2(source register 2): second operand
    • rd(destination register): register for result of computation

I-Format(immediate 연산)

|500

  • R-format과 동일하되, rs2와 funct7을 합쳐서 12-bit signed immediate를 위한 자리를 만들었음. 따라서 -2048에서 2047까지의 구간을 담을 수 있음.
  • immediate를 arithmetic 연산하기 전에는 항상 32-bit으로 sign-extend함.
  • 단, shift 연산에서는 어차피 레지스터가 32-bit의 크기를 가지고 있기 때문에 31 비트 이상 밀어버리는 것은 의미가 없음. 따라서 immediate에서 낮은 5개 비트만을 사용하고, 그 위의 7개 비트는 srli와 srai를 구별하는 데에 사용함.
Load instructions

|500

  • load instruction 또한 I-type으로 구현됨.
  • rs1의 base address에 12-bit signed immediate를 더해서 메모리 주소를 정한다.

S-Format

|500

  • 우리가 레지스터에다가 값을 저장하는 것이 아니라, 어떤 메모리에 store한다는 것을 기억하자!
  • 그러면 rd는 필요하지 않고, 두개의 rs가 필요하다. rs1은 base memory address, rs2는 저장할 데이터가 담겨있는 레지스터다. 여기에 rs1을 위한 immediate offset이 있어야 한다.
  • rs1, rs2 필드의 위치는 그대로 두고(register name들은 매우 중요하므로), Immdiate bit를 잘라내서, lower 5 bits를 원래 rd자리로 보낸다.

B-Format

  • branch에서 넘어갈 수 있는 위치는 비교적 제한적이다. 따라서 PC-relative addressing을 사용하여, PC로부터의 offset을 immediate field에 저장한다.
    • instruction은 4 바이트 단위로 존재하기 때문에, 바이트를 unit of offset으로 사용하지 않는다.
    • 이렇게 하면 플러스 마이너스 $2^{11}$만큼의 instruction에 도달 가능하다.
  • 이런 식이라면, branch를 하지 않을 경우 $PC = PC + 4$, branch를 할 경우 $PC = PC + immediate \cdot 4$를 하는 방식인데, 실제로는 branch를 할 경우 이와 같이 계산하지는 않는다!
  • RISC-V는 16-bit compressed instruction을 지원하기 때문에, 설령 이러한 16-bit instruction이 없는 경우라도 branch offset은 2 bytes 단위로 계산된다. 그래서 결론적으로는 플러스 마이너스 $2^{10}$만큼의 instruction에 도달 가능하다. 그러면 항상 LSB는 0이 되기 때문에 이를 생략한다고 생각하면 된다.
  • 결론적으로는 branch가 없을 경우 $PC += 4$, 있을 경우 $PC += immediate \cdot 2$다.

|500

U-Format

|500

  • 20-bit immediate를 가지고 있으며, 1개의 Destination register(rd)가 있음.
  • lui는 load upper immediate로, destination의 upper 20 bits를 immediate값으로 쓰고, Lower 12 bits는 비운다(0). 여기에 addi를 써주면 lower 12 bits를 채워줄 수 있다.
    • 그런데 corner case로서, lower 12 bits를 더할 때 sign-extend가 일어나서, 만약 제일 위의 bit이 1로 되어 있다면 upper 20 bits에서 1을 뺀 효과가 나타난다.
    • 그렇기 때문에 이런 상황에서는 lui 연산을 할 때 1을 미리 더해놓는다.
    • 그래서 pseudo instruction li는 이러한 문제를 해결해 준다.
  • auipc 는 add upper immediate to PC로, PC에 immediate값을 더하고 그 결과를 destination register에 더해준다.

J-Format

|500

  • $PC+4$의 주소를 rd에 저장해 놓고, $PC = PC + offset$으로 하여 PC-relative jump를 한다. 여기서도 2 Bytes 단위로 플러스마이너스 $2^{19}$칸만큼 움직이기 때문에, 플러스마이너스 $2^{18}$ instruction 만큼 움직일 수 있다는 의미다.

|500

  • jalr에서는 마찬가지로 $PC+4$를 rd에 저장해놓고, $PC = rs + immediate$로 한다. 그러나 여기서는 2 bytes로 곱해주는 것이 아니라, arithmetic이나 load에서와 같다고 보면 된다.

    # call function at 32-bit absolute address
    lui x1, <hit20bits>
    jalr ra, x1, <lo12bits>  
    
    # jump PC-relative with 32-bit offset
    
    auipc x1,  
    jalr x0, x1,  

댓글