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
* 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은 언제나 환영합니다.
간결하고 유용한 자료 감사합니다.
ReplyDeletelui rd, rs1, imm20 부분에서 rs1은 없어야 되는게 아닌가합니다.
Delete잘못봤네요. rs1은 << 할 값이 들어 있겠군요.
Deletelui rd, rs1, imm20 -> lui rd, imm20 으로 변경했습니다.
Delete감사합니다.