added C-extension support

This commit is contained in:
Luxferre
2026-06-18 19:10:32 +03:00
parent caf64b689b
commit 3391969951
6 changed files with 378 additions and 15 deletions
+141 -1
View File
@@ -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