https://github.com/wooster0/rva
RISC-V Assembler with execution of code at assembly-time
https://github.com/wooster0/rva
assembler comptime riscv riscv-assembly riscv32 riscv64 rva
Last synced: 8 months ago
JSON representation
RISC-V Assembler with execution of code at assembly-time
- Host: GitHub
- URL: https://github.com/wooster0/rva
- Owner: wooster0
- Created: 2025-02-20T09:40:24.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-02-20T09:49:33.000Z (8 months ago)
- Last Synced: 2025-02-20T10:34:33.585Z (8 months ago)
- Topics: assembler, comptime, riscv, riscv-assembly, riscv32, riscv64, rva
- Language: Zig
- Homepage:
- Size: 0 Bytes
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# rva
This is a general-purpose RISC-V assembler.
* Supports labels, directives, and other standard features
* Extensible: instructions and pseudoinstructions are not part of the assembler itself but are instead supplied using external standard files:
Example from `standard/rv32i.asm`:
```
@instruction beq b [0b1100011, 0b000]
@instruction bne b [0b1100011, 0b001]
@instruction blt b [0b1100011, 0b100]
@instruction bge b [0b1100011, 0b101]
@instruction bltu b [0b1100011, 0b110]
@instruction bgeu b [0b1100011, 0b111]
```
Example from `standard/pseudoinstructions.asm`:
```
@pseudoinstruction nop {
addi zero, zero, 0
}
@pseudoinstruction li {
addi $$.0, zero, $$.1
}
```
* Supports execution of instructions and code inside `@invoke` blocks at assembly time.
All instructions part of RV32I, RV32M, RV64I, and RV64M are executable at assembly time.
This for example lets you print out values before running the code, using the `@log` directive:
```
@log (5 + 5) * 20
```
A common problem assemblers have is that they have no easy way of letting you inspect constants or macros.
RVA does not have macros; its answer to metaprogramming is assembly time.For more documentation see `documentation.txt`, `examples/`, and `tests.zig`.
The internal pipeline works as follows:
1. main.zig: Take the source code.
2. Tokenizer: Pass it into a tokenizer without producing any tokens yet.
3. Parser.zig: Parse the tokens into commands. Tokens are produced on the go. Look-ahead of up to one token is supported.
A command represents directives, instructions, pseudoinstructions, arithmetic, and operations on values.
4. Assembler.zig: This is where assembly time execution happens. Any code inside `@invoke` blocks is invoked and executed right there and then at assembly time.
All the rest that is not invoked gets emitted to the final binary, as machine code.Unfortunately assembly time execution has some limitations in regard to mutating memory at assembly time which means it has limited usefulness for
creating structures, tables, data, etc. at assembly time.
The assembler is nonetheless in a useable state.