This commit is contained in:
2025-12-29 15:54:38 +00:00
parent c5ea05c682
commit e4d940263d
5 changed files with 842 additions and 1943 deletions
+26 -2
View File
@@ -126,7 +126,7 @@ def disasm(inst: Inst) -> str:
src0_str = fmt_src(src0)
vsrc1_str = _vreg(vsrc1, 2) if is_64bit_vsrc1 else f"v{vsrc1 & 0x7f}.{'h' if vsrc1 >= 128 else 'l'}" if is_16bit else f"v{vsrc1}"
if is_cmpx:
return f"{op_name} {src0_str}, {vsrc1_str}"
return f"{op_name}_e32 {src0_str}, {vsrc1_str}"
return f"{op_name}_e32 vcc_lo, {src0_str}, {vsrc1_str}"
# SOPP
@@ -644,7 +644,19 @@ def disasm(inst: Inst) -> str:
if cls_name == 'SOPK':
sdst, simm16 = unwrap(inst._values.get('sdst', 0)), unwrap(inst._values.get('simm16', 0))
if op_name == 's_version': return f"{op_name} 0x{simm16:x}"
if op_name == 's_setreg_b32': return f"{op_name} 0x{simm16:x}, {_fmt_sdst(sdst, 1)}"
if op_name in ('s_setreg_b32', 's_getreg_b32'):
# Decode hwreg: (size-1) << 11 | offset << 6 | id
hwreg_id, hwreg_offset, hwreg_size = simm16 & 0x3f, (simm16 >> 6) & 0x1f, ((simm16 >> 11) & 0x1f) + 1
hwreg_names = {1: 'HW_REG_MODE', 2: 'HW_REG_STATUS', 3: 'HW_REG_TRAPSTS', 4: 'HW_REG_HW_ID1', 5: 'HW_REG_HW_ID2',
15: 'HW_REG_GPR_ALLOC', 16: 'HW_REG_LDS_ALLOC', 17: 'HW_REG_IB_STS', 18: 'HW_REG_IB_STS2',
20: 'HW_REG_SH_MEM_BASES', 21: 'HW_REG_TBA_LO', 22: 'HW_REG_TBA_HI', 23: 'HW_REG_TMA_LO',
24: 'HW_REG_TMA_HI', 25: 'HW_REG_FLAT_SCR_LO', 26: 'HW_REG_FLAT_SCR_HI', 27: 'HW_REG_XNACK_MASK',
29: 'HW_REG_POPS_PACKER'}
hwreg_name = hwreg_names.get(hwreg_id, str(hwreg_id))
hwreg_str = f"hwreg({hwreg_name}, {hwreg_offset}, {hwreg_size})"
if op_name == 's_setreg_b32':
return f"{op_name} {hwreg_str}, {_fmt_sdst(sdst, 1)}"
return f"{op_name} {_fmt_sdst(sdst, 1)}, {hwreg_str}"
return f"{op_name} {_fmt_sdst(sdst, dst_cnt)}, 0x{simm16:x}"
# Generic fallback
@@ -706,6 +718,18 @@ def asm(text: str) -> Inst:
elif m := re.match(r'lgkmcnt\((\d+)\)', part): lgkmcnt = int(m.group(1))
elif re.match(r'^0x[0-9a-f]+$|^\d+$', part): return autogen.s_waitcnt(simm16=int(part, 0))
return autogen.s_waitcnt(simm16=waitcnt(vmcnt, expcnt, lgkmcnt))
# Handle VOPD dual-issue instructions: opx dst, src :: opy dst, src
if '::' in text:
x_part, y_part = text.split('::')
x_parts, y_parts = x_part.strip().replace(',', ' ').split(), y_part.strip().replace(',', ' ').split()
opx_name, opy_name = x_parts[0].upper(), y_parts[0].upper()
opx, opy = autogen.VOPDOp[opx_name], autogen.VOPDOp[opy_name]
x_ops, y_ops = [parse_operand(p)[0] for p in x_parts[1:]], [parse_operand(p)[0] for p in y_parts[1:]]
vdstx, srcx0 = x_ops[0], x_ops[1] if len(x_ops) > 1 else 0
vsrcx1 = x_ops[2] if len(x_ops) > 2 else VGPR(0)
vdsty, srcy0 = y_ops[0], y_ops[1] if len(y_ops) > 1 else 0
vsrcy1 = y_ops[2] if len(y_ops) > 2 else VGPR(0)
return autogen.VOPD(opx, opy, vdstx=vdstx, vdsty=vdsty, srcx0=srcx0, vsrcx1=vsrcx1, srcy0=srcy0, vsrcy1=vsrcy1)
operands, current, depth, in_pipe = [], "", 0, False
for ch in op_str:
if ch == '[': depth += 1
+2 -2
View File
@@ -1,6 +1,6 @@
# autogenerated from AMD RDNA3.5 ISA PDF by gen.py - do not edit
from enum import IntEnum
from extra.assembly.rdna3.lib import bits, Inst32, Inst64, SGPR, VGPR, TTMP as TTMP, s as s, v as v, SSrc, Src, SImm, Imm
from extra.assembly.rdna3.lib import bits, Inst32, Inst64, SGPR, VGPR, TTMP as TTMP, s as s, v as v, SSrc, Src, SImm, Imm, VDSTYEnc
import functools
class SrcEnum(IntEnum):
@@ -1818,7 +1818,7 @@ class VOPD(Inst64):
opx:VOPDOp = bits[25:22]
opy:VOPDOp = bits[21:17]
vdstx:VGPR = bits[63:56]
vdsty:VGPR = bits[55:49]
vdsty:VDSTYEnc = bits[55:49]
srcx0:Src = bits[8:0]
vsrcx1:VGPR = bits[16:9]
srcy0:Src = bits[40:32]
+7 -2
View File
@@ -37,6 +37,7 @@ class SSrc: pass
class Src: pass
class Imm: pass
class SImm: pass
class VDSTYEnc: pass # VOPD vdsty: encoded = actual >> 1, actual = (encoded << 1) | ((vdstx & 1) ^ 1)
class RawImm:
def __init__(self, val: int): self.val = val
def __repr__(self): return f"RawImm({self.val})"
@@ -47,7 +48,7 @@ def unwrap(val) -> int:
# Encoding helpers
FLOAT_ENC = {0.5: 240, -0.5: 241, 1.0: 242, -1.0: 243, 2.0: 244, -2.0: 245, 4.0: 246, -4.0: 247}
SRC_FIELDS = {'src0', 'src1', 'src2', 'ssrc0', 'ssrc1', 'soffset'}
SRC_FIELDS = {'src0', 'src1', 'src2', 'ssrc0', 'ssrc1', 'soffset', 'srcx0', 'srcy0'}
RAW_FIELDS = {'vdata', 'vdst', 'vaddr', 'addr', 'data', 'data0', 'data1', 'sdst', 'sdata'}
def encode_src(val) -> int:
@@ -112,6 +113,9 @@ class Inst:
self._values[name] = val.idx // 2
elif name in {'srsrc', 'ssamp'} and isinstance(val, Reg):
self._values[name] = val.idx // 4
# VOPD vdsty: encode as actual >> 1 (constraint: vdsty parity must be opposite of vdstx)
elif ann is VDSTYEnc and isinstance(val, VGPR):
self._values[name] = val.idx >> 1
def _encode_field(self, name: str, val) -> int:
if isinstance(val, RawImm): return val.val
@@ -163,8 +167,9 @@ class Inst:
def __repr__(self):
# Use _fields order and exclude fields that are 0/default (for consistent repr after roundtrip)
def is_zero(v): return (isinstance(v, int) and v == 0) or (isinstance(v, VGPR) and v.idx == 0 and v.count == 1)
items = [(k, self._values[k]) for k in self._fields if k in self._values and k != 'encoding'
and not (isinstance(self._values[k], int) and self._values[k] == 0 and k not in {'op'})]
and not (is_zero(self._values[k]) and k not in {'op'})]
lit = f", literal={hex(self._literal)}" if self._literal is not None else ""
return f"{self.__class__.__name__}({', '.join(f'{k}={v}' for k, v in items)}{lit})"
File diff suppressed because it is too large Load Diff
@@ -76,5 +76,8 @@ class TestIntegration(unittest.TestCase):
def test_large_imm(self):
self.inst = v_mov_b32_e32(v[0], 0x1234)
def test_dual_mov(self):
self.inst = VOPD(VOPDOp.V_DUAL_MOV_B32, VOPDOp.V_DUAL_MOV_B32, vdstx=v[0], vdsty=v[1], srcx0=v[2], srcy0=v[4])
if __name__ == "__main__":
unittest.main()