mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 02:03:35 +00:00
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:
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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} },
|
||||
|
||||
@@ -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} },
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
|
||||
@@ -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, ®_count)
|
||||
result[i][0] = rn
|
||||
@@ -290,6 +297,8 @@ param_list :: proc(sig: Operand_Signature) -> [dynamic]Param {
|
||||
append(¶ms, Param{decl = fmt.tprintf("%s: Memory", names[i][0]), name = names[i][0]})
|
||||
case .COND:
|
||||
append(¶ms, Param{decl = fmt.tprintf("%s: Cond", names[i][0]), name = names[i][0]})
|
||||
case .SYSREG:
|
||||
append(¶ms, Param{decl = fmt.tprintf("%s: System_Register", names[i][0]), name = names[i][0]})
|
||||
case .SHIFTED:
|
||||
append(¶ms, Param{decl = fmt.tprintf("%s: Register", names[i][0]), name = names[i][0]})
|
||||
append(¶ms, 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
|
||||
|
||||
Reference in New Issue
Block a user