Files
a-machine/README.md
T

77 lines
5.3 KiB
Markdown
Raw Normal View History

2026-06-18 19:10:32 +03:00
# A-machine: a minimal RISC-V (RV32IMAC) emulator in POSIX AWK
2026-06-18 14:01:36 +03:00
## About
2026-06-18 19:10:32 +03:00
A-machine is a simple and straightforward implementation of the RV32I specification with M (multiplication/division), A (atomic operations), and C (compressed instructions) extensions. It consists of two files:
2026-06-18 14:01:36 +03:00
- [amach.awk](amach.awk), the emulator core itself that supports .dec files,
- and [amach](amach) shell script which is a two-liner that uses POSIX `od` to convert .bin files into .dec files on the fly and then passes them to the emulator core.
2026-06-18 19:54:49 +03:00
Additionally, A-machine is shipped with a reference test suite that assumes that you have a full RISC-V toolchain installed under the `riscv64-linux-gnu-` prefix (adjustable in the `Makefile`). Just run `make run` to build and run all tests. In case you don't have any toolchain available, two files called `rv32imac_tests.bin` and `rv32imac_syscall_tests.bin` are also included into the repo.
2026-06-18 14:01:36 +03:00
The project is to be considered highly experimental and not production-ready in any way.
## Usage
First, decide where your program needs to be loaded in memory. The default LVA (loading virtual address) is 0x100b0. In most AWK implementations, you need to convert this value to decimal (the default is 65712).
Then, most probably, you'll want to use the provided wrapper:
```sh
[LVA=...] ./amach path/to/program.bin
```
Or you can run the following:
```sh
od -An -v -tu1 path/to/program.bin | POSIXLY_CORRECT=1 awk -f amach.awk [-v LVA=...]
```
But in case you already have a program in the `.dec` format, you can pass it directly to AWK:
```sh
POSIXLY_CORRECT=1 awk -f amach.awk [-v LVA=...] -- path/to/program.dec
```
## Support
2026-06-18 19:54:49 +03:00
Currently, A-machine only supports the **unprivileged** RV32IMAC instruction set with an extended subset of POSIX/Linux-compatible `ecall` system calls (using standard `asm-generic` numbers):
- **Process Control**: `sys_exit` (93), `sys_exit_group` (94).
- **File & Directory I/O**: `sys_openat` (56), `sys_close` (57), `sys_read` (63), `sys_write` (64), `sys_lseek` (62). Multiple file descriptors (with full path resolution, creation/truncation flags, and offset tracking) are supported for files and directories.
- **Directory Operations**: `sys_mkdirat` (34), `sys_unlinkat` (35) (including directory removal), `sys_renameat` (38) / `sys_renameat2` (276), `sys_getdents64` (61) (for listing directory contents).
- **File Metadata & Links**: `sys_newfstatat` (79), `sys_fstat` (80), `sys_readlinkat` (78).
- **System Time & Entropy**: `sys_clock_gettime` (113), `sys_clock_gettime64` (403), `sys_gettimeofday` (169), and `sys_getrandom` (278).
For completeness, `fence` instruction is also supported but yields a no-op, and both `ebreak` and `c.ebreak` are supported to halt execution with a debug message.
2026-06-18 14:01:36 +03:00
## Plans (from higher to lower priority)
- Implement a simple RV32IMAC disassembler in POSIX AWK.
- Test for RV32EMC compatibility (that the code built for the "embedded" variant runs here).
- Implement a privileged instruction set minimum (Zicsr), interrupts and traps.
- If time permits, implement a simple RV32IMAC assembler in POSIX AWK, with full pseudo-instruction support.
## FAQ
### What was the rationale of creating a platform emulator in the least suitable language for this purpose?
The main reason is maximum portability. While AWK is clearly tailored for text processing and, in its standard variant, doesn't even has bitwise operations and hexadecimal literals support, it still remains the single most common scripting language present on every POSIX-compatible system, including embedded ones that run [BusyBox](https://busybox.net/) on top of the kernel and might not have anything else from available programming tools at all. In such conditions, an emulation layer written in AWK is far from efficient but still better than nothing.
Apart from that, the A-machine serves more of an educational purpose for the author to learn about the RISC-V ISA and the details of its inner workings.
### Will I be able to run a Linux kernel on A-machine?
While A-Machine creation was partially inspired by the wonderful [mini-rv32ima project](https://github.com/cnlohr/mini-rv32ima) (although not a single line of code had been taken from there), running a (no-MMU) Linux kernel here is not currently possible due to several reasons. First, A-machine needs to support Zicsr and other privileged RV32 extensions to even theoretically be capable of running the kernel. Second, in order to run the same kernel build as mini-rv32ima does, A-machine will need to support the exact same MMIO model and non-standard CSR calls as mini-rv32ima, which already is non-trivial and will indeed require some logic copy-pasting, which the author is trying to avoid.
So, the answer is: no, not anytime soon.
### 64 bits, floats, doubles?
Not in this project. As already mentioned, A-machine, as well as all of its supplementary artifacts, is more of educational value. Stay tuned for the next RISC-V-related emulation projects for something more practical, fast and powerful.
2026-06-18 14:13:15 +03:00
### Is the project name a pun on [Z-machine](https://en.wikipedia.org/wiki/Z-machine)?
You may think so too, but it just came from "AWK machine" and the desire to denote that, despite being an AWK script, this is still "a machine". However, the name is still subject to possible changes in the future.
2026-06-18 14:01:36 +03:00
## Credits
Created by Luxferre in 2026, released into the public domain with no warranties.