-
Notifications
You must be signed in to change notification settings - Fork 0
Assembly Structure
Before beginning you own programs it is recommended to install Notepad++ for the syntax highlight as described in the first steps
To create a new program for the architecture, you will need to create a file on a folder visible to the assembler. In this repository, this folder is located at DRISC Programs/src/. The file also should have the .dasm extension.
After opening the file with Notepad++, you will need to manually change the language to dasm in Language > dasm and you are ready to begin writing your program.
The syntax used in DRISC-V Assembly is similar to other RISC-V assembly formats, but there are a few key differences.
First, you are not required to use commas (,) between parameters in instructions. Parameters are simply separated by spaces. Additionally, offsets are declared after the register containing the address, as shown in the instruction list below.
There are also small differences in how labels and variable addresses are referenced, as well as in other assembly features.
To write an instruction, you typically start with its name, followed by its parameters. For example:
sw s0 s1 3
In DRISC-V syntax, the immediate value is always the last parameter, while the others are almost always registers.
The following instruction table contains the name of every instruction available in the current assembler, along with the parameters required for each to function properly. The parameters you will encounter are:
rd, rs, rs1, and rs2: These are, respectively, the destination and source registers. You can either use the ABI names for the registers or simply use xN, where N is the register number.
imm: This is an immediate value, which can be written as a hexadecimal (e.g., 0xAf24) or as a regular signed decimal integer. You may also use labels or variable addresses if needed.
label: A label is an address marker in your code. To define one, write :Name_Of_The_Label on an empty line. To use it as a parameter, write it the same way. For variables, which will be discussed later, use a . instead of a :.
offset: Similar to imm, but this value will be added to a register containing an address. You can think of it like an array index in C (array[index]).
csr: This can be the name of any CSR listed here.
When reading instruction names, certain suffixes can give you clues about their behavior:
-
I: Usually stands for Immediate. It often refers to an OP-IMM instruction, meaning it uses an immediate value as one of its operands. -
U: Typically means Unsigned. In this case, the last bit is treated as a regular digit rather than a sign bit. -
Z: Refers to Zero, often indicating that a register or value is expected to be zero. -
B: Stands for Byte (8 bits). -
H: Stands for Half-word (16 bits). -
W: Stands for Word (32 bits). -
GEGTLELT: Those are respectively greater equal, greater than, less equal and less than.
Understanding these suffixes can help you quickly identify the purpose and behavior of instructions in the assembler.
| Instruction | Parameters | Behavior | Notes |
|---|---|---|---|
| LUI | rd imm | rd <= imm << 12 | Load upper immediate |
| LI | rd imm | rd <= imm(32 bit) | Load immediate (pseudo) |
| LA | rd label | rd <= label(32 bit) | Load address (pseudo) |
| AUIPC | rd imm | rd <= PC + (imm << 12) | Add upper immediate to PC |
| NOP | — | — | No operation |
| MV | rd rs | rd <= rs | Move register (pseudo) |
| ECALL | — | Environment call | Triggers a System call |
| EBREAK | — | Breakpoint | Triggers a Breakpoint exception |
| MRET | — | PC < mepc; p < pp | Used to return from the trap Handler or to go to user mode |
| Instruction | Parameters | Behavior | Notes |
|---|---|---|---|
| J | label | PC <= label | Unconditional jump |
| JUMP | label | PC <= label | Same as J |
| JR | rs | PC <= rs | Jump to register |
| JAL | rd label | rd <= Next PC ; PC <= label | Jump and link |
| JALR | rd rs1 imm | rd <= Next PC ; PC <= rs1 + imm | Jump and link register |
| CALL | label | ra <= Next PC ; PC <= label | Call subroutine |
| RET | — | PC <= ra | Return from subroutine |
| Instruction | Parameters | Behavior |
|---|---|---|
| BEQ | rs1 rs2 label | if(rs1 == rs2) PC <= label |
| BNE | rs1 rs2 label | if(rs1 != rs2) PC <= label |
| BLE | rs1 rs2 label | if(rs1 <= rs2) PC <= label |
| BLT | rs1 rs2 label | if(rs1 < rs2) PC <= label |
| BGE | rs1 rs2 label | if(rs1 >= rs2) PC <= label |
| BGT | rs1 rs2 label | if(rs1 > rs2) PC <= label |
| BLEU | rs1 rs2 label | if(rs1 <= rs2) (unsigned) PC <= label |
| BLTU | rs1 rs2 label | if(rs1 < rs2) (unsigned) PC <= label |
| BGEU | rs1 rs2 label | if(rs1 >= rs2) (unsigned) PC <= label |
| BGTU | rs1 rs2 label | if(rs1 > rs2) (unsigned) PC <= label |
| ------------- | --------------------- | --------------------------------------------- |
| BEQZ | rs1 label | if(rs1 == 0) PC <= label |
| BNEZ | rs1 label | if(rs1 != 0) PC <= label |
| BLTZ | rs1 label | if(rs1 < 0) PC <= label |
| BGEZ | rs1 label | if(rs1 >= 0) PC <= label |
| BGTZ | rs1 label | if(rs1 > 0) PC <= label |
| BLEZ | rs1 label | if(rs1 <= 0) PC <= label |
| Instruction | Parameters | Behavior | Notes |
|---|---|---|---|
| LB | rd rs1 offset | rd <= sign_extend(mem[rs1 + offset]) | Load Byte |
| LBU | rd rs1 offset | rd <= zero_extend(mem[rs1 + offset]) | Load Byte Unsigned |
| LH | rd rs1 offset | rd <= sign_extend(mem[rs1 + offset]) | Load Half |
| LHU | rd rs1 offset | rd <= zero_extend(mem[rs1 + offset]) | Load Half Unsigned |
| LW | rd rs1 offset | rd <= mem[rs1 + offset] | Load Word |
| SB | rs2 rs1 offset | mem[rs1 + offset] <= rs2 (byte) | Store Byte |
| SH | rs2 rs1 offset | mem[rs1 + offset] <= rs2 (halfword) | Store Half |
| SW | rs2 rs1 offset | mem[rs1 + offset] <= rs2 (word) | Store Word |
Note: Although Division and Remainder instructions are supported by the assembler, the current version of DRISC-V do not support it and may have undefined behavior.
| Instruction | Parameters | Behavior |
|---|---|---|
| ADDI | rd rs1 imm | rd <= rs1 + imm |
| ADD | rd rs1 rs2 | rd <= rs1 + rs2 |
| SUB | rd rs1 rs2 | rd <= rs1 - rs2 |
| MUL | rd rs1 rs2 | rd <= rs1 * rs2 |
| MULH | rd rs1 rs2 | rd <= signed_high(rs1 × rs2) |
| MULHSU | rd rs1 rs2 | rd <= signed_unsigned_high(rs1 × rs2) |
| MULHU | rd rs1 rs2 | rd <= unsigned_high(rs1 × rs2) |
| DIV | rd rs1 rs2 | rd <= rs1 / rs2 |
| DIVU | rd rs1 rs2 | rd <= rs1 / rs2 (unsigned) |
| REM | rd rs1 rs2 | rd <= rs1 % rs2 |
| REMU | rd rs1 rs2 | rd <= rs1 % rs2 (unsigned) |
| INC | rd imm | rd <= rd + imm |
| DEC | rd imm | rd <= rd - imm |
| Instruction | Parameters | Behavior |
|---|---|---|
| ANDI | rd rs1 imm | rd <= rs1 & imm |
| ORI | rd rs1 imm | rd <= rs1 | imm |
| XORI | rd rs1 imm | rd <= rs1 ^ imm |
| AND | rd rs1 rs2 | rd <= rs1 & rs2 |
| OR | rd rs1 rs2 | rd <= rs1 | rs2 |
| XOR | rd rs1 rs2 | rd <= rs1 ^ rs2 |
| NOT | rd rs | rd <= ~rs |
| Instruction | Parameters | Behavior |
|---|---|---|
| SLTI | rd rs1 imm | rd <= (rs1 < imm) ? 1 : 0 |
| SLTIU | rd rs1 imm | rd <= (rs1 < imm) ? 1 : 0 unsigned |
| SLT | rd rs1 rs2 | rd <= (rs1 < rs2) ? 1 : 0 |
| SLTU | rd rs1 rs2 | rd <= (rs1 < rs2) ? 1 : 0 unsigned |
| SGTI | rd rs1 imm | rd <= (rs1 > imm) ? 1 : 0 |
| SGTIU | rd rs1 imm | rd <= (rs1 > imm) ? 1 : 0 unsigned |
| SGT | rd rs1 rs2 | rd <= (rs1 > rs2) ? 1 : 0 |
| SGTU | rd rs1 rs2 | rd <= (rs1 > rs2) ? 1 : 0 unsigned |
| SEQZ | rd rs | rd <= (rs == 0) ? 1 : 0 |
| SNEZ | rd rs | rd <= (rs != 0) ? 1 : 0 |
| SLTZ | rd rs | rd <= (rs < 0) ? 1 : 0 |
| SGTZ | rd rs | rd <= (rs > 0) ? 1 : 0 |
| Instruction | Parameters | Behavior |
|---|---|---|
| SLLI | rd rs1 imm | rd <= rs1 << imm |
| SRLI | rd rs1 imm | rd <= rs1 >> imm |
| SRAI | rd rs1 imm | rd <= rs1 >>> imm |
| SLL | rd rs1 rs2 | rd <= rs1 << rs2 |
| SRL | rd rs1 rs2 | rd <= rs1 >> rs2 |
| SRA | rd rs1 rs2 | rd <= rs1 >>> rs2 |
| Instruction | Parameters | Behavior |
|---|---|---|
| SEXT.B | rd rs | sign-extend byte |
| SEXT.H | rd rs | sign-extend halfword |
| ZEXT.B | rd rs | zero-extend byte |
| ZEXT.H | rd rs | zero-extend halfword |
| Instruction | Parameters | Behavior |
|---|---|---|
| CSRR | rd csr | rd <= CSR[csr] |
| CSRW | csr rs | CSR[csr] <= rs |
| CSRS | csr rs | CSR[csr] |
| CSRC | csr rs | CSR[csr] &= ~rs |
| CSRRW | rd csr rs | rd <= CSR[csr] <= rs |
| CSRRS | rd csr rs | rd <= CSR[csr] |
| CSRRC | rd csr rs | rd <= CSR[csr] &= ~rs |
| CSRWI | csr imm | CSR[csr] <= imm |
| CSRSI | csr imm | CSR[csr] |
| CSRCI | csr imm | CSR[csr] &= ~imm |
| CSRRWI | rd csr imm | rd <= CSR[csr] <= imm |
| CSRRSI | rd csr imm | rd <= CSR[csr] |
| CSRRCI | rd csr imm | rd <= CSR[csr] &= ~imm |
-
- 1.1 Introduction
- 1.2 RISC-V Implementation
- 1.2.1 Available Instruction Set
- 1.2.2 Available Non-ISA Features
-
- 2.1 ALU
- 2.2 Register File
- 2.3 Program Counter
- 2.4 Input Buffer
- 2.5 RAM
- 2.6 Operation Controller
- 2.7 CSR Controller
-
- 3.1 Input Devices
- 3.1.1 Keyboard
- 3.1.2 Switches and Joystick
- 3.1.3 Random Number Generator
- 3.1.4 Real-Time Device
- 3.2 Output Devices
- 3.2.1 Screen
- 3.2.2 Terminal
- 3.2.3 Software Interrupt Register
- 3.1 Input Devices