RISC-V 어셈블리 명령어 설명

어셈블리 명령어 동작을 C 언어 비슷한 문법 등으로 설명한다. RISC-V는 base instruction set 외에도 여러 optional instruction set이 있으나, 기본이 되는 RV32I base instruction set만 다룬다.

Download Link ▶ RISC-V Spec : ISA Specification의 Volume 1, Unprivileged Spec에 RV32I instruction set Spec이 포함되어 있다.

RISC-V integer register

* reference : RISC-V Volume 1, Unprivileged Spec의 "Table 25.1: Assembler mnemonics for RISC-V integer and floating-point registers, and their role in the first standard calling convention."의 integer register 부분만 그대로 copy

Register ABI Name Description Saver
x0 zero Hard-wired zero
x1 ra Return address Caller
x2 sp Stack pointer Callee
x3 gp Global pointer
x4 tp Thread pointer
x5 t0 Temporary/alternate link register Caller
x6–7 t1–2 Temporaries Caller
x8 s0/fp Saved register/frame pointer Callee
x9 s1 Saved register Callee
x10–11 a0–1 Function arguments/return values Caller
x12–17 a2–7 Function arguments Caller
x18–27 s2–11 Saved registers Callee
x28–31 t3–6 Temporaries Caller

RV32I 어셈블리 명령어

* reference : 아래 Link의 문서를 base로 조금 수정을 했다.

대부분 C언어 문법으로 어셈블리 명령어 동작을 표현했으며, 몇 가지 용어를 먼저 설명하고 RV32I 어셈블리 명령어를 설명한다.
  • rd : destination register
  • rs1, rs2 : source register
  • immediate(즉치값) : 상수값이며 imm12는 12bit 상수값을 의미함
  • M[0x100] : memory의 0x100 번지를 의미함
  • rs1[7:0] : rs1의 0번 bit부터 7번 bit(하위 8bit)
  • 포스팅 ▶ 부호 확장(sign extension)과 제로 확장(zero extension)
  • sext : sign extention
  • zext : zero extention
  • PC(Program Counter)
    PC는 CPU 내부 register이며, 다음에 실행될 명령어의 주소를 가리킨다. 예를 들어 [beq rs1, rs2, imm13]은 rs1과 rs2가 같으면 PC에 [PC+imm13]의 값을 넣어서 [PC+imm13] 위치로 프로그램이 이동한다.
명령어 Full Name 설명
add rd, rs1, rs2 ADD rd = rs1 + rs2
sub rd, rs1, rs2 SUB rd = rs1 - rs2
xor rd, rs1, rs2 XOR rd = rs1 ˆ rs2
or rd, rs1, rs2 OR rd = rs1 | rs2
and rd, rs1, rs2 AND rd = rs1 & rs2
sll rd, rs1, rs2 Shift Left Logical rd = rs1 << rs2[4:0]
srl rd, rs1, rs2 Shift Right Logical rd = rs1 >> rs2[4:0]
sra rd, rs1, rs2 Shift Right Arithmetic rd = rs1 >> rs2[4:0]; shift 하고 빈 자리에 기존의 최상위 bit를 복사
slt rd, rs1, rs2 Set Less Than signed 비교, rd = (rs1 < rs2)?1:0
sltu rd, rs1, rs2 Set Less Than Unsigned unsigned 비교, rd = (rs1 < rs2)?1:0
addi rd, rs1, imm12 ADD Immediate rd = rs1 + sext(imm12)
xori rd, rs1, imm12 XOR Immediate rd = rs1 ˆ sext(imm12)
ori rd, rs1, imm12 OR Immediate rd = rs1 | sext(imm12)
andi rd, rs1, imm12 AND Immediate rd = rs1 & sext(imm12)
slli rd, rs1, imm5 Shift Left Logical Immediate rd = rs1 << imm5
srli rd, rs1, imm5 Shift Right Logical Immediate rd = rs1 >> imm5
srai rd, rs1, imm5 Shift Right Arithmetic Immediate rd = rs1 >> imm5
slti rd, rs1, imm12 Set Less Than Immediate signed 비교, rd = (rs1 < sext(imm12))?1:0
sltiu rd, rs1, rs2 Set Less Than Immediate Unsigned unsigned 비교, rd = (rs1 < sext(imm12))?1:0
lb rd, imm12(rs1) Load Byte rd = sext(M[rs1+sext(imm12)][7:0])
lh rd, imm12(rs1) Load Half rd = sext(M[rs1+sext(imm12)][15:0])
lw rd, imm12(rs1) Load Word rd = M[rs1+sext(imm12)]
lbu rd, imm12(rs1) Load Byte Unsigned rd = zext(M[rs1+sext(imm12)][7:0])
lhu rd, imm12(rs1) Load Half Unsigned rd = zext(M[rs1+sext(imm12)][15:0])
sb rs2, imm12(rs1) Store Byte M[rs1+sext(imm12)][7:0] = rs2[7:0]
sh rs2, imm12(rs1) Store Half M[rs1+sext(imm12)][15:0] = rs2[15:0]
sw rs2, imm12(rs1) Store Word M[rs1+sext(imm12)] = rs2
beq rs1, rs2, ①imm13 Branch Equal if(rs1 == rs2) PC += sext(imm13)
bne rs1, rs2, ①imm13 Branch Unequal signed 비교, if(rs1 != rs2) PC += sext(imm13)
blt rs1, rs2, ①imm13 Branch Less Than signed 비교, if(rs1 < rs2) PC += sext(imm13)
bge rs1, rs2, ①imm13 Branch Greater Equal signed 비교, if(rs1 >= rs2) PC += sext(imm13)
bltu rs1, rs2, ①imm13 Branch Less Than Unsigned unsigned 비교, if(rs1 < rs2) PC += sext(imm13)
bgeu rs1, rs2, ①imm13 Branch Greater Equal Unsigned unsigned 비교, if(rs1 >= rs2) PC+= sext(imm13)
jal rd, ②imm21 Jump And Link rd = PC+4; PC += sext(imm21)
jalr rd, rs1, imm12 Jump And Link Register rd = PC+4; PC = (rs1 + sext(imm12)) & ~1
lui rd, imm20 Load Upper Immediate rd = imm20 << 12
auipc rd, imm20 Add Upper Immediate to PC rd = PC + (imm20 << 12)
fence Fence device I/O와 memory 접근의 순서를 지킴
ecall Environment Call trap을 발생시켜서 OS에 control을 넘기는 용도로 사용
ebreak Environment Break trap을 발생시켜서 debugger에 control을 넘기는 용도로 사용
① imm13 : 하위 1비트는 무조건 0
② imm21 : 하위 1비트는 무조건 0


의사 명령어(pseudo instruction)

* reference : 아래 링크의 "A listing of standard RISC-V pseudoinstructions"의 integer 명령어만 그대로 copy

Instruction Set에 있는 명령어는 아니나 어셈블리에서 사용자의 편의를 위해 사용하는 명령어고, 해당 명령어는 Instruction Set에 있는 명령어로 변환된다.

* XLEN : integer register 크기, RV32는 32
Pseudoinstruction Base Instruction(s) Meaning
la rd, symbol auipc rd, symbol[31:12]; addi rd, rd, symbol[11:0] Load address
l{b|h|w|d} rd, symbol auipc rd, symbol[31:12]; l{b|h|w|d} rd, symbol[11:0](rd) Load global
s{b|h|w|d} rd, symbol, rt auipc rt, symbol[31:12]; s{b|h|w|d} rd, symbol[11:0](rt) Store global
nop addi x0, x0, 0 No operation
li rd, immediate Myriad sequences Load immediate
mv rd, rs addi rd, rs, 0 Copy register
not rd, rs xori rd, rs, -1 Ones’ complement
neg rd, rs sub rd, x0, rs Two’s complement
negw rd, rs subw rd, x0, rs Two’s complement word
sext.b rd, rs slli rd, rs, XLEN - 8; srai rd, rd, XLEN - 8 Sign extend byte
sext.h rd, rs slli rd, rs, XLEN - 16; srai rd, rd, XLEN - 16 Sign extend half word
sext.w rd, rs addiw rd, rs, 0 Sign extend word
zext.b rd, rs andi rd, rs, 255 Zero extend byte
zext.h rd, rs slli rd, rs, XLEN - 16; srli rd, rd, XLEN - 16 Zero extend half word
zext.w rd, rs slli rd, rs, XLEN - 32; srli rd, rd, XLEN - 32 Zero extend word
seqz rd, rs sltiu rd, rs, 1 Set if = zero
snez rd, rs sltu rd, x0, rs Set if != zero
sltz rd, rs slt rd, rs, x0 Set if < zero
sgtz rd, rs slt rd, x0, rs Set if > zero
beqz rs, offset beq rs, x0, offset Branch if = zero
bnez rs, offset bne rs, x0, offset Branch if != zero
blez rs, offset bge x0, rs, offset Branch if ≤ zero
bgez rs, offset bge rs, x0, offset Branch if ≥ zero
bltz rs, offset blt rs, x0, offset Branch if < zero
bgtz rs, offset blt x0, rs, offset Branch if > zero
bgt rs, rt, offset blt rt, rs, offset Branch if >
ble rs, rt, offset bge rt, rs, offset Branch if ≤
bgtu rs, rt, offset bltu rt, rs, offset Branch if >, unsigned
bleu rs, rt, offset bgeu rt, rs, offset Branch if ≤, unsigned
j offset jal x0, offset Jump
jal offset jal x1, offset Jump and link
jr rs jalr x0, rs, 0 Jump register
jalr rs jalr x1, rs, 0 Jump and link register
ret jalr x0, x1, 0 Return from subroutine
call offset auipc x6, offset[31:12]; jalr x1, x6, offset[11:0] Call far-away subroutine
tail offset auipc x6, offset[31:12]; jalr x0, x6, offset[11:0] Tail call far-away subroutine
fence fence iorw, iorw Fence on all memory and I/O

* Feedback은 언제나 환영합니다.

Comments

  1. 간결하고 유용한 자료 감사합니다.

    ReplyDelete
    Replies
    1. lui rd, rs1, imm20 부분에서 rs1은 없어야 되는게 아닌가합니다.

      Delete
    2. 잘못봤네요. rs1은 << 할 값이 들어 있겠군요.

      Delete
    3. lui rd, rs1, imm20 -> lui rd, imm20 으로 변경했습니다.
      감사합니다.

      Delete

Post a Comment