rexcode/arm64: system registers get a type instead of being bare i64

They were plain i64 constants handed to op_imm, so any integer typed as
one and `inst_mrs(X0, 999999)` compiled fine. Worse, the printer could
not tell a system register from an immediate and had to recover the
distinction by mnemonic and slot -- MSR's other form holds a PSTATE
field selector in the same position, so it keyed off whether operand 1
was a register.

System_Register is now its own type with its own Operand_Kind, union
member and op_sysreg constructor, exactly as Cond is. The printer's slot
logic is gone: the operand knows what it is, so naming it is a case in
the same switch that prints every other operand kind. MSR's PSTATE
selector is typed PSTATE_FIELD, which is what it always was.

It cannot join `Register` itself: that is a u16 with the class in its
high byte, leaving 8 bits for the number, and a system register needs
15. Widening it would break `Memory`, which packs two registers plus a
displacement and a mode into exactly 64 bits.

The constants are also reorganised. They had accreted into overlapping
sections -- two "ID registers" groups, three cache groups, a "Batch 5:
comprehensive sysreg sweep" banner, and a "hmm let me recompute" note
left in a comment. All 231 are now grouped by architectural function
(18 groups, alphabetical within each) with their five fields aligned.

Verified unchanged against llvm-mc: 222 registers byte-exact through
MRS, 8 write-only through MSR, and the PSTATE form still decodes as an
immediate rather than a register.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UmHLRF11EoWwNWCJ7JGaA
This commit is contained in:
Brendan Punsky
2026-08-27 09:59:15 -04:00
committed by Flāvius
parent 47b637e862
commit dcaab1aa85
14 changed files with 375 additions and 391 deletions

View File

@@ -203,7 +203,7 @@ extract_operand_inline :: #force_inline proc "contextless" (
case .NZCV_FIELD:
return Operand{immediate = i64(word & 0xF), kind = .IMMEDIATE, size = 1}
case .SYS_FIELD:
return Operand{immediate = i64((word >> 5) & 0x7FFF), kind = .IMMEDIATE, size = 2}
return Operand{sysreg = System_Register((word >> 5) & 0x7FFF), kind = .SYSTEM_REGISTER, size = 2}
case .HINT_FIELD:
return Operand{immediate = i64((word >> 5) & 0x7F), kind = .IMMEDIATE, size = 1}
case .BARRIER_FIELD:

View File

@@ -277,8 +277,10 @@ operand_matches_inline :: #force_inline proc "contextless" (
return op.kind == .IMMEDIATE
case .IMM_12, .IMM_16, .IMM_8, .IMM_6, .IMM_5, .IMM_4, .IMM_3, .IMM_2,
.NZCV_IMM, .SYS_REG, .HW_SHIFT, .LSE_SIZE, .VEC_SHIFT, .VEC_INDEX:
.NZCV_IMM, .PSTATE_FIELD, .HW_SHIFT, .LSE_SIZE, .VEC_SHIFT, .VEC_INDEX:
return op.kind == .IMMEDIATE
case .SYS_REG:
return op.kind == .SYSTEM_REGISTER
case .BITMASK_IMM:
// The user passes the raw logical mask value; we validate that it
// fits the AArch64 bitmask-immediate encoding at the form's width.
@@ -390,7 +392,7 @@ pack_operand_inline :: #force_inline proc(
return (u32(reg_hw(op.extended.reg)) & 0x1F) << 16 |
(u32(op.extended.extend) & 0x7) << 13 |
(u32(op.extended.amount) & 0x7) << 10
case .NONE, .IMMEDIATE, .MEMORY, .RELATIVE, .COND:
case .NONE, .IMMEDIATE, .MEMORY, .RELATIVE, .COND, .SYSTEM_REGISTER:
return 0
}
@@ -417,7 +419,7 @@ pack_operand_inline :: #force_inline proc(
case .NZCV_FIELD:
return (u32(op.immediate) & 0xF) << 0
case .SYS_FIELD:
return (u32(op.immediate) & 0x7FFF) << 5
return (u32(op.sysreg) & 0x7FFF) << 5
case .HINT_FIELD:
return (u32(op.immediate) & 0x7F) << 5
case .BARRIER_FIELD:

View File

@@ -150,7 +150,9 @@ Operand_Type :: enum u8 {
IMM_4, // 4-bit (HINT, DMB/DSB barrier types, NZCV flags)
IMM_2, // 2-bit (FP rounding mode / NEON cmode bits 14:13 etc.)
NZCV_IMM, // 4-bit NZCV for CCMP/CCMN immediate forms
SYS_REG, // 16-bit system register encoding (MSR/MRS)
SYS_REG, // MRS/MSR target system register
PSTATE_FIELD, // MSR immediate form: a PSTATE field selector,
// a different namespace from the system registers
HW_SHIFT, // 2-bit LSL hw (0/16/32/48) for MOV-immediate
BITMASK_IMM, // Logical immediate (bitmask-encoded N:imms:immr)
LSE_SIZE, // 2-bit size selector for LSE atomics (00=B 01=H 10=W 11=X)

View File

@@ -345,12 +345,12 @@ inst_sevl_none :: #force_inline proc "contextless" () -> Instruction {
emit_sevl_none :: #force_inline proc(instructions: ^[dynamic]Instruction) { append(instructions, inst_sevl_none()) }
inst_hint_i :: #force_inline proc "contextless" (imm: i64) -> Instruction { return Instruction{mnemonic = .HINT, operand_count = 1, length = 4, ops = {op_imm(imm, 1), {}, {}, {}}} }
emit_hint_i :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64) { append(instructions, inst_hint_i(imm)) }
inst_mrs_r_i :: #force_inline proc "contextless" (dst: Register, imm: i64) -> Instruction { return inst_r_i(.MRS, dst, imm) }
emit_mrs_r_i :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, imm: i64) { append(instructions, inst_mrs_r_i(dst, imm)) }
inst_mrs_r_s :: #force_inline proc "contextless" (dst: Register, sysreg: System_Register) -> Instruction { return Instruction{mnemonic = .MRS, operand_count = 2, length = 4, ops = {op_reg(dst), op_sysreg(sysreg), {}, {}}} }
emit_mrs_r_s :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, sysreg: System_Register) { append(instructions, inst_mrs_r_s(dst, sysreg)) }
inst_msr_i_i :: #force_inline proc "contextless" (imm: i64, imm2: i64) -> Instruction { return Instruction{mnemonic = .MSR, operand_count = 2, length = 4, ops = {op_imm(imm, 4), op_imm(imm2, 1), {}, {}}} }
inst_msr_i_r :: #force_inline proc "contextless" (imm: i64, src: Register) -> Instruction { return Instruction{mnemonic = .MSR, operand_count = 2, length = 4, ops = {op_imm(imm, 4), op_reg(src), {}, {}}} }
inst_msr_s_r :: #force_inline proc "contextless" (sysreg: System_Register, src: Register) -> Instruction { return Instruction{mnemonic = .MSR, operand_count = 2, length = 4, ops = {op_sysreg(sysreg), op_reg(src), {}, {}}} }
emit_msr_i_i :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64, imm2: i64) { append(instructions, inst_msr_i_i(imm, imm2)) }
emit_msr_i_r :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64, src: Register) { append(instructions, inst_msr_i_r(imm, src)) }
emit_msr_s_r :: #force_inline proc(instructions: ^[dynamic]Instruction, sysreg: System_Register, src: Register) { append(instructions, inst_msr_s_r(sysreg, src)) }
inst_isb_i :: #force_inline proc "contextless" (imm: i64) -> Instruction { return Instruction{mnemonic = .ISB, operand_count = 1, length = 4, ops = {op_imm(imm, 1), {}, {}, {}}} }
emit_isb_i :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64) { append(instructions, inst_isb_i(imm)) }
inst_dsb_i :: #force_inline proc "contextless" (imm: i64) -> Instruction { return Instruction{mnemonic = .DSB, operand_count = 1, length = 4, ops = {op_imm(imm, 1), {}, {}, {}}} }
@@ -2216,10 +2216,10 @@ inst_sevl :: inst_sevl_none
emit_sevl :: emit_sevl_none
inst_hint :: inst_hint_i
emit_hint :: emit_hint_i
inst_mrs :: inst_mrs_r_i
emit_mrs :: emit_mrs_r_i
inst_msr :: proc{ inst_msr_i_i, inst_msr_i_r }
emit_msr :: proc{ emit_msr_i_i, emit_msr_i_r }
inst_mrs :: inst_mrs_r_s
emit_mrs :: emit_mrs_r_s
inst_msr :: proc{ inst_msr_i_i, inst_msr_s_r }
emit_msr :: proc{ emit_msr_i_i, emit_msr_s_r }
inst_isb :: inst_isb_i
emit_isb :: emit_isb_i
inst_dsb :: inst_dsb_i

View File

@@ -28,6 +28,7 @@ Operand_Kind :: enum u8 {
SHIFTED_REG, // X reg + shift type + shift amount
EXTENDED_REG, // X/W reg + extend + amount
COND, // 4-bit condition code (EQ/NE/.../AL/NV)
SYSTEM_REGISTER, // MRS/MSR target, as a packed 15-bit field
}
Shift_Type :: enum u8 {
@@ -104,6 +105,7 @@ Operand :: struct #packed {
shifted: Shifted_Reg, // 8
extended: Extended_Reg, // 8
cond: u8, // 1
sysreg: System_Register, // 2
}, // 12 total because of alignment
kind: Operand_Kind, // 1
size: u8, // 1 -- carried width info; meaning varies
@@ -151,6 +153,10 @@ op_cond :: #force_inline proc "contextless" (c: Cond) -> Operand {
return Operand{cond = u8(c), kind = .COND, size = 1}
}
op_sysreg :: #force_inline proc "contextless" (sr: System_Register) -> Operand {
return Operand{sysreg = sr, kind = .SYSTEM_REGISTER, size = 2}
}
// -----------------------------------------------------------------------------
// SVE Z-register builders -- encode the element arrangement in op.size
// (B=1, H=2, S=4, D=8). Matcher uses op.size to disambiguate the right

View File

@@ -118,20 +118,6 @@ sbprint :: proc(
// MOVZ/MOVN/MOVK store the shift as an hw index (0..3 = LSL #0/16/32/48),
// which assemblers write as `lsl #16` and omit entirely when it is zero.
// MRS/MSR carry the system register as a packed field, so it has to be
// printed by name -- a bare number is not something an assembler takes.
// MSR's other form takes a PSTATE field selector in the same slot,
// which is a different namespace; it is the one whose second operand
// is an immediate rather than a register.
sysreg_slot, sysreg_ok := -1, false
#partial switch inst.mnemonic {
case .MRS:
sysreg_slot, sysreg_ok = 1, inst.operand_count >= 2
case .MSR:
sysreg_slot = 0
sysreg_ok = inst.operand_count >= 2 && inst.ops[1].kind == .REGISTER
}
mov_wide := inst.mnemonic == .MOVZ || inst.mnemonic == .MOVN || inst.mnemonic == .MOVK
end_slot := int(inst.operand_count)
if mov_wide && end_slot == 3 && inst.ops[2].kind == .IMMEDIATE && inst.ops[2].immediate == 0 {
@@ -148,8 +134,6 @@ sbprint :: proc(
if mov_wide && slot == 2 {
strings.write_string(sb, opts.uppercase ? "LSL #" : "lsl #")
write_decimal_u32(sb, u32(inst.ops[slot].immediate) * 16)
} else if slot == sysreg_slot && sysreg_ok {
write_sysreg(sb, inst.ops[slot].immediate, opts.uppercase)
} else {
write_operand(sb, &inst.ops[slot], &display, opts)
}
@@ -359,11 +343,11 @@ write_mnemonic :: proc(sb: ^strings.Builder, m: Mnemonic, uppercase: bool) {
// A system register by name (`cntvct_el0`), falling back to the raw field
// when it is not one we know.
@(private="file")
write_sysreg :: proc(sb: ^strings.Builder, value: i64, uppercase: bool) {
name, ok := sysreg_name(value)
write_sysreg :: proc(sb: ^strings.Builder, sr: System_Register, uppercase: bool) {
name, ok := sysreg_name(sr)
if !ok {
strings.write_byte(sb, '#')
write_signed_decimal(sb, value)
write_signed_decimal(sb, i64(sr))
return
}
for i in 0 ..< len(name) {
@@ -490,6 +474,9 @@ write_operand :: proc(
strings.write_byte(sb, '#')
write_signed_decimal(sb, op.immediate)
case .SYSTEM_REGISTER:
write_sysreg(sb, op.sysreg, opts.uppercase)
case .COND:
c := op.cond & 0xF
s := COND_NAMES[c]

View File

@@ -103,41 +103,41 @@ V28 :: Register(REG_V | 28); V29 :: Register(REG_V | 29); V30 :: Register(REG_V
@(require_results) w_reg :: #force_inline proc "contextless" (n: u8) -> Register { return Register(REG_W | u16(n & 0x1F)) }
// =============================================================================
// AArch64 SYSTEM REGISTERS (named constants for MRS / MSR)
// AArch64 SYSTEM REGISTERS (MRS / MSR)
// =============================================================================
//
// The MRS / MSR instructions encode the target system register as a 15-bit
// field at bits 19:5 of the instruction word:
// A system register does not fit `Register`: that is a u16 carrying the class
// in its high byte, which leaves 8 bits for the number, and a system register
// needs 15. Widening it is not free either -- `Memory` packs two of them plus
// a displacement and a mode into exactly 64 bits. So this is its own type
// alongside `Register`, the way `Cond` is, with its own Operand_Kind and its
// own `op_sysreg` constructor.
//
// o0 (1 bit) : op0 - 2 (op0 = 2 -> o0=0; op0 = 3 -> o0=1)
// op1 (3 bit) : op1
// CRn (4 bit) : CRn
// CRm (4 bit) : CRm
// op2 (3 bit) : op2
// MRS / MSR name their target as a 15-bit field at bits 19:5 of the word,
// packed MSB-first as o0 || op1 || CRn || CRm || op2:
//
// concatenated MSB-first: o0 || op1 || CRn || CRm || op2.
// o0 (1 bit) op0 - 2 (op0 = 2 -> 0, op0 = 3 -> 1)
// op1 (3 bits)
// CRn (4 bits)
// CRm (4 bits)
// op2 (3 bits)
//
// Users pass these as the immediate operand to `inst_*` builders or by
// hand, e.g.:
//
// MRS X0, NZCV -> op_imm(arm64.NZCV, 2)
//
// The encoder packs the field into SYS_FIELD at bits 19:5 via the standard
// `(imm & 0x7FFF) << 5` mask, so callers can pass either the raw 15-bit
// field value (preferred) or the historical 0x_DA10-style 16-bit form
// (top bit gets masked off).
// Each constant below carries those five fields in its comment, and every
// value is verified byte-exact against llvm-mc.
System_Register :: distinct u16
// -----------------------------------------------------------------------------
// Helper for building sysreg field values at compile time.
// sysreg_field(op0, op1, CRn, CRm, op2) = packed 15-bit field
// op0 must be 2 or 3 (the o0 bit = op0 - 2).
// Build a field value from the five architectural numbers, for a register this
// list does not name. op0 must be 2 or 3.
// -----------------------------------------------------------------------------
sysreg_field :: #force_inline proc "contextless" (op0, op1, CRn, CRm, op2: u32) -> i64 {
@(require_results)
sysreg_field :: #force_inline proc "contextless" (op0, op1, CRn, CRm, op2: u16) -> System_Register {
o0 := (op0 - 2) & 0x1
return i64(
return System_Register(
(o0 << 14) |
(op1 << 11) |
(op1 << 11) |
(CRn << 7) |
(CRm << 3) |
op2,
@@ -145,381 +145,357 @@ sysreg_field :: #force_inline proc "contextless" (op0, op1, CRn, CRm, op2: u32)
}
// -----------------------------------------------------------------------------
// Commonly-used named registers (the ones every disassembler knows about).
// Process state, exceptions and stack pointers
// -----------------------------------------------------------------------------
// op0 op1 CRn CRm op2
NZCV :: i64(0x5A10) // 3 3 4 2 0
DAIF :: i64(0x5A11) // 3 3 4 2 1
FPCR :: i64(0x5A20) // 3 3 4 4 0
FPSR :: i64(0x5A21) // 3 3 4 4 1
CURRENT_EL :: i64(0x4212) // 3 0 4 2 2
SP_EL0 :: i64(0x4208) // 3 0 4 1 0
SP_EL1 :: i64(0x6208) // 3 4 4 1 0
ELR_EL1 :: i64(0x4201) // 3 0 4 0 1
ELR_EL2 :: i64(0x6201) // 3 4 4 0 1
SPSR_EL1 :: i64(0x4200) // 3 0 4 0 0
SPSR_EL2 :: i64(0x6200) // 3 4 4 0 0
ESR_EL1 :: i64(0x4290) // 3 0 5 2 0
ESR_EL2 :: i64(0x6290) // 3 4 5 2 0
FAR_EL1 :: i64(0x4300) // 3 0 6 0 0
FAR_EL2 :: i64(0x6300) // 3 4 6 0 0
TPIDR_EL0 :: i64(0x5E82) // 3 3 13 0 2
TPIDRRO_EL0 :: i64(0x5E83) // 3 3 13 0 3
TPIDR_EL1 :: i64(0x4684) // 3 0 13 0 4 (corrected: 3 0 13 0 4 -> 4684 hmm let me recompute)
// Counters / system identity
CNTFRQ_EL0 :: i64(0x5F00) // 3 3 14 0 0
CNTPCT_EL0 :: i64(0x5F01) // 3 3 14 0 1
CNTVCT_EL0 :: i64(0x5F02) // 3 3 14 0 2
MIDR_EL1 :: i64(0x4000) // 3 0 0 0 0
MPIDR_EL1 :: i64(0x4005) // 3 0 0 0 5
DCZID_EL0 :: i64(0x5807) // 3 3 0 0 7 (used by __sve_max_vl-style probes too)
CTR_EL0 :: i64(0x5801) // 3 3 0 0 1
TCR_EL1 :: i64(0x4102) // 3 0 2 0 2
SCTLR_EL1 :: i64(0x4080) // 3 0 1 0 0
VBAR_EL1 :: i64(0x4600) // 3 0 12 0 0
HCR_EL2 :: i64(0x6088) // 3 4 1 1 0
TTBR0_EL1 :: i64(0x4100) // 3 0 2 0 0
TTBR1_EL1 :: i64(0x4101) // 3 0 2 0 1
// op0 op1 CRn CRm op2
AFSR0_EL1 :: System_Register(0x4288) // 3 0 5 1 0
AFSR1_EL1 :: System_Register(0x4289) // 3 0 5 1 1
CURRENT_EL :: System_Register(0x4212) // 3 0 4 2 2
DAIF :: System_Register(0x5A11) // 3 3 4 2 1
ELR_EL1 :: System_Register(0x4201) // 3 0 4 0 1
ELR_EL2 :: System_Register(0x6201) // 3 4 4 0 1
ELR_EL3 :: System_Register(0x7201) // 3 6 4 0 1
ESR_EL1 :: System_Register(0x4290) // 3 0 5 2 0
ESR_EL2 :: System_Register(0x6290) // 3 4 5 2 0
FAR_EL1 :: System_Register(0x4300) // 3 0 6 0 0
FAR_EL2 :: System_Register(0x6300) // 3 4 6 0 0
ISR_EL1 :: System_Register(0x4608) // 3 0 12 1 0
NZCV :: System_Register(0x5A10) // 3 3 4 2 0
SPSR_EL1 :: System_Register(0x4200) // 3 0 4 0 0
SPSR_EL2 :: System_Register(0x6200) // 3 4 4 0 0
SPSR_EL3 :: System_Register(0x7200) // 3 6 4 0 0
SP_EL0 :: System_Register(0x4208) // 3 0 4 1 0
SP_EL1 :: System_Register(0x6208) // 3 4 4 1 0
VBAR_EL1 :: System_Register(0x4600) // 3 0 12 0 0
VBAR_EL2 :: System_Register(0x6600) // 3 4 12 0 0
VBAR_EL3 :: System_Register(0x7600) // 3 6 12 0 0
// -----------------------------------------------------------------------------
// Identification registers (ID_AA64*_EL1) -- read-only feature bitmaps
// Floating-point control
// -----------------------------------------------------------------------------
ID_AA64ISAR0_EL1 :: i64(0x4030) // 3 0 0 6 0
ID_AA64ISAR1_EL1 :: i64(0x4031) // 3 0 0 6 1
ID_AA64ISAR2_EL1 :: i64(0x4032) // 3 0 0 6 2
ID_AA64PFR0_EL1 :: i64(0x4020) // 3 0 0 4 0
ID_AA64PFR1_EL1 :: i64(0x4021) // 3 0 0 4 1
ID_AA64DFR0_EL1 :: i64(0x4028) // 3 0 0 5 0
ID_AA64DFR1_EL1 :: i64(0x4029) // 3 0 0 5 1
ID_AA64MMFR0_EL1 :: i64(0x4038) // 3 0 0 7 0
ID_AA64MMFR1_EL1 :: i64(0x4039) // 3 0 0 7 1
ID_AA64MMFR2_EL1 :: i64(0x403A) // 3 0 0 7 2
// op0 op1 CRn CRm op2
FPCR :: System_Register(0x5A20) // 3 3 4 4 0
FPSR :: System_Register(0x5A21) // 3 3 4 4 1
MVFR0_EL1 :: System_Register(0x4018) // 3 0 0 3 0
MVFR1_EL1 :: System_Register(0x4019) // 3 0 0 3 1
MVFR2_EL1 :: System_Register(0x401A) // 3 0 0 3 2
// -----------------------------------------------------------------------------
// Performance Monitor Unit (PMU)
// Thread and process identity
// -----------------------------------------------------------------------------
PMCR_EL0 :: i64(0x5CE0) // 3 3 9 12 0
PMCNTENSET_EL0 :: i64(0x5CE1) // 3 3 9 12 1
PMCNTENCLR_EL0 :: i64(0x5CE2) // 3 3 9 12 2
PMOVSCLR_EL0 :: i64(0x5CE3) // 3 3 9 12 3
PMSWINC_EL0 :: i64(0x5CE4) // 3 3 9 12 4
PMSELR_EL0 :: i64(0x5CE5) // 3 3 9 12 5
PMCEID0_EL0 :: i64(0x5CE6) // 3 3 9 12 6
PMCEID1_EL0 :: i64(0x5CE7) // 3 3 9 12 7
PMCCNTR_EL0 :: i64(0x5CE8) // 3 3 9 13 0
PMUSERENR_EL0 :: i64(0x5CF0) // 3 3 9 14 0
// op0 op1 CRn CRm op2
CONTEXTIDR_EL1 :: System_Register(0x4681) // 3 0 13 0 1
TPIDR2_EL0 :: System_Register(0x5E85) // 3 3 13 0 5 (SME thread pointer 2)
TPIDRRO_EL0 :: System_Register(0x5E83) // 3 3 13 0 3
TPIDR_EL0 :: System_Register(0x5E82) // 3 3 13 0 2
TPIDR_EL1 :: System_Register(0x4684) // 3 0 13 0 4
TPIDR_EL2 :: System_Register(0x6682) // 3 4 13 0 2
TPIDR_EL3 :: System_Register(0x7682) // 3 6 13 0 2
// -----------------------------------------------------------------------------
// Memory attribute / context / control registers
// Identification -- read-only feature bitmaps
// -----------------------------------------------------------------------------
CONTEXTIDR_EL1 :: i64(0x4681) // 3 0 13 0 1
CPACR_EL1 :: i64(0x4082) // 3 0 1 0 2
MAIR_EL1 :: i64(0x4510) // 3 0 10 2 0
AMAIR_EL1 :: i64(0x4518) // 3 0 10 3 0
VTCR_EL2 :: i64(0x610A) // 3 4 2 1 2
VTTBR_EL2 :: i64(0x6108) // 3 4 2 1 0
ACTLR_EL1 :: i64(0x4081) // 3 0 1 0 1
AFSR0_EL1 :: i64(0x4288) // 3 0 5 1 0
AFSR1_EL1 :: i64(0x4289) // 3 0 5 1 1
ISR_EL1 :: i64(0x4608) // 3 0 12 1 0
// op0 op1 CRn CRm op2
CCSIDR_EL1 :: System_Register(0x4800) // 3 1 0 0 0
CLIDR_EL1 :: System_Register(0x4801) // 3 1 0 0 1
CSSELR_EL1 :: System_Register(0x5000) // 3 2 0 0 0
CTR_EL0 :: System_Register(0x5801) // 3 3 0 0 1
DCZID_EL0 :: System_Register(0x5807) // 3 3 0 0 7 (used by __sve_max_vl-style probes too)
GMID_EL1 :: System_Register(0x4804) // 3 1 0 0 4 (FEAT_MTE)
ID_AA64AFR0_EL1 :: System_Register(0x402C) // 3 0 0 5 4 (auxiliary)
ID_AA64AFR1_EL1 :: System_Register(0x402D) // 3 0 0 5 5
ID_AA64DFR0_EL1 :: System_Register(0x4028) // 3 0 0 5 0
ID_AA64DFR1_EL1 :: System_Register(0x4029) // 3 0 0 5 1
ID_AA64DFR2_EL1 :: System_Register(0x402A) // 3 0 0 5 2
ID_AA64ISAR0_EL1 :: System_Register(0x4030) // 3 0 0 6 0
ID_AA64ISAR1_EL1 :: System_Register(0x4031) // 3 0 0 6 1
ID_AA64ISAR2_EL1 :: System_Register(0x4032) // 3 0 0 6 2
ID_AA64ISAR3_EL1 :: System_Register(0x4033) // 3 0 0 6 3
ID_AA64MMFR0_EL1 :: System_Register(0x4038) // 3 0 0 7 0
ID_AA64MMFR1_EL1 :: System_Register(0x4039) // 3 0 0 7 1
ID_AA64MMFR2_EL1 :: System_Register(0x403A) // 3 0 0 7 2
ID_AA64PFR0_EL1 :: System_Register(0x4020) // 3 0 0 4 0
ID_AA64PFR1_EL1 :: System_Register(0x4021) // 3 0 0 4 1
ID_AA64SMFR0_EL1 :: System_Register(0x4025) // 3 0 0 4 5 (SME feature ID)
ID_AA64ZFR0_EL1 :: System_Register(0x4024) // 3 0 0 4 4 (SVE feature ID)
ID_AFR0_EL1 :: System_Register(0x400B) // 3 0 0 1 3
ID_DFR0_EL1 :: System_Register(0x400A) // 3 0 0 1 2
ID_ISAR0_EL1 :: System_Register(0x4010) // 3 0 0 2 0
ID_ISAR1_EL1 :: System_Register(0x4011) // 3 0 0 2 1
ID_ISAR2_EL1 :: System_Register(0x4012) // 3 0 0 2 2
ID_ISAR3_EL1 :: System_Register(0x4013) // 3 0 0 2 3
ID_ISAR4_EL1 :: System_Register(0x4014) // 3 0 0 2 4
ID_ISAR5_EL1 :: System_Register(0x4015) // 3 0 0 2 5
ID_ISAR6_EL1 :: System_Register(0x4017) // 3 0 0 2 7
ID_MMFR0_EL1 :: System_Register(0x400C) // 3 0 0 1 4
ID_MMFR1_EL1 :: System_Register(0x400D) // 3 0 0 1 5
ID_MMFR2_EL1 :: System_Register(0x400E) // 3 0 0 1 6
ID_MMFR3_EL1 :: System_Register(0x400F) // 3 0 0 1 7
ID_MMFR4_EL1 :: System_Register(0x4016) // 3 0 0 2 6
ID_MMFR5_EL1 :: System_Register(0x401E) // 3 0 0 3 6
ID_PFR0_EL1 :: System_Register(0x4008) // 3 0 0 1 0
ID_PFR1_EL1 :: System_Register(0x4009) // 3 0 0 1 1
ID_PFR2_EL1 :: System_Register(0x401C) // 3 0 0 3 4
MIDR_EL1 :: System_Register(0x4000) // 3 0 0 0 0
MPIDR_EL1 :: System_Register(0x4005) // 3 0 0 0 5
// -----------------------------------------------------------------------------
// Random number registers (v8.5-A FEAT_RNG)
// Pointer authentication keys (FEAT_PAuth)
// -----------------------------------------------------------------------------
RNDR :: i64(0x5920) // 3 3 2 4 0
RNDRRS :: i64(0x5921) // 3 3 2 4 1
// op0 op1 CRn CRm op2
APDAKEYHI_EL1 :: System_Register(0x4111) // 3 0 2 2 1
APDAKEYLO_EL1 :: System_Register(0x4110) // 3 0 2 2 0
APDBKEYHI_EL1 :: System_Register(0x4113) // 3 0 2 2 3
APDBKEYLO_EL1 :: System_Register(0x4112) // 3 0 2 2 2
APGAKEYHI_EL1 :: System_Register(0x4119) // 3 0 2 3 1
APGAKEYLO_EL1 :: System_Register(0x4118) // 3 0 2 3 0
APIAKEYHI_EL1 :: System_Register(0x4109) // 3 0 2 1 1
APIAKEYLO_EL1 :: System_Register(0x4108) // 3 0 2 1 0 (FEAT_PAuth)
APIBKEYHI_EL1 :: System_Register(0x410B) // 3 0 2 1 3
APIBKEYLO_EL1 :: System_Register(0x410A) // 3 0 2 1 2
// -----------------------------------------------------------------------------
// More ID registers
// Memory tagging (FEAT_MTE)
// -----------------------------------------------------------------------------
ID_AA64ZFR0_EL1 :: i64(0x4024) // 3 0 0 4 4 (SVE feature ID)
ID_AA64SMFR0_EL1 :: i64(0x4025) // 3 0 0 4 5 (SME feature ID)
ID_AA64AFR0_EL1 :: i64(0x402C) // 3 0 0 5 4 (auxiliary)
ID_AA64AFR1_EL1 :: i64(0x402D) // 3 0 0 5 5
// op0 op1 CRn CRm op2
GCR_EL1 :: System_Register(0x4086) // 3 0 1 0 6 (FEAT_MTE)
RGSR_EL1 :: System_Register(0x4085) // 3 0 1 0 5 (FEAT_MTE)
TFSRE0_EL1 :: System_Register(0x42B1) // 3 0 5 6 1 (FEAT_MTE)
TFSR_EL1 :: System_Register(0x42B0) // 3 0 5 6 0 (FEAT_MTE)
// -----------------------------------------------------------------------------
// Cache hierarchy + selection
// SVE and SME configuration
// -----------------------------------------------------------------------------
CCSIDR_EL1 :: i64(0x4800) // 3 1 0 0 0
CLIDR_EL1 :: i64(0x4801) // 3 1 0 0 1
CSSELR_EL1 :: i64(0x5000) // 3 2 0 0 0
// op0 op1 CRn CRm op2
SMCR_EL1 :: System_Register(0x4096) // 3 0 1 2 6 (FEAT_SME)
SMCR_EL2 :: System_Register(0x6096) // 3 4 1 2 6
SVCR :: System_Register(0x5A12) // 3 3 4 2 2 (FEAT_SME: SM + ZA bits)
ZCR_EL1 :: System_Register(0x4090) // 3 0 1 2 0 (FEAT_SVE)
ZCR_EL2 :: System_Register(0x6090) // 3 4 1 2 0
ZCR_EL3 :: System_Register(0x7090) // 3 6 1 2 0
// -----------------------------------------------------------------------------
// EL2 / EL3 control + return registers
// System control and memory management
// -----------------------------------------------------------------------------
SCTLR_EL2 :: i64(0x6080) // 3 4 1 0 0
SCTLR_EL3 :: i64(0x7080) // 3 6 1 0 0
SPSR_EL3 :: i64(0x7200) // 3 6 4 0 0
ELR_EL3 :: i64(0x7201) // 3 6 4 0 1
TPIDR_EL2 :: i64(0x6682) // 3 4 13 0 2
TPIDR_EL3 :: i64(0x7682) // 3 6 13 0 2 -- err, EL3 needs op1=6
HSTR_EL2 :: i64(0x608B) // 3 4 1 1 3
MDCR_EL2 :: i64(0x6089) // 3 4 1 1 1
CNTHCTL_EL2 :: i64(0x6708) // 3 4 14 1 0
DACR32_EL2 :: i64(0x6180) // 3 4 3 0 0
FPEXC32_EL2 :: i64(0x6298) // 3 4 5 3 0
VBAR_EL2 :: i64(0x6600) // 3 4 12 0 0
VBAR_EL3 :: i64(0x7600) // 3 6 12 0 0
TPIDR2_EL0 :: i64(0x5E85) // 3 3 13 0 5 (SME thread pointer 2)
// op0 op1 CRn CRm op2
ACTLR_EL1 :: System_Register(0x4081) // 3 0 1 0 1
AMAIR_EL1 :: System_Register(0x4518) // 3 0 10 3 0
CPACR_EL1 :: System_Register(0x4082) // 3 0 1 0 2
LORC_EL1 :: System_Register(0x4523) // 3 0 10 4 3
LOREA_EL1 :: System_Register(0x4521) // 3 0 10 4 1
LORID_EL1 :: System_Register(0x4527) // 3 0 10 4 7
LORN_EL1 :: System_Register(0x4522) // 3 0 10 4 2
LORSA_EL1 :: System_Register(0x4520) // 3 0 10 4 0
MAIR_EL1 :: System_Register(0x4510) // 3 0 10 2 0
PAR_EL1 :: System_Register(0x43A0) // 3 0 7 4 0
SCTLR_EL1 :: System_Register(0x4080) // 3 0 1 0 0
SCTLR_EL2 :: System_Register(0x6080) // 3 4 1 0 0
SCTLR_EL3 :: System_Register(0x7080) // 3 6 1 0 0
TCR_EL1 :: System_Register(0x4102) // 3 0 2 0 2
TTBR0_EL1 :: System_Register(0x4100) // 3 0 2 0 0
TTBR1_EL1 :: System_Register(0x4101) // 3 0 2 0 1
// -----------------------------------------------------------------------------
// Debug registers (op0 = 2)
// Generic timer
// -----------------------------------------------------------------------------
MDSCR_EL1 :: i64(0x0012) // 2 0 0 2 2
DSPSR_EL0 :: i64(0x5A28) // 3 3 4 5 0
DLR_EL0 :: i64(0x5A29) // 3 3 4 5 1
OSLAR_EL1 :: i64(0x0084) // 2 0 1 0 4 (op0=2 -> o0=0)
OSLSR_EL1 :: i64(0x008C) // 2 0 1 1 4
// op0 op1 CRn CRm op2
CNTFRQ_EL0 :: System_Register(0x5F00) // 3 3 14 0 0
CNTHCTL_EL2 :: System_Register(0x6708) // 3 4 14 1 0
CNTHP_CTL_EL2 :: System_Register(0x6711) // 3 4 14 2 1
CNTHP_CVAL_EL2 :: System_Register(0x6712) // 3 4 14 2 2
CNTHP_TVAL_EL2 :: System_Register(0x6710) // 3 4 14 2 0
CNTHV_CTL_EL2 :: System_Register(0x6719) // 3 4 14 3 1
CNTHV_CVAL_EL2 :: System_Register(0x671A) // 3 4 14 3 2
CNTHV_TVAL_EL2 :: System_Register(0x6718) // 3 4 14 3 0
CNTKCTL_EL1 :: System_Register(0x4708) // 3 0 14 1 0
CNTPCT_EL0 :: System_Register(0x5F01) // 3 3 14 0 1
CNTPS_CTL_EL1 :: System_Register(0x7F11) // 3 7 14 2 1
CNTPS_CVAL_EL1 :: System_Register(0x7F12) // 3 7 14 2 2
CNTPS_TVAL_EL1 :: System_Register(0x7F10) // 3 7 14 2 0
CNTP_CTL_EL0 :: System_Register(0x5F11) // 3 3 14 2 1
CNTP_CVAL_EL0 :: System_Register(0x5F12) // 3 3 14 2 2
CNTP_TVAL_EL0 :: System_Register(0x5F10) // 3 3 14 2 0
CNTVCT_EL0 :: System_Register(0x5F02) // 3 3 14 0 2
CNTVOFF_EL2 :: System_Register(0x6703) // 3 4 14 0 3
CNTV_CTL_EL0 :: System_Register(0x5F19) // 3 3 14 3 1
CNTV_CVAL_EL0 :: System_Register(0x5F1A) // 3 3 14 3 2
CNTV_TVAL_EL0 :: System_Register(0x5F18) // 3 3 14 3 0
// -----------------------------------------------------------------------------
// Cache / Memory feature extras
// Statistical profiling (FEAT_SPE)
// -----------------------------------------------------------------------------
RGSR_EL1 :: i64(0x4085) // 3 0 1 0 5 (FEAT_MTE)
GCR_EL1 :: i64(0x4086) // 3 0 1 0 6 (FEAT_MTE)
TFSR_EL1 :: i64(0x42B0) // 3 0 5 6 0 (FEAT_MTE)
TFSRE0_EL1 :: i64(0x42B1) // 3 0 5 6 1 (FEAT_MTE)
GMID_EL1 :: i64(0x4804) // 3 1 0 0 4 (FEAT_MTE)
// op0 op1 CRn CRm op2
PMBIDR_EL1 :: System_Register(0x44D7) // 3 0 9 10 7
PMBLIMITR_EL1 :: System_Register(0x44D0) // 3 0 9 10 0
PMBPTR_EL1 :: System_Register(0x44D1) // 3 0 9 10 1
PMBSR_EL1 :: System_Register(0x44D3) // 3 0 9 10 3
PMSCR_EL1 :: System_Register(0x44C8) // 3 0 9 9 0
PMSELR_EL0 :: System_Register(0x5CE5) // 3 3 9 12 5
PMSEVFR_EL1 :: System_Register(0x44CD) // 3 0 9 9 5
PMSFCR_EL1 :: System_Register(0x44CC) // 3 0 9 9 4
PMSICR_EL1 :: System_Register(0x44CA) // 3 0 9 9 2
PMSIDR_EL1 :: System_Register(0x44CF) // 3 0 9 9 7
PMSIRR_EL1 :: System_Register(0x44CB) // 3 0 9 9 3
PMSLATFR_EL1 :: System_Register(0x44CE) // 3 0 9 9 6
PMSWINC_EL0 :: System_Register(0x5CE4) // 3 3 9 12 4
// -----------------------------------------------------------------------------
// SME / SVE configuration
// Performance monitors
// -----------------------------------------------------------------------------
SVCR :: i64(0x5A12) // 3 3 4 2 2 (FEAT_SME: SM + ZA bits)
SMCR_EL1 :: i64(0x4096) // 3 0 1 2 6 (FEAT_SME)
SMCR_EL2 :: i64(0x6096) // 3 4 1 2 6
ZCR_EL1 :: i64(0x4090) // 3 0 1 2 0 (FEAT_SVE)
ZCR_EL2 :: i64(0x6090) // 3 4 1 2 0
ZCR_EL3 :: i64(0x7090) // 3 6 1 2 0
// op0 op1 CRn CRm op2
PMCCFILTR_EL0 :: System_Register(0x5F7F) // 3 3 14 15 7
PMCCNTR_EL0 :: System_Register(0x5CE8) // 3 3 9 13 0
PMCEID0_EL0 :: System_Register(0x5CE6) // 3 3 9 12 6
PMCEID1_EL0 :: System_Register(0x5CE7) // 3 3 9 12 7
PMCNTENCLR_EL0 :: System_Register(0x5CE2) // 3 3 9 12 2
PMCNTENSET_EL0 :: System_Register(0x5CE1) // 3 3 9 12 1
PMCR_EL0 :: System_Register(0x5CE0) // 3 3 9 12 0
PMINTENCLR_EL1 :: System_Register(0x44F2) // 3 0 9 14 2
PMINTENSET_EL1 :: System_Register(0x44F1) // 3 0 9 14 1
PMOVSCLR_EL0 :: System_Register(0x5CE3) // 3 3 9 12 3
PMUSERENR_EL0 :: System_Register(0x5CF0) // 3 3 9 14 0
// -----------------------------------------------------------------------------
// Cache / data prefetch hint controls
// Trace
// -----------------------------------------------------------------------------
PRSELR_EL1 :: i64(0x4311) // 3 0 6 2 1
APIAKEYLO_EL1 :: i64(0x4108) // 3 0 2 1 0 (FEAT_PAuth)
APIAKEYHI_EL1 :: i64(0x4109) // 3 0 2 1 1
APIBKEYLO_EL1 :: i64(0x410A) // 3 0 2 1 2
APIBKEYHI_EL1 :: i64(0x410B) // 3 0 2 1 3
APDAKEYLO_EL1 :: i64(0x4110) // 3 0 2 2 0
APDAKEYHI_EL1 :: i64(0x4111) // 3 0 2 2 1
APDBKEYLO_EL1 :: i64(0x4112) // 3 0 2 2 2
APDBKEYHI_EL1 :: i64(0x4113) // 3 0 2 2 3
APGAKEYLO_EL1 :: i64(0x4118) // 3 0 2 3 0
APGAKEYHI_EL1 :: i64(0x4119) // 3 0 2 3 1
// =============================================================================
// Batch 5: comprehensive sysreg sweep
// =============================================================================
// op0 op1 CRn CRm op2
TRBBASER_EL1 :: System_Register(0x44DA) // 3 0 9 11 2
TRBIDR_EL1 :: System_Register(0x44DF) // 3 0 9 11 7
TRBLIMITR_EL1 :: System_Register(0x44D8) // 3 0 9 11 0
TRBMAR_EL1 :: System_Register(0x44DC) // 3 0 9 11 4
TRBPTR_EL1 :: System_Register(0x44D9) // 3 0 9 11 1
TRBSR_EL1 :: System_Register(0x44DB) // 3 0 9 11 3
TRBTRG_EL1 :: System_Register(0x44DE) // 3 0 9 11 6
// ---- More ID registers (AArch32 + extras) ----
ID_AA64DFR2_EL1 :: i64(0x402A) // 3 0 0 5 2
ID_AA64ISAR3_EL1 :: i64(0x4033) // 3 0 0 6 3
ID_PFR0_EL1 :: i64(0x4008) // 3 0 0 1 0
ID_PFR1_EL1 :: i64(0x4009) // 3 0 0 1 1
ID_DFR0_EL1 :: i64(0x400A) // 3 0 0 1 2
ID_AFR0_EL1 :: i64(0x400B) // 3 0 0 1 3
ID_MMFR0_EL1 :: i64(0x400C) // 3 0 0 1 4
ID_MMFR1_EL1 :: i64(0x400D) // 3 0 0 1 5
ID_MMFR2_EL1 :: i64(0x400E) // 3 0 0 1 6
ID_MMFR3_EL1 :: i64(0x400F) // 3 0 0 1 7
ID_MMFR4_EL1 :: i64(0x4016) // 3 0 0 2 6
ID_MMFR5_EL1 :: i64(0x401E) // 3 0 0 3 6
ID_ISAR0_EL1 :: i64(0x4010) // 3 0 0 2 0
ID_ISAR1_EL1 :: i64(0x4011) // 3 0 0 2 1
ID_ISAR2_EL1 :: i64(0x4012) // 3 0 0 2 2
ID_ISAR3_EL1 :: i64(0x4013) // 3 0 0 2 3
ID_ISAR4_EL1 :: i64(0x4014) // 3 0 0 2 4
ID_ISAR5_EL1 :: i64(0x4015) // 3 0 0 2 5
ID_ISAR6_EL1 :: i64(0x4017) // 3 0 0 2 7
ID_PFR2_EL1 :: i64(0x401C) // 3 0 0 3 4
MVFR0_EL1 :: i64(0x4018) // 3 0 0 3 0
MVFR1_EL1 :: i64(0x4019) // 3 0 0 3 1
MVFR2_EL1 :: i64(0x401A) // 3 0 0 3 2
// -----------------------------------------------------------------------------
// Debug
// -----------------------------------------------------------------------------
// ---- Counter / Timer (full set) ----
CNTKCTL_EL1 :: i64(0x4708) // 3 0 14 1 0
CNTP_TVAL_EL0 :: i64(0x5F10) // 3 3 14 2 0
CNTP_CTL_EL0 :: i64(0x5F11) // 3 3 14 2 1
CNTP_CVAL_EL0 :: i64(0x5F12) // 3 3 14 2 2
CNTV_TVAL_EL0 :: i64(0x5F18) // 3 3 14 3 0
CNTV_CTL_EL0 :: i64(0x5F19) // 3 3 14 3 1
CNTV_CVAL_EL0 :: i64(0x5F1A) // 3 3 14 3 2
CNTHP_TVAL_EL2 :: i64(0x6710) // 3 4 14 2 0
CNTHP_CTL_EL2 :: i64(0x6711) // 3 4 14 2 1
CNTHP_CVAL_EL2 :: i64(0x6712) // 3 4 14 2 2
CNTHV_TVAL_EL2 :: i64(0x6718) // 3 4 14 3 0
CNTHV_CTL_EL2 :: i64(0x6719) // 3 4 14 3 1
CNTHV_CVAL_EL2 :: i64(0x671A) // 3 4 14 3 2
CNTPS_TVAL_EL1 :: i64(0x7F10) // 3 7 14 2 0
CNTPS_CTL_EL1 :: i64(0x7F11) // 3 7 14 2 1
CNTPS_CVAL_EL1 :: i64(0x7F12) // 3 7 14 2 2
CNTVOFF_EL2 :: i64(0x6703) // 3 4 14 0 3
// op0 op1 CRn CRm op2
DBGAUTHSTATUS_EL1 :: System_Register(0x03F6) // 2 0 7 14 6
DBGCLAIMCLR_EL1 :: System_Register(0x03CE) // 2 0 7 9 6
DBGCLAIMSET_EL1 :: System_Register(0x03C6) // 2 0 7 8 6
DBGDTRRX_EL0 :: System_Register(0x1828) // 2 3 0 5 0
DBGDTRTX_EL0 :: System_Register(0x1828) // 2 3 0 5 0 (write view of DBGDTRRX_EL0)
DBGDTR_EL0 :: System_Register(0x1820) // 2 3 0 4 0
DBGPRCR_EL1 :: System_Register(0x00A4) // 2 0 1 4 4
DLR_EL0 :: System_Register(0x5A29) // 3 3 4 5 1
DSPSR_EL0 :: System_Register(0x5A28) // 3 3 4 5 0
MDCCINT_EL1 :: System_Register(0x0010) // 2 0 0 2 0
MDRAR_EL1 :: System_Register(0x0080) // 2 0 1 0 0
MDSCR_EL1 :: System_Register(0x0012) // 2 0 0 2 2
OSLAR_EL1 :: System_Register(0x0084) // 2 0 1 0 4 (op0=2 -> o0=0)
OSLSR_EL1 :: System_Register(0x008C) // 2 0 1 1 4
PRSELR_EL1 :: System_Register(0x4311) // 3 0 6 2 1
// ---- Debug breakpoints (DBGB*) and watchpoints (DBGW*), numbered ----
//
// Each register file is 16 deep: DBGBVR0..15, DBGBCR0..15, DBGWVR0..15,
// DBGWCR0..15. Use the helper:
// sysreg_debug_breakpoint_value(n) -- DBGBVRn_EL1 = (2, 0, 0, n, 4)
// sysreg_debug_breakpoint_control(n) -- DBGBCRn_EL1 = (2, 0, 0, n, 5)
// sysreg_debug_watchpoint_value(n) -- DBGWVRn_EL1 = (2, 0, 0, n, 6)
// sysreg_debug_watchpoint_control(n) -- DBGWCRn_EL1 = (2, 0, 0, n, 7)
// -----------------------------------------------------------------------------
// Generic interrupt controller
// -----------------------------------------------------------------------------
sysreg_debug_breakpoint_value :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(2, 0, 0, n & 0xF, 4)
}
sysreg_debug_breakpoint_control :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(2, 0, 0, n & 0xF, 5)
}
sysreg_debug_watchpoint_value :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(2, 0, 0, n & 0xF, 6)
}
sysreg_debug_watchpoint_control :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(2, 0, 0, n & 0xF, 7)
}
// op0 op1 CRn CRm op2
ICC_ASGI1R_EL1 :: System_Register(0x465E) // 3 0 12 11 6
ICC_BPR0_EL1 :: System_Register(0x4643) // 3 0 12 8 3
ICC_BPR1_EL1 :: System_Register(0x4663) // 3 0 12 12 3
ICC_CTLR_EL1 :: System_Register(0x4664) // 3 0 12 12 4
ICC_CTLR_EL3 :: System_Register(0x7664) // 3 6 12 12 4
ICC_DIR_EL1 :: System_Register(0x4659) // 3 0 12 11 1
ICC_EOIR0_EL1 :: System_Register(0x4641) // 3 0 12 8 1
ICC_EOIR1_EL1 :: System_Register(0x4661) // 3 0 12 12 1
ICC_HPPIR0_EL1 :: System_Register(0x4642) // 3 0 12 8 2
ICC_HPPIR1_EL1 :: System_Register(0x4662) // 3 0 12 12 2
ICC_IAR0_EL1 :: System_Register(0x4640) // 3 0 12 8 0
ICC_IAR1_EL1 :: System_Register(0x4660) // 3 0 12 12 0
ICC_IGRPEN0_EL1 :: System_Register(0x4666) // 3 0 12 12 6
ICC_IGRPEN1_EL1 :: System_Register(0x4667) // 3 0 12 12 7
ICC_IGRPEN1_EL3 :: System_Register(0x7667) // 3 6 12 12 7
ICC_PMR_EL1 :: System_Register(0x4230) // 3 0 4 6 0
ICC_RPR_EL1 :: System_Register(0x465B) // 3 0 12 11 3
ICC_SGI0R_EL1 :: System_Register(0x465F) // 3 0 12 11 7
ICC_SGI1R_EL1 :: System_Register(0x465D) // 3 0 12 11 5
ICC_SRE_EL1 :: System_Register(0x4665) // 3 0 12 12 5
ICC_SRE_EL2 :: System_Register(0x664D) // 3 4 12 9 5
ICC_SRE_EL3 :: System_Register(0x7665) // 3 6 12 12 5
ICH_EISR_EL2 :: System_Register(0x665B) // 3 4 12 11 3
ICH_ELRSR_EL2 :: System_Register(0x665D) // 3 4 12 11 5
ICH_HCR_EL2 :: System_Register(0x6658) // 3 4 12 11 0
ICH_MISR_EL2 :: System_Register(0x665A) // 3 4 12 11 2
ICH_VMCR_EL2 :: System_Register(0x665F) // 3 4 12 11 7
ICH_VTR_EL2 :: System_Register(0x6659) // 3 4 12 11 1
// Other debug registers
DBGDTR_EL0 :: i64(0x1820) // 2 3 0 4 0
DBGDTRRX_EL0 :: i64(0x1828) // 2 3 0 5 0
DBGDTRTX_EL0 :: i64(0x1828) // 2 3 0 5 0 (write view of DBGDTRRX_EL0)
DBGPRCR_EL1 :: i64(0x00A4) // 2 0 1 4 4
DBGCLAIMSET_EL1 :: i64(0x03C6) // 2 0 7 8 6
DBGCLAIMCLR_EL1 :: i64(0x03CE) // 2 0 7 9 6
DBGAUTHSTATUS_EL1:: i64(0x03F6) // 2 0 7 14 6
MDCCINT_EL1 :: i64(0x0010) // 2 0 0 2 0
MDRAR_EL1 :: i64(0x0080) // 2 0 1 0 0
// -----------------------------------------------------------------------------
// RAS -- error record registers
// -----------------------------------------------------------------------------
// PMU event counters (PMEVCNTRn_EL0 / PMEVTYPERn_EL0). Up to n=30.
// PMEVCNTRn_EL0 = sysreg(3, 3, 14, 8+(n>>3), n & 7)
// PMEVTYPERn_EL0 = sysreg(3, 3, 14, 12+(n>>3), n & 7)
// op0 op1 CRn CRm op2
DISR_EL1 :: System_Register(0x4609) // 3 0 12 1 1
ERRIDR_EL1 :: System_Register(0x4298) // 3 0 5 3 0
ERRSELR_EL1 :: System_Register(0x4299) // 3 0 5 3 1
ERXADDR_EL1 :: System_Register(0x42A3) // 3 0 5 4 3
ERXCTLR_EL1 :: System_Register(0x42A1) // 3 0 5 4 1
ERXFR_EL1 :: System_Register(0x42A0) // 3 0 5 4 0
ERXMISC0_EL1 :: System_Register(0x42A8) // 3 0 5 5 0
ERXMISC1_EL1 :: System_Register(0x42A9) // 3 0 5 5 1
ERXMISC2_EL1 :: System_Register(0x42AA) // 3 0 5 5 2
ERXMISC3_EL1 :: System_Register(0x42AB) // 3 0 5 5 3
ERXSTATUS_EL1 :: System_Register(0x42A2) // 3 0 5 4 2
VDISR_EL2 :: System_Register(0x6609) // 3 4 12 1 1
VSESR_EL2 :: System_Register(0x6293) // 3 4 5 2 3
sysreg_pmu_event_counter :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(3, 3, 14, 8 + ((n >> 3) & 0x3), n & 0x7)
}
sysreg_pmu_event_typer :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(3, 3, 14, 12 + ((n >> 3) & 0x3), n & 0x7)
}
// -----------------------------------------------------------------------------
// Virtualisation (EL2) and secure monitor (EL3)
// -----------------------------------------------------------------------------
PMINTENSET_EL1 :: i64(0x44F1) // 3 0 9 14 1
PMINTENCLR_EL1 :: i64(0x44F2) // 3 0 9 14 2
// op0 op1 CRn CRm op2
GPCCR_EL3 :: System_Register(0x710E) // 3 6 2 1 6 (Granule Protection Control)
GPTBR_EL3 :: System_Register(0x710C) // 3 6 2 1 4 (Granule Protection Table Base)
HCR_EL2 :: System_Register(0x6088) // 3 4 1 1 0
HSTR_EL2 :: System_Register(0x608B) // 3 4 1 1 3
MDCR_EL2 :: System_Register(0x6089) // 3 4 1 1 1
MFAR_EL3 :: System_Register(0x7305) // 3 6 6 0 5 (Multiple FAR)
VTCR_EL2 :: System_Register(0x610A) // 3 4 2 1 2
VTTBR_EL2 :: System_Register(0x6108) // 3 4 2 1 0
// ---- GICv3 (ICC_*) -- CPU interface ----
ICC_IAR0_EL1 :: i64(0x4640) // 3 0 12 8 0
ICC_IAR1_EL1 :: i64(0x4660) // 3 0 12 12 0
ICC_EOIR0_EL1 :: i64(0x4641) // 3 0 12 8 1
ICC_EOIR1_EL1 :: i64(0x4661) // 3 0 12 12 1
ICC_HPPIR0_EL1 :: i64(0x4642) // 3 0 12 8 2
ICC_HPPIR1_EL1 :: i64(0x4662) // 3 0 12 12 2
ICC_BPR0_EL1 :: i64(0x4643) // 3 0 12 8 3
ICC_BPR1_EL1 :: i64(0x4663) // 3 0 12 12 3
ICC_DIR_EL1 :: i64(0x4659) // 3 0 12 11 1
ICC_PMR_EL1 :: i64(0x4230) // 3 0 4 6 0
ICC_RPR_EL1 :: i64(0x465B) // 3 0 12 11 3
ICC_SGI0R_EL1 :: i64(0x465F) // 3 0 12 11 7
ICC_SGI1R_EL1 :: i64(0x465D) // 3 0 12 11 5
ICC_ASGI1R_EL1 :: i64(0x465E) // 3 0 12 11 6
ICC_SRE_EL1 :: i64(0x4665) // 3 0 12 12 5
ICC_SRE_EL2 :: i64(0x664D) // 3 4 12 9 5
ICC_SRE_EL3 :: i64(0x7665) // 3 6 12 12 5
ICC_CTLR_EL1 :: i64(0x4664) // 3 0 12 12 4
ICC_CTLR_EL3 :: i64(0x7664) // 3 6 12 12 4
ICC_IGRPEN0_EL1 :: i64(0x4666) // 3 0 12 12 6
ICC_IGRPEN1_EL1 :: i64(0x4667) // 3 0 12 12 7
ICC_IGRPEN1_EL3 :: i64(0x7667) // 3 6 12 12 7
// -----------------------------------------------------------------------------
// AArch32 compatibility
// -----------------------------------------------------------------------------
// ---- GICv3 hypervisor (ICH_*) ----
ICH_HCR_EL2 :: i64(0x6658) // 3 4 12 11 0
ICH_VTR_EL2 :: i64(0x6659) // 3 4 12 11 1
ICH_MISR_EL2 :: i64(0x665A) // 3 4 12 11 2
ICH_EISR_EL2 :: i64(0x665B) // 3 4 12 11 3
ICH_ELRSR_EL2 :: i64(0x665D) // 3 4 12 11 5
ICH_VMCR_EL2 :: i64(0x665F) // 3 4 12 11 7
// op0 op1 CRn CRm op2
DACR32_EL2 :: System_Register(0x6180) // 3 4 3 0 0
FPEXC32_EL2 :: System_Register(0x6298) // 3 4 5 3 0
// ICH_LR0_EL2 .. ICH_LR15_EL2 = sysreg(3, 4, 12, 12+(n>>3), n & 7)
sysreg_ich_lr :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(3, 4, 12, 12 + ((n >> 3) & 0x1), n & 0x7)
}
// -----------------------------------------------------------------------------
// Random number (FEAT_RNG)
// -----------------------------------------------------------------------------
// ICH_AP0Rn_EL2 (n=0..3) and ICH_AP1Rn_EL2 (n=0..3)
sysreg_ich_ap0r :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(3, 4, 12, 8, n & 0x3)
}
sysreg_ich_ap1r :: #force_inline proc "contextless" (n: u32) -> i64 {
return sysreg_field(3, 4, 12, 9, n & 0x3)
}
// ---- TRBE (Trace Buffer Extension, FEAT_TRBE) ----
TRBLIMITR_EL1 :: i64(0x44D8) // 3 0 9 11 0
TRBPTR_EL1 :: i64(0x44D9) // 3 0 9 11 1
TRBBASER_EL1 :: i64(0x44DA) // 3 0 9 11 2
TRBSR_EL1 :: i64(0x44DB) // 3 0 9 11 3
TRBMAR_EL1 :: i64(0x44DC) // 3 0 9 11 4
TRBTRG_EL1 :: i64(0x44DE) // 3 0 9 11 6
TRBIDR_EL1 :: i64(0x44DF) // 3 0 9 11 7
// ---- SPE (Statistical Profiling Extension, FEAT_SPE) ----
PMSCR_EL1 :: i64(0x44C8) // 3 0 9 9 0
PMSICR_EL1 :: i64(0x44CA) // 3 0 9 9 2
PMSIRR_EL1 :: i64(0x44CB) // 3 0 9 9 3
PMSFCR_EL1 :: i64(0x44CC) // 3 0 9 9 4
PMSEVFR_EL1 :: i64(0x44CD) // 3 0 9 9 5
PMSLATFR_EL1 :: i64(0x44CE) // 3 0 9 9 6
PMSIDR_EL1 :: i64(0x44CF) // 3 0 9 9 7
PMBLIMITR_EL1 :: i64(0x44D0) // 3 0 9 10 0
PMBPTR_EL1 :: i64(0x44D1) // 3 0 9 10 1
PMBSR_EL1 :: i64(0x44D3) // 3 0 9 10 3
PMBIDR_EL1 :: i64(0x44D7) // 3 0 9 10 7
// ---- RAS (Reliability, Availability, Serviceability) ----
ERRSELR_EL1 :: i64(0x4299) // 3 0 5 3 1
ERRIDR_EL1 :: i64(0x4298) // 3 0 5 3 0
ERXADDR_EL1 :: i64(0x42A3) // 3 0 5 4 3
ERXCTLR_EL1 :: i64(0x42A1) // 3 0 5 4 1
ERXFR_EL1 :: i64(0x42A0) // 3 0 5 4 0
ERXSTATUS_EL1 :: i64(0x42A2) // 3 0 5 4 2
ERXMISC0_EL1 :: i64(0x42A8) // 3 0 5 5 0
ERXMISC1_EL1 :: i64(0x42A9) // 3 0 5 5 1
ERXMISC2_EL1 :: i64(0x42AA) // 3 0 5 5 2
ERXMISC3_EL1 :: i64(0x42AB) // 3 0 5 5 3
DISR_EL1 :: i64(0x4609) // 3 0 12 1 1
VDISR_EL2 :: i64(0x6609) // 3 4 12 1 1
VSESR_EL2 :: i64(0x6293) // 3 4 5 2 3
// ---- LOR (Limited Ordering Region) ----
LORC_EL1 :: i64(0x4523) // 3 0 10 4 3
LOREA_EL1 :: i64(0x4521) // 3 0 10 4 1
LORID_EL1 :: i64(0x4527) // 3 0 10 4 7
LORN_EL1 :: i64(0x4522) // 3 0 10 4 2
LORSA_EL1 :: i64(0x4520) // 3 0 10 4 0
// ---- Translation result (returned by AT) ----
PAR_EL1 :: i64(0x43A0) // 3 0 7 4 0
// ---- RME (Realm Management Extension) sysregs ----
GPCCR_EL3 :: i64(0x710E) // 3 6 2 1 6 (Granule Protection Control)
GPTBR_EL3 :: i64(0x710C) // 3 6 2 1 4 (Granule Protection Table Base)
MFAR_EL3 :: i64(0x7305) // 3 6 6 0 5 (Multiple FAR)
// ---- TPIDRRO_EL0 alias / extra thread pointers ----
// (TPIDRRO_EL0 already added above)
// ---- Performance Monitor extras ----
PMCCFILTR_EL0 :: i64(0x5F7F) // 3 3 14 15 7
PMUSERENR_EL0_REPEAT :: PMUSERENR_EL0 // re-export alias placeholder
// op0 op1 CRn CRm op2
RNDR :: System_Register(0x5920) // 3 3 2 4 0
RNDRRS :: System_Register(0x5921) // 3 3 2 4 1
// -----------------------------------------------------------------------------
// Value -> name, for printing
// -----------------------------------------------------------------------------
//
// MRS/MSR carry the system register as a packed 15-bit field, so a disassembly
// has a number where an assembler wants a name. Sorted by value; binary search.
// A disassembly has the packed field where an assembler wants a name. Sorted
// by value; binary search.
//
// 1 encodings carry two names. Where the pair is a read view and a write
// view of one register (DBGDTRRX/DBGDTRTX) the read name wins, since MRS is
// the direction that has to print; the rest are genuine aliases and either
// name assembles, so a round-trip can come back spelled as the sibling.
// 1 encoding carries two names: DBGDTRRX_EL0 and DBGDTRTX_EL0 are the read
// and write views of one register. The read name wins, since MRS is the
// direction that has to print.
Sysreg_Name :: struct {
value: u16,
value: System_Register,
name: string,
}
@@ -757,11 +733,11 @@ SYSREG_NAMES := [?]Sysreg_Name{
{0x7F12, "cntps_cval_el1"},
}
// Name for a packed system-register field, or ok=false when it is not one we
// know -- callers should fall back to printing the raw immediate.
// Name for a system register, or ok=false when it is not one we know --
// callers should fall back to printing the raw field.
@(require_results)
sysreg_name :: proc "contextless" (value: i64) -> (name: string, ok: bool) {
v := u16(value & 0x7FFF)
sysreg_name :: proc "contextless" (sr: System_Register) -> (name: string, ok: bool) {
v := System_Register(u16(sr) & 0x7FFF)
lo, hi := 0, len(SYSREG_NAMES) - 1
for lo <= hi {
mid := (lo + hi) / 2

View File

@@ -1955,7 +1955,7 @@ DECODE_ENTRIES := [2498]lib.Decode_Entry{
{ .TLBI_VAALE1, {.X_REG,.NONE,.NONE,.NONE}, {.RT,.NONE,.NONE,.NONE}, 0xD50887E0, 0xFFFFFFE0, .BASE, {is_64=true, explicit_count=1} },
{ .TLBI_VAALE1IS, {.X_REG,.NONE,.NONE,.NONE}, {.RT,.NONE,.NONE,.NONE}, 0xD50883E0, 0xFFFFFFE0, .BASE, {is_64=true, explicit_count=1} },
{ .HINT, {.IMM_8,.NONE,.NONE,.NONE}, {.HINT_FIELD,.NONE,.NONE,.NONE}, 0xD503201F, 0xFFFFF01F, .BASE, {explicit_count=1} },
{ .MSR, {.SYS_REG,.IMM_4,.NONE,.NONE}, {.MSR_PSTATE,.BARRIER_FIELD,.NONE,.NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {explicit_count=2} },
{ .MSR, {.PSTATE_FIELD,.IMM_4,.NONE,.NONE}, {.MSR_PSTATE,.BARRIER_FIELD,.NONE,.NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {explicit_count=2} },
{ .SVC, {.IMM_16,.NONE,.NONE,.NONE}, {.IMM16,.NONE,.NONE,.NONE}, 0xD4000001, 0xFFE0001F, .BASE, {branch=true, explicit_count=1} },
{ .HVC, {.IMM_16,.NONE,.NONE,.NONE}, {.IMM16,.NONE,.NONE,.NONE}, 0xD4000002, 0xFFE0001F, .BASE, {branch=true, explicit_count=1} },
{ .SMC, {.IMM_16,.NONE,.NONE,.NONE}, {.IMM16,.NONE,.NONE,.NONE}, 0xD4000003, 0xFFE0001F, .BASE, {branch=true, explicit_count=1} },

View File

@@ -492,7 +492,7 @@ ENCODE_FORMS := [2496]lib.Encoding{
// .MRS
{ .MRS, {.X_REG,.SYS_REG,.NONE,.NONE}, {.RT,.SYS_FIELD,.NONE,.NONE}, 0xD5300000, 0xFFF00000, .BASE, {explicit_count=2} },
// .MSR
{ .MSR, {.SYS_REG,.IMM_4,.NONE,.NONE}, {.MSR_PSTATE,.BARRIER_FIELD,.NONE,.NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {explicit_count=2} },
{ .MSR, {.PSTATE_FIELD,.IMM_4,.NONE,.NONE}, {.MSR_PSTATE,.BARRIER_FIELD,.NONE,.NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {explicit_count=2} },
{ .MSR, {.SYS_REG,.X_REG,.NONE,.NONE}, {.SYS_FIELD,.RT,.NONE,.NONE}, 0xD5100000, 0xFFF00000, .BASE, {explicit_count=2} },
// .ISB
{ .ISB, {.IMM_4,.NONE,.NONE,.NONE}, {.BARRIER_FIELD,.NONE,.NONE,.NONE}, 0xD50330DF, 0xFFFFF0FF, .BASE, {explicit_count=1} },

View File

@@ -691,7 +691,7 @@ INSTRUCTION_TABLE := [Mnemonic][]Form{
{{.MRS, {.X_REG, .SYS_REG, .NONE, .NONE}, {.RT, .SYS_FIELD, .NONE, .NONE}, 0xD5300000, 0xFFF00000, .BASE, {}}, {written={0}, read={1}, side_effects={.PRIVILEGED}}},
},
.MSR = {
{{.MSR, {.SYS_REG, .IMM_4, .NONE, .NONE}, {.MSR_PSTATE, .BARRIER_FIELD, .NONE, .NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {}}, {side_effects={.PRIVILEGED}}},
{{.MSR, {.PSTATE_FIELD, .IMM_4, .NONE, .NONE}, {.MSR_PSTATE, .BARRIER_FIELD, .NONE, .NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {}}, {side_effects={.PRIVILEGED}}},
{{.MSR, {.SYS_REG, .X_REG, .NONE, .NONE}, {.SYS_FIELD, .RT, .NONE, .NONE}, 0xD5100000, 0xFFF00000, .BASE, {}}, {written={0}, read={1}, side_effects={.PRIVILEGED}}},
},
.ISB = {

View File

@@ -312,7 +312,7 @@ run_pipeline_tests :: proc() {
},
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X0), a.op_imm(0xDA10, 2), {}, {}},
ops = {a.op_reg(a.X0), a.op_sysreg(a.NZCV), {}, {}},
},
}
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
@@ -698,19 +698,19 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X0), a.op_imm(a.NZCV, 2), {}, {}},
ops = {a.op_reg(a.X0), a.op_sysreg(a.NZCV), {}, {}},
},
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X1), a.op_imm(a.TPIDR_EL0, 2), {}, {}},
ops = {a.op_reg(a.X1), a.op_sysreg(a.TPIDR_EL0), {}, {}},
},
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X2), a.op_imm(a.CNTVCT_EL0, 2), {}, {}},
ops = {a.op_reg(a.X2), a.op_sysreg(a.CNTVCT_EL0), {}, {}},
},
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X3), a.op_imm(a.DCZID_EL0, 2), {}, {}},
ops = {a.op_reg(a.X3), a.op_sysreg(a.DCZID_EL0), {}, {}},
},
}
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
@@ -958,7 +958,7 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.Instruction{
mnemonic = .MRS, operand_count = 2, length = 4,
ops = {a.op_reg(a.X7), a.op_imm(a.RNDR, 2), {}, {}},
ops = {a.op_reg(a.X7), a.op_sysreg(a.RNDR), {}, {}},
},
}
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)

View File

@@ -12,7 +12,7 @@ package main
// with per-mnemonic overload groups.
//
// AArch64 has ~50 operand types, many exotic (SVE/SME/NEON-arrangement/
// shifted/extended/bitmask/sysreg). EVERY operand type is now mapped to a
// shifted/extended/bitmask/system-register). EVERY operand type is mapped to a
// concrete Odin parameter (or parameters) and a constructor expression, so
// NO form is skipped: every mnemonic that has at least one encode form gets
// an inst_<mnem> / emit_<mnem> overload group.
@@ -26,7 +26,8 @@ package main
// SVE Z register / Z pair / Z quad -> u8 / op_z_* (suffix z)
// SVE predicate (P_REG / merge / zero / gov) -> u8 / Register(REG_P|..) (suffix p)
// all immediates (incl ZA tile, SME slice, -> i64 / op_imm (suffix i)
// patterns, bitmask, sysreg, HW, NZCV, ...)
// patterns, bitmask, HW, NZCV, ...)
// MRS/MSR system register -> System_Register / op_sysreg (suffix s)
// PC-relative label -> u32 / op_label (suffix l)
// memory -> Memory / op_mem (suffix m)
// condition code -> Cond / op_cond (suffix c)
@@ -69,6 +70,7 @@ Operand_Category :: enum {
REL, // u32 label -> op_label (1 param, suffix l)
MEM, // Memory -> op_mem (1 param, suffix m)
COND, // Cond -> op_cond (1 param, suffix c)
SYSREG, // System_Register -> op_sysreg (1 param, suffix s)
SHIFTED, // Register + Shift_Type + u8 -> op_shifted (3 params, suffix sh)
EXTENDED, // Register + Extend + u8 -> op_extended (3 params, suffix ex)
}
@@ -133,6 +135,8 @@ operand_category :: proc(t: a.Operand_Type) -> Operand_Category {
return .MEM
case .COND, .COND_NOT_AL:
return .COND
case .SYS_REG:
return .SYSREG
case .W_SHIFTED, .X_SHIFTED:
return .SHIFTED
case .W_EXTENDED, .X_EXTENDED:
@@ -177,6 +181,7 @@ operand_suffix :: proc(t: a.Operand_Type) -> string {
case .REL: return "l"
case .MEM: return "m"
case .COND: return "c"
case .SYSREG: return "s"
case .SHIFTED: return "sh"
case .EXTENDED: return "ex"
}
@@ -255,6 +260,8 @@ operand_primary_names :: proc(sig: Operand_Signature) -> [4][3]string {
result[i][0] = "mem"
case .COND:
result[i][0] = "cond"
case .SYSREG:
result[i][0] = "sysreg"
case .SHIFTED:
rn := reg_name(i, &reg_count)
result[i][0] = rn
@@ -290,6 +297,8 @@ param_list :: proc(sig: Operand_Signature) -> [dynamic]Param {
append(&params, Param{decl = fmt.tprintf("%s: Memory", names[i][0]), name = names[i][0]})
case .COND:
append(&params, Param{decl = fmt.tprintf("%s: Cond", names[i][0]), name = names[i][0]})
case .SYSREG:
append(&params, Param{decl = fmt.tprintf("%s: System_Register", names[i][0]), name = names[i][0]})
case .SHIFTED:
append(&params, Param{decl = fmt.tprintf("%s: Register", names[i][0]), name = names[i][0]})
append(&params, Param{decl = fmt.tprintf("%s: Shift_Type", names[i][1]), name = names[i][1]})
@@ -363,6 +372,8 @@ write_operand_expr :: proc(sb: ^strings.Builder, t: a.Operand_Type, names: [3]st
fmt.sbprintf(sb, "op_mem(%s)", names[0])
case .COND:
fmt.sbprintf(sb, "op_cond(%s)", names[0])
case .SYSREG:
fmt.sbprintf(sb, "op_sysreg(%s)", names[0])
case .SHIFTED:
fmt.sbprintf(sb, "op_shifted(%s, %s, %s)", names[0], names[1], names[2])
case .EXTENDED:
@@ -398,7 +409,7 @@ uses_plain_constructors :: proc(sig: Operand_Signature) -> bool {
.V_4H_FP16, .V_8H_FP16:
return false // needs op_v_*
}
case .IMM, .REL, .MEM, .COND:
case .IMM, .REL, .MEM, .COND, .SYSREG:
// fine
case:
return false // ZREG / PREG / SHIFTED / EXTENDED