os-workshop

same materials and sample source for RV32 OS projects
git clone http://frotz.net/git/os-workshop.git
Log | Files | Refs

riscv-assembly.md (7347B)


      1 # RISCV Assembly Language
      2 
      3 The core 32bit integer instruction set for RISCV is pretty small:
      4 
      5 | instruction | description | function |
      6 | -- | -- | -- |
      7 | addi rd, rs1, s12 | add immediate | rd = rs1 + s12 |
      8 | slti rd, rs1, s12 | set less than immediate | rd = (s32)rs1 < (s32)s12 ? 1 : 0 |
      9 | sltui rd, rs1, s12 | set less than unsigned imm | rd = (u32)rs1 < (u32)s12 ? 1 : 0 |
     10 | andi rd, rs1, s12 | logical and immediate | rd = rs1 & s12 |
     11 | ori rd, rs1, s12 | logical or immediate | rd = rs1 | s12 |
     12 | xori rd, rs1, s12 | logical xor immediate | rd = rs1 ^ s12 |
     13 | slli rd, rs1, u5 | logical left shift imm | rd = rs1 << u5 |
     14 | srli rd, rs1, u5 | logical right shift imm | rd = (u32)rs >> u5 |
     15 | srai rd, rs1, u5 | arithmetic right shift imm | rd = (s32)rs >> u5 |
     16 | lui rd, u20 | load upper immediate | rd = u20 << 12 |
     17 | auipc rd, u20 | add upper imm to pc | rd = pc + (u20 << 12) |
     18 | add rd, rs1, rs2 | addition | rd = rs1 + rs2 |
     19 | slt rd, rs1, rs2 | set if less than (signed) | rd = (s32)rs1 < (s32)rs2 ? 1 : 0 ) |
     20 | sltu rd, rs1, rs2 | set if less than (unsigned) | rd = (u32)rs1 < (u32)rs2 ? 1 : 0 |
     21 | and rd, rs1, rs2 | logical and | rd = rs1 & rs2 |
     22 | or rd, rs1, rs2 | logical or | rd = rs1 | rs2 |
     23 | xor rd, rs1, rs2 | logical xor | rd = rs1 ^ rs2 |
     24 | sll rd, rs1, rs2 | logical shift left | rd = rs1 << (rs2 & 0x1F) |
     25 | srl rd, rs1, rs2 | logical shift right | rd = rs1 >> (rs2 & 0x1F) |
     26 | sub rd, rs1, rs2 | subtraction | rd = rs1 + rs2 |
     27 | sra rd, rs1, rs2 | arithmetic shift right | rd = (s32)rs1 >> (rs2 & 0x1F) |
     28 | jal rd, addr | jump and link | rd = pc + 4, pc = addr [1] | 
     29 | jalr rd, rs1, s12 | jump and link register | rd = pc + 4, pc = (rs1 + s12) & ~1 |
     30 | beq rs1, rs2, addr | branch if equal | if rs1 == rs2 then pc = addr [2] |
     31 | bne rs1, rs2, addr | branch if not equal | if rs1 != rs2 then pc = addr [2] |
     32 | blt rs1, rs2, addr | branch if less than| if rs1 < rs2 then pc = addr [2] |
     33 | bltu rs1, rs2, addr | branch if less than (unsigned) | if rs1 < rs2 then pc = addr [2] |
     34 | bge rs1, rs2, addr | branch if >= | if rs1 >= rs2 then pc = addr [2] |
     35 | bgeu rs1, rs2, addr | branch if >= (unsigned) | if rs1 >= rs2 then pc = addr [2] |
     36 | lw rd, s12(rs1) | load word | rd = *((u32*) (rs1 + s12)) |
     37 | lh rd, s12(rs1) | load halfword | rd = *((u16*) (rs1 + s12)) |
     38 | lb rd, s12(rs1) | load byte | rd = *((u8*) (rs1 + s12)) |
     39 | sw rs2, s12(rs1) | store word | *((u32*) (rs1 + s12)) = rs2 |
     40 | sh rs2, s12(rs1) | store halfword | *((u16*) (rs1 + s12)) = rs2 |
     41 | sb rs2, s12(rs1) | store byte | *((u8*) (rs1 + s12)) = rs2 |
     42 | fence | memory ordering | |
     43 | ecall | service call | trap to higher processor mode |
     44 | ebreak | hardware breakpoint | return control to debugger |
     45 | csrrw rd, csr, rs1 | csr atomic read/write | rd = csr, csr = rs1 |
     46 | csrrs rd, csr, rs1 | csr atomic read/set | rd = csr, csr |=  rs1 |
     47 | csrrc rd, csr, rs1 | csr atomic read/clear | rd = csr, csr &= ~rs1 |
     48 | csrrwi rd, csr, u5 | csr atomic read/write imm | rd = csr, csr = u5 |
     49 | csrrsi rd, csr, u5 | csr atomic read/set imm | rd = csr, csr |= u5 |
     50 | csrrci rd, csr, u5 | csr atomic read/clear imm | rd = csr, csr &= ~u5 |
     51 
     52 The assembler and diassembler recognize a number of useful pseudo instructions which put friendly names (and/or shorter forms) on many common use cases.  For example there is a BLT (branch if less than) instruction, but not a BGT instruction, but the assembler treats BGT as an alias for BLT with the arguments swapped.
     53 
     54 | pseudo instruction | alias for | description | function |
     55 | ------------------ | --------- | ----------- | -------- |
     56 | nop | addi x0, x0, 0 | nop | nop | - |
     57 | j addr | jal x0, addr | jump | pc = addr [1] |
     58 | jal addr | jal x1, offset | jump and link | x1 = pc + 4, pc = addr [1] |
     59 | jr rs | jalr x0, 0(rs) | jump register | pc = rs |
     60 | jalr rs | jalr x1, 0(rs) | jump and link register | x1 = pc + 4, pc = rs |
     61 | ret | jalr x0, 0(x1) | return | pc = x1 |
     62 | call addr | auipc x1, offhi ; jalr x1, offlo(x1) | far call | pc = addr |
     63 | li rd, imm | various forms | load immediate | rd = imm |
     64 | mv rd, rs | addi rd, rs, 0 | move | rd = rs |
     65 | not rd, rs | xori rd, rs, -1 | logical not | rd = ~rs |
     66 | neg rd, rs | sub rd, x0, rs | negate | rd = -rs |
     67 | seqz rd, rs | sltiu rd, rs, 1 | set if equal zero | rd = rs == 0 ? 1 : 0 |
     68 | snez rd, rs | sltu rd, x0, rs | set if not equal zero | rd = rs != 0 ? 1 : 0 |
     69 | sltz rd, rs | slt rd, rs, x0 | set if < zero | rd = rs < 0 ? 1 : 0 |
     70 | sgtz rd, rs | slt rd, x0, rs | set if > zero | rd = rs > 0 ? 1 : 0 |
     71 | beqz rs, addr | beq rs, x0, addr | branch if equal zero | if rs == 0 then pc = addr [2] |
     72 | bnez rs, addr | bne rs, x0, addr | branch if not zero | if rs != 0 then pc = addr [2] |
     73 | blez rs, addr | bge x0, rs, addr | branch if <= zero | if rs <= 0 then pc = addr [2] |
     74 | bgez rs, addr | bge rs, x0, addr | branch if >= zero | if rs >= 0 then pc = addr [2] |
     75 | bltz rs, addr | blt rs, x0, addr | branch if < zero | if rs < 0 then pc = addr [2] |
     76 | bgtz rs, addr | blt x0, rs, addr | branch if > zero | if rs > 0 then pc = addr [2] |
     77 | bgt rs, rt, addr | blt rt, rs, addr | branch if greater | if rs > rt then pc = addr [2] |
     78 | blt rs, rt, addr | bge rt, rs, addr | branch if <= | if rs <= rt then pc = addr [2] |
     79 | bgtu rs, rt, addr | bltu rt, rs, addr | branch if > (unsigned) | if rs > rt then pc = addr [2] |
     80 | bleu rs, rt, addr | bgeu rt, rs, addr | branch if <= (unsigned) | if rs <= rt then pc = addr [2] |
     81 | csrr rd, csr | csrrs rd, csr, x0 | read csr | rd = csr |
     82 | csrw csr, rs | csrrw x0, csr, rs | write csr | csr = rs |
     83 | csrs csr, rs | csrrs x0, csr, rs | set csr bits | csr |= rs |
     84 | csrc csr, rs | csrrc x0, csr, rs | clear csr bits | csr &= ~rs |
     85 | csrwi csr, u5 | csrrwi x0, csr, u5 | write csr imm | csr = u5 |
     86 | csrsi csr, u5 | csrrsi x0, csr, u5 | set csr bits imm | csr |= u5 |
     87 | csrci csr, u5 | csrrci x0, csr, u5 | clear csr bits imm | csr &= ~u5 |
     88 
     89 [1] addr is encoded as a signed 21bit value, allowing a range of +/- 1MB from the pc
     90 
     91 [2] addr is encoded as a signed 12bit value, allowing a range of +/- 4KB from the pc
     92 
     93 
     94 RISCV has 32 integer registers (x0 - x31), but the assembler and disassembler recognize and use aliases for these names which indicate what role they serve in the standard ABI.  Register x0 always reads as zero and writes to it are discarded. There is also a program counter (pc).
     95 
     96 | register | alias | description | saver |
     97 | -------- | ----- | ----------- | ----- |
     98 | x0 | zero | hard-wired zero | - |
     99 | x1 | ra | return address | caller |
    100 | x2 | sp | stack pointer | callee |
    101 | x3 | gp | global pointer | - |
    102 | x4 | tp | thread pointer | - |
    103 | x5 | t0 | temporary | caller |
    104 | x6 - x7 | t1 - t2 | temporaries | caller |
    105 | x8 | s0 / fp | saved register / frame pointer | callee |
    106 | x9 | s1 | saved register | callee |
    107 | x10 - x11 | a0 - a1 | arguments / return values | caller |
    108 | x12 - x17 | a2 - a7 | arguments | caller |
    109 | x18 - x27 | s2 - s11 | saved registers | callee |
    110 | x28 - x31 | t3 - t6 | temporaries | caller |
    111 | pc | - | program counter | - |
    112 
    113 
    114 | symbol | meaning | range |
    115 | ------ | ------- | ----- |
    116 | rd | destination register (written to) | x0 .. x31  |
    117 | rs1 | first source register | x0 .. x31 |
    118 | rs2 | second source register | x0 .. x31 |
    119 | s12 | 12bit signed immediate | -2048 .. 2047 |
    120 | u5 | unsigned 5bit immediate | 0 .. 31 |
    121 | csr | control/status register number | 0 .. 4095 |
    122