riscv(misc): add disassmbler support

This commit is contained in:
gns 2024-03-06 09:48:43 +08:00 committed by gns
parent 751c8b6396
commit 55f24bab73
2 changed files with 995 additions and 0 deletions

979
src/jit/dis_riscv.lua Normal file
View File

@ -0,0 +1,979 @@
------------------------------------------------------------------------------
-- LuaJIT RISC-V disassembler module.
--
-- Copyright (C) 2005-2025 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
--
-- Contributed by Milos Poletanovic from Syrmia.com.
-- Contributed by gns from PLCT Lab, ISCAS.
------------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles most standard RISC-V instructions.
-- Mode is little-endian
------------------------------------------------------------------------------
local type = type
local byte, format = string.byte, string.format
local match, gmatch = string.match, string.gmatch
local concat = table.concat
local bit = require("bit")
local band, bor, tohex = bit.band, bit.bor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
local jit = require("jit")
local jstat = { jit.status() }
local function is_opt_enabled(opt)
for _, v in ipairs(jstat) do
if v == opt then
return true
end
end
return false
end
local xthead = is_opt_enabled("XThead")
------------------------------------------------------------------------------
-- Opcode maps
------------------------------------------------------------------------------
--RVC32 extension
local map_quad0 = {
shift = 13, mask = 7,
[0] = "c.addi4spnZW", "c.fldNMh", "c.lwZMn", "c.flwNMn",
false, "c.fsdNMh", "c.swZMn", "c.fswNMn"
}
local map_sub2quad1 = {
shift = 5, mask = 3,
[0] = "c.subMZ", "c.xorMZ", "c.orMZ", "c.andMZ"
}
local map_sub1quad1 = {
shift = 10, mask = 3,
[0] = "c.srliM1", "c.sraiM1", "c.andiMx", map_sub2quad1
}
local map_quad1 = {
shift = 13, mask = 7,
[0] = {
shift = 7, mask = 31,
[0] = "c.nop", _ = "c.addiDx"
},
[1] = "c.jalT", [2] = "c.liDx",
[3] = {
shift = 7, mask = 31,
[0] = "c.luiDK", [1] = "c.luiDK", [2] = "c.addi16spX",
_ = "c.luiDK"
},
[4] = map_sub1quad1, [5] = "c.jT", [6] = "c.beqzMq", [7] = "c.bnezMq"
}
local map_sub1quad2 = {
shift = 12, mask = 1,
[0] = {
shift = 2, mask = 31,
[0] = "c.jrD", _ = "c.mvDE"
},
[1] = {
shift = 2, mask = 31,
[0] = {
shift = 7, mask = 31,
[0] = "c.ebreak", _ = "c.jalrD"
},
_ = "c.addDE"
}
}
local map_quad2 = {
shift = 13, mask = 7,
[0] = "c.slliD1", [1] = "c.fldspFQ",[2] = "c.lwspDY", [3] = "c.flwspFY",
[4] = map_sub1quad2, [5] = "c.fsdspVt", [6] = "c.swspEu", [7] = "c.fswspVu"
}
local map_compr = {
[0] = map_quad0, map_quad1, map_quad2
}
--RV32M
local map_mext = {
shift = 12, mask = 7,
[0] = "mulDRr", "mulhDRr", "mulhsuDRr", "mulhuDRr",
"divDRr", "divuDRr", "remDRr", "remuDRr"
}
--RV64M
local map_mext64 = {
shift = 12, mask = 7,
[0] = "mulwDRr", [4] = "divwDRr", [5] = "divuwDRr", [6] = "remwDRr",
[7] = "remuwDRr"
}
--RV32F, RV64F, RV32D, RV64D
local map_fload = {
shift = 12, mask = 7,
[2] = "flwFL", [3] = "fldFL"
}
local map_fstore = {
shift = 12, mask = 7,
[2] = "fswSg", [3] = "fsdSg"
}
local map_fmadd = {
shift = 25, mask = 3,
[0] = "fmadd.sFGgHo", "fmadd.dFGgHo"
}
local map_fmsub = {
shift = 25, mask = 3,
[0] = "fmsub.sFGgHo", "fmsub.dFGgHo"
}
local map_fnmsub = {
shift = 25, mask = 3,
[0] = "fnmsub.sFGgHo", "fnmsub.dFGgHo"
}
local map_fnmadd = {
shift = 25, mask = 3,
[0] = "fnmadd.sFGgHo", "fnmadd.dFGgHo"
}
local map_fsgnjs = {
shift = 12, mask = 7,
[0] = "fsgnj.s|fmv.sFGg6", "fsgnjn.s|fneg.sFGg6", "fsgnjx.s|fabs.sFGg6"
}
local map_fsgnjd = {
shift = 12, mask = 7,
[0] = "fsgnj.d|fmv.dFGg6", "fsgnjn.d|fneg.dFGg6", "fsgnjx.d|fabs.dFGg6"
}
local map_fms = {
shift = 12, mask = 7,
[0] = "fmin.sFGg", "fmax.sFGg", "fminm.sFGg", "fmaxm.sFGg"
}
local map_fmd = {
shift = 12, mask = 7,
[0] = "fmin.dFGg", "fmax.dFGg", "fminm.dFGg", "fmaxm.dFGg"
}
local map_fcomps = {
shift = 12, mask = 7,
[0] = "fle.sDGg", "flt.sDGg", "feq.sDGg",
[4] = "fleq.sDGg", "fltq.sDGg"
}
local map_fcompd = {
shift = 12, mask = 7,
[0] = "fle.dDGg", "flt.dDGg", "feq.dDGg",
[4] = "fleq.dDGg", "fltq.dDGg"
}
local map_fcvtwls = {
shift = 20, mask = 31,
[0] = "fcvt.w.sDGo", "fcvt.wu.sDGo", "fcvt.l.sDGo", "fcvt.lu.sDGo"
}
local map_fcvtwld = {
shift = 20, mask = 31,
[0] = "fcvt.w.dDGo", "fcvt.wu.dDGo", "fcvt.l.dDGo", "fcvt.lu.dDGo",
[8] = {
shift = 12, mask = 7,
[1] = "fcvtmodw.dDG"
}
}
local map_fcvts = {
shift = 20, mask = 31,
[0] = "fcvt.s.wFRo", "fcvt.s.wuFRo", "fcvt.s.lFRo", "fcvt.s.luFRo"
}
local map_fcvtd = {
shift = 20, mask = 31,
[0] = "fcvt.d.wFRo", "fcvt.d.wuFRo", "fcvt.d.lFRo", "fcvt.d.luFRo"
}
local map_fcvtsd = {
shift = 20, mask = 31,
[0] = "fcvt.s.dFGo",
[4] = "fround.sFGo", [5] = "froundnx.sFGo"
}
local map_fcvtds = {
shift = 20, mask = 31,
[0] = "fcvt.d.sFGo",
[4] = "fround.dFGo", [5] = "froundnx.dFGo"
}
local map_fmvwx = {
shift = 20, mask = 31,
[0] = "fmv.w.xFR", [1] = "fli.sFy"
}
local map_fmvdx = {
shift = 20, mask = 31,
[0] = "fmv.d.xFR", [1] = "fli.dFy"
}
local map_fext = {
shift = 25, mask = 127,
[0] = "fadd.sFGgo", [1] = "fadd.dFGgo", [4] = "fsub.sFGgo", [5] = "fsub.dFGgo",
[8] = "fmul.sFGgo", [9] = "fmul.dFGgo", [12] = "fdiv.sFGgo", [13] = "fdiv.dFGgo",
[16] = map_fsgnjs, [17] = map_fsgnjd, [20] = map_fms, [21] = map_fmd,
[32] = map_fcvtsd, [33] = map_fcvtds,[44] = "fsqrt.sFGo", [45] = "fsqrt.dFGo",
[80] = map_fcomps, [81] = map_fcompd, [96] = map_fcvtwls, [97] = map_fcvtwld,
[104] = map_fcvts, [105] = map_fcvtd,
[112] = {
shift = 12, mask = 7,
[0] = "fmv.x.wDG", "fclass.sDG"
},
[113] = {
shift = 12, mask = 7,
[0] = "fmv.x.dDG", "fclass.dDG"
},
[120] = map_fmvwx, [121] = map_fmvdx
}
--RV32A, RV64A
local map_aext = {
shift = 27, mask = 31,
[0] = {
shift = 12, mask = 7,
[2] = "amoadd.wDrO", [3] = "amoadd.dDrO"
},
{
shift = 12, mask = 7,
[2] = "amoswap.wDrO", [3] = "amoswap.dDrO"
},
{
shift = 12, mask = 7,
[2] = "lr.wDO", [3] = "lr.dDO"
},
{
shift = 12, mask = 7,
[2] = "sc.wDrO", [3] = "sc.dDrO"
},
{
shift = 12, mask = 7,
[2] = "amoxor.wDrO", [3] = "amoxor.dDrO"
},
[8] = {
shift = 12, mask = 7,
[2] = "amoor.wDrO", [3] = "amoor.dDrO"
},
[12] = {
shift = 12, mask = 7,
[2] = "amoand.wDrO", [3] = "amoand.dDrO"
},
[16] = {
shift = 12, mask = 7,
[2] = "amomin.wDrO", [3] = "amomin.dDrO"
},
[20] = {
shift = 12, mask = 7,
[2] = "amomax.wDrO", [3] = "amomax.dDrO"
},
[24] = {
shift = 12, mask = 7,
[2] = "amominu.wDrO", [3] = "amominu.dDrO"
},
[28] = {
shift = 12, mask = 7,
[2] = "amomaxu.wDrO", [3] = "amomaxu.dDrO"
},
}
-- RV32I, RV64I
local map_load = {
shift = 12, mask = 7,
[0] = "lbDL", "lhDL", "lwDL", "ldDL",
"lbuDL", "lhuDL", "lwuDL"
}
local map_opimm = {
shift = 12, mask = 7,
[0] = {
shift = 7, mask = 0x1ffffff,
[0] = "nop", _ = "addi|li|mvDR0I2"
},
{
shift = 25, mask = 127,
[48] = {
shift = 20, mask = 31,
[4] = "sext.bDR", [5] = "sext.hDR"
},
_ = "slliDRi",
}, "sltiDRI", "sltiu|seqzDRI5",
"xori|notDRI4",
{
shift = 26, mask = 63,
[0] = "srliDRi", [16] = "sraiDRi", [24] = "roriDRi",
[26] = {
shift = 20, mask = 63,
[56] = "rev8DR"
}
},
"oriDRI", "andiDRI"
}
local map_branch = {
shift = 12, mask = 7,
[0] = "beq|beqzRr0B", "bne|bnezRr0B" , false, false,
"blt|bgtz|bltzR0r2B", "bge|blez|bgezR0r2B", "bltuRrB", "bgeuRrB"
}
local map_store = {
shift = 12, mask = 7,
[0] = "sbSr", "shSr", "swSr", "sdSr"
}
local map_op = {
shift = 25, mask = 127,
[0] = {
shift = 12, mask = 7,
[0] = "addDRr", "sllDRr", "slt|sgtz|sltzDR0r2", "sltu|snezDR0r",
"xorDRr", "srlDRr", "orDRr", "andDRr"
},
[1] = map_mext,
[4] = {
},
[5] = { -- Zbb
shift = 12, mask = 7,
[4] = "minDRr", [5] = "minuDRr", [6] = "maxDRr", [7] = "maxuDRr"
},
[7] = { -- Zicond
shift = 12, mask = 7,
[5] = "czero.eqzDRr", [7] = "czero.nezDRr"
},
[16] = { -- Zba
shift = 12, mask = 7,
[2] = "sh1addDRr", [4] = "sh2addDRr", [6] = "sh3addDRr"
},
[32] = { -- Zbb
shift = 12, mask = 7,
[0] = "sub|negDR0r", [4] = "xnorDRr", [5] = "sraDRr", [6] = "ornDRr", [7] = "andnDRr"
},
[48] = { -- Zbb
shift = 12, mask = 7,
[1] = "rolDRr", [5] = "rorDRr"
}
}
--- 64I
local map_opimm32 = {
shift = 12, mask = 7,
[0] = "addiw|sext.wDRI0", "slliwDRi",
[2] = { -- Zba
shift = 25, mask = 127,
[1] = "slli.uwDRi"
},
[5] = { -- 64I
shift = 25, mask = 127,
[0] = "srliwDRi", [32] = "sraiwDRi", [48] = "roriwDRi"
},
[48] = { -- Zbb
shift = 25, mask = 127,
[5] = "roriwDRi"
}
}
local map_op32 = {
shift = 25, mask = 127,
[0] = { -- 64I
shift = 12, mask = 7,
[0] = "addwDRr", [1] = "sllwDRr", [5] = "srlwDRr"
},
[1] = map_mext64,
[4] = { -- Zba & Zbb
shift = 12, mask = 7,
[0] = "add.uw|zext.w|DRr0", [4] = "zext.hDRr"
},
[16] = { -- Zba
shift = 12, mask = 7,
[2] = "sh1add.uw", [4] = "sh2add.uw", [6] = "sh3add.uw"
},
[32] = { -- 64I
shift = 12, mask = 7,
[0] = "subw|negwDR0r", [5] = "srawDRr"
},
[48] = { -- Zbb
shift = 12, mask = 7,
[1] = "rolwDRr", [5] = "rorwDRr"
}
}
local map_ecabre = {
shift = 12, mask = 7,
[0] = {
shift = 20, mask = 4095,
[0] = "ecall", "ebreak"
}
}
local map_fence = {
shift = 12, mask = 1,
[0] = "fence", --"fence.i" ZIFENCEI EXTENSION
}
local map_jalr = {
shift = 7, mask = 0x1ffffff,
_ = "jalr|jrDRI7", [256] = "ret"
}
local map_xthead_custom0 = {
shift = 12, mask = 7,
[1] = { -- Arithmetic
shift = 27, mask = 31,
[0] = "th.addslDRrv",
[2] = {
shift = 26, mask = 63,
[4] = "th.srriDRi",
[5] = {
shift = 25, mask = 127,
[10] = "th.srriwDRi"
}
},
[4] = { -- XTheadMac
shift = 25, mask = 3,
[0] = "th.mulaDRr", "th.mulsDRr", "th.mulawDRr", "th.mulswDRr"
},
[5] = { -- XTheadMac
shift = 25, mask = 3,
[0] = "th.mulahDRr", "th.mulshDRr"
},
[8] = { -- XTheadCondMov
shift = 25, mask = 3,
[0] = "th.mveqzDRr", "th.mvnezDRr"
},
[16] = { -- XTheadBb
shift = 20, mask = 31,
[0] = {
shift = 25, mask = 3,
[0] = "th.tstnbzDRi", "th.revDR", "th.ff0DR", "th.ff1DR"
}
},
[17] = { -- XTheadBb
shift = 26, mask = 1,
[0] = "th.tstDRi"
},
[18] = { -- XTheadBb
shift = 20, mask = 31,
[0] = {
shift = 25, mask = 3,
[0] = "th.revwDR"
}
}
},
[2] = "th.extDRji", [3] = "th.extuDRji",
{ -- MemLoad
shift = 29, mask = 7,
[7] = { -- XTheadMemPair
shift = 25, mask = 3,
[0] = "th.lwdDrP", [2] = "th.lwudDrP", "th.lddDrP"
}
},
{ -- MemStore
shift = 29, mask = 7,
[7] = { -- XTheadMemPair
shift = 25, mask = 3,
[0] = "th.swdDrP", [3] = "th.sddDrP"
}
}
}
local map_custom0 = xthead and map_xthead_custom0 or nil
local map_pri = {
[3] = map_load, [7] = map_fload, [11] = map_custom0, [15] = map_fence, [19] = map_opimm,
[23] = "auipcDA", [27] = map_opimm32,
[35] = map_store, [39] = map_fstore, [47] = map_aext, [51] = map_op,
[55] = "luiDU", [59] = map_op32, [67] = map_fmadd, [71] = map_fmsub,
[75] = map_fnmsub, [99] = map_branch, [79] = map_fnmadd, [83] = map_fext,
[103] = map_jalr, [111] = "jal|j|D0J", [115] = map_ecabre
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "zero", "ra", "sp", "gp", "tp", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
}
local map_fgpr = {
[0] = "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
}
local map_rm = {
[0] = "rne", "rtz", "rdn", "rup", "rmm", [7] = "dyn"
}
local map_fli = {
[0] = "-1.0",
"min",
"0x1p-16", "0x1p-15", "0x1p-8", "0x1p-7",
"0.0625", "0.125",
"0.25", "0.3125", "0.375", "0.4375",
"0.5", "0.625", "0.75", "0.875",
"1.0", "1.25", "1.5", "1.75",
"2.0", "2.5", "3.0",
"4.0", "8.0", "16.0", "128.0", "256.0",
"32768.0", "65536.0", "inf", "nan"
}
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then extra = "\t->"..sym end
end
if ctx.hexdump > 0 then
ctx.out:write((format("%08x %s %-7s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ","), extra)))
else
ctx.out(format("%08x %-7s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
local pos = ctx.pos
local first_byte = byte(ctx.code, ctx.pos+1)
--Examine if the next instruction is 16-bits or 32-bits
if(band(first_byte, 3) < 3) then
ctx.pos = pos + 2
else
ctx.pos = pos + 4
end
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
local function get_le(ctx)
local pos = ctx.pos
--Examine if the next instruction is 16-bits or 32-bits
local first_byte = byte(ctx.code, pos+1)
if(band(first_byte, 3) < 3) then --checking first two bits of opcode
local b0, b1 = byte(ctx.code, pos+1, pos+2)
return bor(lshift(b1, 8), b0)
else
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
end
end
local function parse_W(opcode)
local part1 = band(rshift(opcode, 7), 15) --9:6
local part2 = band(rshift(opcode, 11), 3) --5:4
local part3 = band(rshift(opcode, 5), 1)--3
local part4 = band(rshift(opcode, 6), 1)--2
return bor(lshift(0, 31), lshift(part1, 6) , lshift(part2, 4),
lshift(part3, 3), lshift(part4, 2))
end
local function parse_x(opcode)
local part1 = band(rshift(opcode, 12), 1) --5
local part2 = band(rshift(opcode, 2), 31) --4:0
if(part1 == 1) then
return bor(lshift(1, 31), lshift(0x1ffffff, 6), lshift(part1, 5), part2)
else
return bor(lshift(0, 31), lshift(part1, 5), part2)
end
end
local function parse_X(opcode)
local part1 = band(rshift(opcode, 12), 1) --12
local part2 = band(rshift(opcode, 3), 3) --8:7
local part3 = band(rshift(opcode, 5), 1) --6
local part4 = band(rshift(opcode, 2), 1) --5
local part5 = band(rshift(opcode, 6), 1) --4
if(part1 == 1) then
return bor(lshift(1, 31), lshift(0x3fffff, 9), lshift(part2, 7),
lshift(part3, 6), lshift(part4, 5), lshift(part5, 4))
else
return bor(lshift(0, 31), lshift(part2, 7), lshift(part3, 6),
lshift(part4, 5), lshift(part5, 4))
end
end
local function parse_S(opcode)
local part1 = band(rshift(opcode, 25), 127) --11:5
local sign = band(rshift(part1, 6), 1)
local part2 = band(rshift(opcode, 7), 31) --4:0
if (sign == 1) then
return bor(lshift(1, 31), lshift(0x7ffff, 12), lshift(part1, 5), part2)
else
return bor(lshift(0, 31), lshift(part1, 5), part2)
end
end
local function parse_B(opcode)
local part1 = band(rshift(opcode, 7), 1) --11
local part2 = band(rshift(opcode, 25), 63) --10:5
local part3 = band(rshift(opcode, 8), 15) -- 4 : 1
if (part1 == 1) then
return bor(lshift(1, 31), lshift(0x7ffff, 12), lshift(part1, 11),
lshift(part2, 5), lshift(part3, 1), 0)
else
return bor(lshift(0, 31), lshift(part1, 11), lshift(part2, 5),
lshift(part3, 1), 0)
end
end
local function parse_q(opcode)
local part1 = band(rshift(opcode, 12), 1) --8
local part2 = band(rshift(opcode, 5), 3) --7:6
local part3 = band(rshift(opcode, 2), 1) --5
local part4 = band(rshift(opcode, 10), 3) --4:3
local part5 = band(rshift(opcode, 3), 3) --2:1
if(part1 == 1) then
return bor(lshift(1, 31), lshift(0x7fffff, 8), lshift(part2, 6),
lshift(part3, 5), lshift(part4, 3), lshift(part5, 1))
else
return bor(lshift(0, 31), lshift(part2, 6), lshift(part3, 5),
lshift(part4, 3), lshift(part5, 1))
end
end
local function parse_J(opcode)
local part1 = band(rshift(opcode, 31), 1) --20
local part2 = band(rshift(opcode, 12), 255) -- 19:12
local part3 = band(rshift(opcode, 20), 1) --11
local part4 = band(rshift(opcode, 21), 1023) --10:1
if(part1 == 1) then
return bor(lshift(1, 31), lshift(0x7ff, 20), lshift(part2, 12),
lshift(part3, 11), lshift(part4, 1))
else
return bor(lshift(0, 31), lshift(0, 20), lshift(part2, 12),
lshift(part3, 11), lshift(part4, 1))
end
end
local function parse_T(opcode)
local part1 = band(rshift(opcode, 12), 1) --11
local part2 = band(rshift(opcode, 8), 1) --10
local part3 = band(rshift(opcode, 9), 3)--9:8
local part4 = band(rshift(opcode, 6), 1) --7
local part5 = band(rshift(opcode, 7), 1) -- 6
local part6 = band(rshift(opcode, 2), 1) --5
local part7 = band(rshift(opcode, 11), 1) --4
local part8 = band(rshift(opcode, 3), 7) --3:1
if(part1 == 1) then
return bor(lshift(1, 31), lshift(0x7ffff, 12), lshift(part1, 11),
lshift(part2, 10), lshift(part3, 8), lshift(part4, 7),
lshift(part5, 6), lshift(part6, 5), lshift(part7, 4),
lshift(part8, 1))
else
return bor(lshift(0, 31), lshift(part1, 11), lshift(part2, 10),
lshift(part3, 8), lshift(part4, 7), lshift(part5, 6),
lshift(part6, 5), lshift(part7, 4), lshift(part8, 1))
end
end
local function parse_K(opcode)
local part1 = band(rshift(opcode, 12), 1) --5 17
local part2 = band(rshift(opcode, 2), 31) --4:0 16:12
if(part1 == 1) then
return bor(lshift(0, 31), lshift(0x7fff, 5), part2)
else
return bor(lshift(0, 31), lshift(part1, 5), part2)
end
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local op = ctx:get()
local operands = {}
local last = nil
ctx.op = op
ctx.rel =nil
local opat = 0
--for compressed instructions
if(band(op, 3) < 3) then
opat = ctx.map_compr[band(op, 3)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
local test = band(rshift(op, opat.shift), opat.mask)
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
else
opat = ctx.map_pri[band(op,127)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
end
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
local a1, a2 = 0
if altname then
pat = pat2
end
local alias_done = false --variable for the case of 2 pseudoinstructions, if both parameters are x0, 0
for p in gmatch(pat, ".") do
local x = nil
if p == "D" then
x = map_gpr[band(rshift(op, 7), 31)]
elseif p == "F" then
x = map_fgpr[band(rshift(op, 7), 31)]
elseif p == "R" then
x = map_gpr[band(rshift(op, 15), 31)]
elseif p == "G" then
x = map_fgpr[band(rshift(op, 15), 31)]
elseif p == "r" then
x = map_gpr[band(rshift(op, 20), 31)]
if(name == "sb" or name == "sh" or name == "sw" or name == "sd") then
local temp = last --because of the diffrent order of the characters
operands[#operands] = x
x = temp
end
elseif p == "g" then
x = map_fgpr[band(rshift(op, 20), 31)]
if(name == "fsw" or name == "fsd") then
local temp = last
operands[#operands] = x
x = temp
end
elseif p == "Z" then
x = map_gpr[8 + band(rshift(op, 2), 7)]
elseif p == "N" then
x = map_fgpr[8 + band(rshift(op, 2), 7)]
elseif p == "M" then
x = map_gpr[8 + band(rshift(op, 7), 7)]
elseif p == "E" then
x = map_gpr[band(rshift(op, 2), 31)]
elseif p == "W" then
local uimm = parse_W(op)
x = format("%s,%d", "sp", uimm)
elseif p == "x" then
x = parse_x(op)
elseif p == "h" then
local part1 = band(rshift(op, 5), 3) --7:6
local part2 = band(rshift(op, 10), 7) --5:3
local uimm = bor(lshift(0, 31), lshift(part1, 6) , lshift(part2, 3))
operands[#operands] = format("%d(%s)", uimm, last)
elseif p == "X" then
local imm = parse_X(op)
x = format("%s,%d", "sp", imm)
elseif p == "O" then
x = format("(%s)", map_gpr[band(rshift(op, 15), 31)])
elseif p == "H" then
x = map_fgpr[band(rshift(op, 27), 31)]
elseif p == "L" then
local register = map_gpr[band(rshift(op, 15), 31)]
local disp = arshift(op, 20)
x = format("%d(%s)", disp, register)
elseif p == "P" then -- XTheadMemPair
local register = map_gpr[band(rshift(op, 15), 31)]
local disp = band(arshift(op, 25), 3)
local isword = bxor(band(arshift(op, 26), 1), 1)
x = format("(%s), %d, %d", register, disp, isword and 3 or 4)
elseif p == "I" then
x = arshift(op, 20)
--different for jalr
if(name == "jalr") then
local reg = map_gpr[band(rshift(op, 15), 31)]
if(ctx.reltab[reg] == nil) then
operands[#operands] = format("%d(%s)", x, last)
else
local target = ctx.reltab[reg] + x
operands[#operands] = format("%d(%s) #0x%08x", x, last, target)
ctx.rel = target
ctx.reltab[reg] = nil --assume no reuses of the register
end
x = nil --not to add additional operand
end
elseif p == "i" then
--both for RV32I AND RV64I
local value = band(arshift(op, 20), 63)
x = string.format("%d", value)
elseif p == "j" then -- XThead imm1[31..26]
local value = band(rshift(op, 26), 63)
x = string.format("%d", value)
elseif p == "v" then --XThead imm[2][26..25]
local value = band(rshift(op, 25), 3)
x = string.format("%d", value)
elseif p == "S" then
local register = map_gpr[band(rshift(op, 15), 31)] --register
local imm = parse_S(op)
x = format("%d(%s)", imm, register)
elseif p == "n" then
local part1 = band(rshift(op, 5), 1) --6
local part2 = band(rshift(op, 10), 7) --5:3
local part3 = band(rshift(op, 6), 1) --2
local uimm = bor(lshift(0, 31), lshift(part1, 6), lshift(part2, 3),
lshift(part3, 2))
operands[#operands] = format("%d(%s)", uimm, last)
elseif p == "A" then
local value, dest = band(rshift(op, 12), 0xfffff), map_gpr[band(rshift(op, 7), 31)]
ctx.reltab[dest] = ctx.addr + ctx.pos + lshift(value, 12)
x = format("0x%x", value)
elseif p == "B" then
x = ctx.addr + ctx.pos + parse_B(op)
ctx.rel = x
x = format("0x%08x", x)
elseif p == "U" then
local value = band(rshift(op, 12), 0xfffff)
x = string.format("0x%x", value)
elseif p == "Q" then
local part1 = band(rshift(op, 2), 7) --8:6
local part2 = band(rshift(op, 12), 1) --5
local part3 = band(rshift(op, 5), 3) --4:3
local uimm = bor(lshift(0, 31), lshift(part1, 6), lshift(part2, 5),
lshift(part3, 3))
x = format("%d(%s)", uimm, "sp")
elseif p == "q" then
x = ctx.addr + ctx.pos + parse_q(op)
ctx.rel = x
x = format("0x%08x", x)
elseif p == "J" then
x = ctx.addr + ctx.pos + parse_J(op)
ctx.rel = x
x = format("0x%08x", x)
elseif p == "K" then
local value = parse_K(op)
x = string.format("0x%x", value)
elseif p == "Y" then
local part1 = band(rshift(op, 2), 3) --7:6
local part2 = band(rshift(op, 12), 1) --5
local part3 = band(rshift(op, 4), 7) --4:2
local uimm = bor(lshift(0, 31), lshift(part1, 6), lshift(part2, 5),
lshift(part3, 2))
x = format("%d(%s)", uimm, "sp")
elseif p == "o" then -- rounding mode
x = map_rm[band(rshift(op, 12), 7)]
elseif p == "y" then -- fli lut
x = map_fli[band(rshift(op, 15), 31)]
elseif p == "1" then
local part1 = band(rshift(op, 12), 1) --5
local part2 = band(rshift(op, 2), 31) --4:0
local uimm = bor(lshift(0, 31), lshift(part1, 5), part2)
x = string.format("0x%x", uimm)
elseif p == "T" then
x = ctx.addr + ctx.pos + parse_T(op)
ctx.rel = x
x = format("0x%08x", x)
elseif p == "t" then
local part1 = band(rshift(op, 7), 7) --8:6
local part2 = band(rshift(op, 10), 7) --5:3
local uimm = bor(lshift(0, 31), lshift(part1, 6), lshift(part2, 3))
x = format("%d(%s)", uimm, "sp")
elseif p == "u" then
local part1 = band(rshift(op, 7), 3) --7:6
local part2 = band(rshift(op, 9), 15) --5:2
local uimm = bor(lshift(0, 31), lshift(part1, 6), lshift(part2, 2))
x = format("%d(%s)", uimm, "sp")
elseif p == "V" then
x = map_fgpr[band(rshift(op, 2), 31)]
elseif p == "0" then --PSEUDOINSTRUCTIONS
if (last == "zero" or last == 0) then
local n = #operands
operands[n] = nil
last = operands[n-1]
local a1, a2 = match(altname, "([^|]*)|(.*)")
if a1 then name, altname = a1, a2
else name = altname end
alias_done = true
end
elseif (p == "4") then
if(last == -1) then
name = altname
operands[#operands] = nil
end
elseif (p == "5") then
if(last == 1) then
name = altname
operands[#operands] = nil
end
elseif (p == "6") then
if(last == operands[#operands - 1]) then
name = altname
operands[#operands] = nil
end
elseif (p == "7") then --jalr rs
local value = string.sub(operands[#operands], 1, 1)
local reg = string.sub(operands[#operands], 3, #(operands[#operands]) - 1)
if(value == "0" and
(operands[#operands - 1] == "ra" or operands[#operands - 1] == "zero")) then
if(operands[#operands - 1] == "zero") then
name = altname
end
operands[#operands] = nil
operands[#operands] = reg
end
elseif (p == "2" and alias_done == false) then
if (last == "zero" or last == 0) then
local a1, a2 = match(altname, "([^|]*)|(.*)")
name = a2
operands[#operands] = nil
end
end
if x then operands[#operands+1] = x; last = x end
end
return putop(ctx, name, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then
ofs = 0
end
local stop = len and ofs+len or #ctx.code
--instructions can be both 32 and 16 bits
stop = stop - stop % 2
ctx.pos = ofs - ofs % 2
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
ctx.get = get_le
ctx.map_pri = map_pri
ctx.map_compr = map_compr
ctx.reltab = {}
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
create(code, addr, out):disass(addr)
end
-- Return register name for RID.
local function regname(r)
if r < 32 then return map_gpr[r] end
return "f"..(r-32)
end
-- Public module functions.
return {
create = create,
disass = disass,
regname = regname
}

16
src/jit/dis_riscv64.lua Normal file
View File

@ -0,0 +1,16 @@
----------------------------------------------------------------------------
-- LuaJIT RISC-V 64 disassembler wrapper module.
--
-- Copyright (C) 2005-2025 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the default riscv little-endian functions from the
-- RISC-V disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_riscv = require((string.match(..., ".*%.") or "").."dis_riscv")
return {
create = dis_riscv.create,
disass = dis_riscv.disass,
regname = dis_riscv.regname
}