From 3391969951f337e47039f9bd4f721bb1934f3fcc Mon Sep 17 00:00:00 2001 From: Luxferre Date: Thu, 18 Jun 2026 19:10:32 +0300 Subject: [PATCH] added C-extension support --- Makefile | 18 +-- README.md | 9 +- amach.awk | 142 +++++++++++++++++- rv32ima_tests.bin | Bin 15492 -> 0 bytes rv32imac_tests.bin | Bin 0 -> 17940 bytes rv32ima_tests.s => rv32imac_tests.s | 224 ++++++++++++++++++++++++++++ 6 files changed, 378 insertions(+), 15 deletions(-) delete mode 100755 rv32ima_tests.bin create mode 100755 rv32imac_tests.bin rename rv32ima_tests.s => rv32imac_tests.s (81%) diff --git a/Makefile b/Makefile index 130bb27..c5746db 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +2,21 @@ CC = riscv64-linux-gnu-gcc OBJCOPY = riscv64-linux-gnu-objcopy EMULATOR = ./amach -ASFLAGS = -march=rv32ima -mabi=ilp32 -nostdlib -s -static -fno-pic -fno-pie -mno-relax +ASFLAGS = -march=rv32imac -mabi=ilp32 -nostdlib -s -static -fno-pic -fno-pie -mno-relax LDFLAGS = -Wl,-Ttext=0x100b0 -Wl,--build-id=none -all: rv32ima_tests.bin +all: rv32imac_tests.bin -rv32ima_tests.elf: rv32ima_tests.s - $(CC) $(ASFLAGS) $(LDFLAGS) rv32ima_tests.s -o rv32ima_tests.elf +rv32imac_tests.elf: rv32imac_tests.s + $(CC) $(ASFLAGS) $(LDFLAGS) rv32imac_tests.s -o rv32imac_tests.elf -rv32ima_tests.bin: rv32ima_tests.elf - $(OBJCOPY) -O binary rv32ima_tests.elf rv32ima_tests.bin +rv32imac_tests.bin: rv32imac_tests.elf + $(OBJCOPY) -O binary rv32imac_tests.elf rv32imac_tests.bin -run: rv32ima_tests.bin - $(EMULATOR) rv32ima_tests.bin +run: rv32imac_tests.bin + $(EMULATOR) rv32imac_tests.bin clean: - rm -f rv32ima_tests.elf rv32ima_tests.bin + rm -f rv32imac_tests.elf rv32imac_tests.bin .PHONY: all run clean diff --git a/README.md b/README.md index b18bc1c..359c27b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# A-machine: a minimal RISC-V (RV32IMA) emulator in POSIX AWK +# A-machine: a minimal RISC-V (RV32IMAC) emulator in POSIX AWK ## About -A-machine is a simple and straightforward implementation of the RV32I specification with M (multiplication/division) and A (atomic operations) extenstions. It consists of two files: +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: - [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. -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, a file called `rv32ima_tests.bin` is also included into the repo. +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, a file called `rv32imac_tests.bin` is also included into the repo. The project is to be considered highly experimental and not production-ready in any way. @@ -32,11 +32,10 @@ POSIXLY_CORRECT=1 awk -f amach.awk [-v LVA=...] -- path/to/program.dec ## Support -Currently, A-machine only supports the **unprivileged** RV32IMA instruction set with a few additional `ecall` syscalls: 63 (sys_read, for fd 0 only), 64 (sys_write, for fd 1 and 2 only) and 93 (sys_exit). For completeness, `fence` instruction is also supported but yields a no-op. +Currently, A-machine only supports the **unprivileged** RV32IMAC instruction set with a few additional `ecall` syscalls: 63 (sys_read, for fd 0 only), 64 (sys_write, for fd 1 and 2 only) and 93 (sys_exit). For completeness, `fence` instruction is also supported but yields a no-op. ## Plans (from higher to lower priority) -- Implement the C-extension (compressed instruction set). - Implement a simple RV32IMAC disassembler in POSIX AWK. - Introduce more popular Linux-compatible syscalls (that make sense to implement in AWK but don't increase the overall project complexity). - Test for RV32EMC compatibility (that the code built for the "embedded" variant runs here). diff --git a/amach.awk b/amach.awk index 00c66a2..02ecbd9 100644 --- a/amach.awk +++ b/amach.awk @@ -1,5 +1,5 @@ #!/usr/bin/env awk -f -# A-Machine: an experimental RISC-V (RV32IMA) emulator in POSIX AWK +# A-Machine: an experimental RISC-V (RV32IMAC) emulator in POSIX AWK # with a very small subset of supported ECALLs # Accepts a headerless binary previously converted to .dec format # e.g. with POSIX od: od -An -v -tu1 program.bin > program.dec @@ -275,8 +275,148 @@ function amach_atomic(f3, f5, aq, rl, rd, rs1, rs2, r1, r2, val, uval, ur2) { } else trapout(sprintf("Illegal atomic instruction at 0x%X", pc-4)) } +# C-extension (compressed instructions) handler +function amach_comp(instr, op, f3, b12, r11_7, r9_7, r6_2, r4_2, shamt, imm, base, val) { + op = instr % 4 + f3 = int(instr / 8192) % 8 + b12 = int(instr / 4096) % 2 + r11_7 = int(instr / 128) % 32 + r9_7 = (int(instr / 128) % 8) + 8 + r6_2 = int(instr / 4) % 32 + r4_2 = (int(instr / 4) % 8) + 8 + shamt = r6_2 + b12 * 32 + + if (op == 0) { + if (f3 == 0) { # C.ADDI4SPN + imm = (int(instr / 128) % 16) * 64 + (int(instr / 2048) % 4) * 16 + (int(instr / 32) % 2) * 8 + (int(instr / 64) % 2) * 4 + if (imm == 0) trapout(sprintf("Illegal instruction C.ADDI4SPN at 0x%X", pc-2)) + setreg(r4_2, getreg(2) + imm) + } else if (f3 == 2) { # C.LW + imm = (int(instr / 32) % 2) * 64 + (int(instr / 1024) % 8) * 8 + (int(instr / 64) % 2) * 4 + base = (getreg(r9_7) + imm) % 4294967296 + if (base < 0) base += 4294967296 + val = MEM[base] + MEM[(base+1)%4294967296]*256 + MEM[(base+2)%4294967296]*65536 + MEM[(base+3)%4294967296]*16777216 + setreg(r4_2, val) + } else if (f3 == 6) { # C.SW + imm = (int(instr / 32) % 2) * 64 + (int(instr / 1024) % 8) * 8 + (int(instr / 64) % 2) * 4 + base = (getreg(r9_7) + imm) % 4294967296 + if (base < 0) base += 4294967296 + val = getreg(r4_2) + if (val < 0) val += 4294967296 + MEM[base] = val % 256 + MEM[(base+1)%4294967296] = int(val/256) % 256 + MEM[(base+2)%4294967296] = int(val/65536) % 256 + MEM[(base+3)%4294967296] = int(val/16777216) % 256 + } else trapout(sprintf("Illegal instruction at 0x%X", pc-2)) + } else if (op == 1) { + if (f3 == 0) { # C.NOP / C.ADDI + imm = r6_2 + b12 * 32 + if (imm >= 32) imm -= 64 + setreg(r11_7, getreg(r11_7) + imm) + } else if (f3 == 1 || f3 == 5) { # C.JAL / C.J + imm = b12 * 2048 + (int(instr / 256) % 2) * 1024 + (int(instr / 512) % 4) * 256 + (int(instr / 64) % 2) * 128 + (int(instr / 128) % 2) * 64 + (int(instr / 4) % 2) * 32 + (int(instr / 2048) % 2) * 16 + (int(instr / 8) % 8) * 2 + if (imm >= 2048) imm -= 4096 + if (f3 == 1) setreg(1, pc) + pc = (pc - 2) + imm + } else if (f3 == 2) { # C.LI + imm = r6_2 + b12 * 32 + if (imm >= 32) imm -= 64 + setreg(r11_7, imm) + } else if (f3 == 3) { # C.ADDI16SP / C.LUI + if (r11_7 == 2) { # C.ADDI16SP + imm = b12 * 512 + (int(instr / 8) % 4) * 128 + (int(instr / 32) % 2) * 64 + (int(instr / 4) % 2) * 32 + (int(instr / 64) % 2) * 16 + if (imm >= 512) imm -= 1024 + if (imm == 0) trapout(sprintf("Illegal instruction C.ADDI16SP at 0x%X", pc-2)) + setreg(2, getreg(2) + imm) + } else if (r11_7 != 0) { # C.LUI + imm = r6_2 + b12 * 32 + if (imm >= 32) imm -= 64 + imm = imm * 4096 + if (imm == 0) trapout(sprintf("Illegal instruction C.LUI at 0x%X", pc-2)) + setreg(r11_7, imm) + } + } else if (f3 == 4) { + val = int(instr / 1024) % 4 + if (val == 0) { # C.SRLI + if (shamt >= 32) trapout(sprintf("Illegal shift amount %d at 0x%X", shamt, pc-2)) + imm = getreg(r9_7) + if (imm < 0) imm += 4294967296 + setreg(r9_7, int(imm / (2^shamt))) + } else if (val == 1) { # C.SRAI + if (shamt >= 32) trapout(sprintf("Illegal shift amount %d at 0x%X", shamt, pc-2)) + setreg(r9_7, floor(getreg(r9_7) / (2^shamt))) + } else if (val == 2) { # C.ANDI + imm = r6_2 + b12 * 32 + if (imm >= 32) imm -= 64 + setreg(r9_7, bw_and(getreg(r9_7), imm)) + } else if (val == 3) { # C.SUB, C.XOR, C.OR, C.AND + imm = int(instr / 32) % 4 + if (b12 != 0) trapout(sprintf("Illegal register-register instruction at 0x%X", pc-2)) + if (imm == 0) setreg(r9_7, getreg(r9_7) - getreg(r4_2)) + else if (imm == 1) setreg(r9_7, bw_xor(getreg(r9_7), getreg(r4_2))) + else if (imm == 2) setreg(r9_7, bw_or(getreg(r9_7), getreg(r4_2))) + else if (imm == 3) setreg(r9_7, bw_and(getreg(r9_7), getreg(r4_2))) + } + } else if (f3 == 6 || f3 == 7) { # C.BEQZ / C.BNEZ + imm = b12 * 256 + (int(instr / 32) % 4) * 64 + (int(instr / 4) % 2) * 32 + (int(instr / 1024) % 4) * 8 + (int(instr / 8) % 4) * 2 + if (imm >= 256) imm -= 512 + val = (f3 == 6) ? (getreg(r9_7) == 0) : (getreg(r9_7) != 0) + pc = val ? (pc - 2) + imm : pc + } + } else if (op == 2) { + if (f3 == 0) { # C.SLLI + if (shamt >= 32) trapout(sprintf("Illegal shift amount %d at 0x%X", shamt, pc-2)) + if (r11_7 != 0) { + setreg(r11_7, (getreg(r11_7) * (2^shamt)) % 4294967296) + } + } else if (f3 == 2) { # C.LWSP + if (r11_7 == 0) trapout(sprintf("Illegal instruction C.LWSP with rd=0 at 0x%X", pc-2)) + imm = (int(instr / 4) % 4) * 64 + b12 * 32 + (int(instr / 16) % 8) * 4 + base = (getreg(2) + imm) % 4294967296 + if (base < 0) base += 4294967296 + val = MEM[base] + MEM[(base+1)%4294967296]*256 + MEM[(base+2)%4294967296]*65536 + MEM[(base+3)%4294967296]*16777216 + setreg(r11_7, val) + } else if (f3 == 4) { # C.JR, C.MV, C.JALR, C.ADD + if (b12 == 0) { + if (r6_2 == 0) { # C.JR + if (r11_7 == 0) trapout(sprintf("Illegal instruction C.JR with rs1=0 at 0x%X", pc-2)) + pc = getreg(r11_7) + } else { # C.MV + setreg(r11_7, getreg(r6_2)) + } + } else { + if (r6_2 == 0) { + if (r11_7 == 0) { # C.EBREAK + trapout(sprintf("EBREAK at 0x%X", pc-2)) + } else { # C.JALR + imm = getreg(r11_7) + setreg(1, pc) + pc = imm + } + } else { # C.ADD + setreg(r11_7, getreg(r11_7) + getreg(r6_2)) + } + } + } else if (f3 == 6) { # C.SWSP + imm = (int(instr / 128) % 4) * 64 + (int(instr / 512) % 16) * 4 + base = (getreg(2) + imm) % 4294967296 + if (base < 0) base += 4294967296 + val = getreg(r6_2) + if (val < 0) val += 4294967296 + MEM[base] = val % 256 + MEM[(base+1)%4294967296] = int(val/256) % 256 + MEM[(base+2)%4294967296] = int(val/65536) % 256 + MEM[(base+3)%4294967296] = int(val/16777216) % 256 + } else trapout(sprintf("Illegal instruction at 0x%X", pc-2)) + } else trapout(sprintf("Illegal instruction at 0x%X", pc-2)) +} + # main instruction decoding and execution routine function amach_exec(instr, opcode, rd, rs1, rs2, imm, funct3, funct7) { + if ((instr % 4) != 3) { + amach_comp(instr) + return + } opcode = instr % 128 instr = int(instr / 128) rd = instr % 32 diff --git a/rv32ima_tests.bin b/rv32ima_tests.bin deleted file mode 100755 index e8889b767078d79ff42cf2038dc01a8e66a108f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15492 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 F{{aWYuo?gW literal 0 HcmV?d00001 diff --git a/rv32ima_tests.s b/rv32imac_tests.s similarity index 81% rename from rv32ima_tests.s rename to rv32imac_tests.s index 95bca4c..ecd3059 100644 --- a/rv32ima_tests.s +++ b/rv32imac_tests.s @@ -1,4 +1,5 @@ .section .text +.option norvc .global _start .macro INC_TESTS @@ -530,6 +531,229 @@ _start: # ========================================== fence + # ========================================== + # RV32C Compressed Instruction Tests + # ========================================== + .option rvc + + # 1. c.addi4spn + INC_TESTS + mv s0, sp + c.addi4spn a0, sp, 40 + sub a0, a0, s0 + ASSERT_EQ a0, 40, c_addi4spn_val + + # 2. c.lw and c.sw + INC_TESTS + la a1, data_buffer + li a0, 0x76543210 + sw a0, 4(a1) + c.lw a2, 4(a1) + ASSERT_EQ a2, 0x76543210, c_lw_val + + INC_TESTS + li a0, 0x11223344 + c.sw a0, 8(a1) + lw a2, 8(a1) + ASSERT_EQ a2, 0x11223344, c_sw_val + + # 3. c.nop + INC_TESTS + c.nop + li a0, 1 + ASSERT_EQ a0, 1, c_nop_val + + # 4. c.addi + INC_TESTS + li a0, 10 + c.addi a0, -3 + ASSERT_EQ a0, 7, c_addi_val + + # 5. c.jal + INC_TESTS +3: + c.jal 1f + li a0, 0 + j 2f +1: + li a0, 1 +2: + ASSERT_EQ a0, 1, c_jal_val + + INC_TESTS + la a1, 3b + 2 + ASSERT_EQ_REG ra, a1, c_jal_link + + # 6. c.li + INC_TESTS + c.li a0, -15 + ASSERT_EQ a0, -15, c_li_val + + # 7. c.addi16sp + INC_TESTS + mv s0, sp + c.addi16sp sp, -32 + sub a0, s0, sp + ASSERT_EQ a0, 32, c_addi16sp_val + mv sp, s0 + + # 8. c.lui + INC_TESTS + c.lui a0, 15 + ASSERT_EQ a0, 0xf000, c_lui_val + + # 9. c.srli, c.srai, c.andi + INC_TESTS + li a0, 0x80 + c.srli a0, 3 + ASSERT_EQ a0, 0x10, c_srli_val + + INC_TESTS + li a0, -16 + c.srai a0, 2 + ASSERT_EQ a0, -4, c_srai_val + + INC_TESTS + li a0, 15 + c.andi a0, 9 + ASSERT_EQ a0, 9, c_andi_val + + # 10. c.sub, c.xor, c.or, c.and + INC_TESTS + li a0, 15 + li a1, 5 + c.sub a0, a1 + ASSERT_EQ a0, 10, c_sub_val + + INC_TESTS + li a0, 5 + li a1, 3 + c.xor a0, a1 + ASSERT_EQ a0, 6, c_xor_val + + INC_TESTS + li a0, 5 + li a1, 3 + c.or a0, a1 + ASSERT_EQ a0, 7, c_or_val + + INC_TESTS + li a0, 5 + li a1, 3 + c.and a0, a1 + ASSERT_EQ a0, 1, c_and_val + + # 11. c.j + INC_TESTS + c.j 1f + li a0, 0 + j 2f +1: + li a0, 1 +2: + ASSERT_EQ a0, 1, c_j_val + + # 12. c.beqz, c.bnez + INC_TESTS + li a0, 0 + c.beqz a0, 1f + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 1, c_beqz_taken + + INC_TESTS + li a0, 1 + c.beqz a0, 1f + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 0, c_beqz_not_taken + + INC_TESTS + li a0, 1 + c.bnez a0, 1f + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 1, c_bnez_taken + + INC_TESTS + li a0, 0 + c.bnez a0, 1f + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 0, c_bnez_not_taken + + # 13. c.slli + INC_TESTS + li a0, 5 + c.slli a0, 2 + ASSERT_EQ a0, 20, c_slli_val + + # 14. c.lwsp, c.swsp + INC_TESTS + mv s0, sp + c.addi16sp sp, -32 + li a0, 0x11223344 + sw a0, 16(sp) + c.lwsp a1, 16(sp) + ASSERT_EQ a1, 0x11223344, c_lwsp_val + + INC_TESTS + li a0, 0x55667788 + c.swsp a0, 20(sp) + lw a1, 20(sp) + ASSERT_EQ a1, 0x55667788, c_swsp_val + mv sp, s0 + + # 15. c.jr, c.mv, c.jalr, c.add + INC_TESTS + la a0, 1f + c.jr a0 + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 1, c_jr_val + + INC_TESTS + li a1, 42 + c.mv a0, a1 + ASSERT_EQ a0, 42, c_mv_val + + INC_TESTS + la a0, 1f +3: + c.jalr a0 + li a1, 0 + j 2f +1: + li a1, 1 +2: + ASSERT_EQ a1, 1, c_jalr_val + INC_TESTS + la a2, 3b + 2 + ASSERT_EQ_REG ra, a2, c_jalr_link + + INC_TESTS + li a0, 10 + li a1, 20 + c.add a0, a1 + ASSERT_EQ a0, 30, c_add_val + + .option norvc + # ========================================== # Report Results # ==========================================