diff --git a/core/rexcode/isa/arm64/decoder.odin b/core/rexcode/isa/arm64/decoder.odin index 057065941..2784cc8f2 100644 --- a/core/rexcode/isa/arm64/decoder.odin +++ b/core/rexcode/isa/arm64/decoder.odin @@ -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: diff --git a/core/rexcode/isa/arm64/encoder.odin b/core/rexcode/isa/arm64/encoder.odin index 5c567489d..d7b5fecab 100644 --- a/core/rexcode/isa/arm64/encoder.odin +++ b/core/rexcode/isa/arm64/encoder.odin @@ -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: diff --git a/core/rexcode/isa/arm64/encoding_types.odin b/core/rexcode/isa/arm64/encoding_types.odin index a4fe99f41..46d6e8495 100644 --- a/core/rexcode/isa/arm64/encoding_types.odin +++ b/core/rexcode/isa/arm64/encoding_types.odin @@ -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) diff --git a/core/rexcode/isa/arm64/mnemonic_builders.odin b/core/rexcode/isa/arm64/mnemonic_builders.odin index 113adcf76..8557d62f2 100644 --- a/core/rexcode/isa/arm64/mnemonic_builders.odin +++ b/core/rexcode/isa/arm64/mnemonic_builders.odin @@ -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 diff --git a/core/rexcode/isa/arm64/operands.odin b/core/rexcode/isa/arm64/operands.odin index f1fee81db..86e20675e 100644 --- a/core/rexcode/isa/arm64/operands.odin +++ b/core/rexcode/isa/arm64/operands.odin @@ -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 diff --git a/core/rexcode/isa/arm64/printer.odin b/core/rexcode/isa/arm64/printer.odin index 85d8c21c9..0e12ed44a 100644 --- a/core/rexcode/isa/arm64/printer.odin +++ b/core/rexcode/isa/arm64/printer.odin @@ -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] diff --git a/core/rexcode/isa/arm64/registers.odin b/core/rexcode/isa/arm64/registers.odin index 2ae17eaa1..10e6040d5 100644 --- a/core/rexcode/isa/arm64/registers.odin +++ b/core/rexcode/isa/arm64/registers.odin @@ -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 diff --git a/core/rexcode/isa/arm64/tablegen/generated/decode_tables.odin b/core/rexcode/isa/arm64/tablegen/generated/decode_tables.odin index e01c4b843..a1b37e39f 100644 --- a/core/rexcode/isa/arm64/tablegen/generated/decode_tables.odin +++ b/core/rexcode/isa/arm64/tablegen/generated/decode_tables.odin @@ -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} }, diff --git a/core/rexcode/isa/arm64/tablegen/generated/encode_tables.odin b/core/rexcode/isa/arm64/tablegen/generated/encode_tables.odin index f0feb9801..77fa940bf 100644 --- a/core/rexcode/isa/arm64/tablegen/generated/encode_tables.odin +++ b/core/rexcode/isa/arm64/tablegen/generated/encode_tables.odin @@ -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} }, diff --git a/core/rexcode/isa/arm64/tablegen/instruction_table.odin b/core/rexcode/isa/arm64/tablegen/instruction_table.odin index 13fb3296c..a32b04759 100644 --- a/core/rexcode/isa/arm64/tablegen/instruction_table.odin +++ b/core/rexcode/isa/arm64/tablegen/instruction_table.odin @@ -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 = { diff --git a/core/rexcode/isa/arm64/tables/arm64.encode_forms.bin b/core/rexcode/isa/arm64/tables/arm64.encode_forms.bin index d8d681632..6d8f7d751 100644 Binary files a/core/rexcode/isa/arm64/tables/arm64.encode_forms.bin and b/core/rexcode/isa/arm64/tables/arm64.encode_forms.bin differ diff --git a/core/rexcode/isa/arm64/tables/arm64.entries.bin b/core/rexcode/isa/arm64/tables/arm64.entries.bin index 8b10be152..17cf118ff 100644 Binary files a/core/rexcode/isa/arm64/tables/arm64.entries.bin and b/core/rexcode/isa/arm64/tables/arm64.entries.bin differ diff --git a/core/rexcode/isa/arm64/tests/pipeline_smoke.odin b/core/rexcode/isa/arm64/tests/pipeline_smoke.odin index 2953b8bf1..7a6f18e56 100644 --- a/core/rexcode/isa/arm64/tests/pipeline_smoke.odin +++ b/core/rexcode/isa/arm64/tests/pipeline_smoke.odin @@ -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) diff --git a/core/rexcode/isa/arm64/tools/gen_mnemonic_builders.odin b/core/rexcode/isa/arm64/tools/gen_mnemonic_builders.odin index 8b68749a0..167c8b193 100644 --- a/core/rexcode/isa/arm64/tools/gen_mnemonic_builders.odin +++ b/core/rexcode/isa/arm64/tools/gen_mnemonic_builders.odin @@ -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_ / emit_ 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