Files
zig/src/codegen/aarch64/encoding.zig
2025-07-28 22:23:19 -07:00

15719 lines
625 KiB
Zig

/// B1.2 Registers in AArch64 Execution state
pub const Register = struct {
alias: Alias,
format: Format,
pub const Format = union(enum) {
alias,
integer: IntegerSize,
scalar: VectorSize,
vector: Arrangement,
element: struct { size: VectorSize, index: u4 },
};
pub const IntegerSize = enum(u1) {
word = 0b0,
doubleword = 0b1,
pub fn prefix(is: IntegerSize) u8 {
return (comptime std.enums.EnumArray(IntegerSize, u8).init(.{
.word = 'w',
.doubleword = 'x',
})).get(is);
}
};
pub const VectorSize = enum(u3) {
byte = 0,
half = 1,
single = 2,
double = 3,
quad = 4,
scalable,
predicate,
pub fn prefix(vs: VectorSize) u8 {
return (comptime std.enums.EnumArray(VectorSize, u8).init(.{
.byte = 'b',
.half = 'h',
.single = 's',
.double = 'd',
.quad = 'q',
.scalable = 'z',
.predicate = 'p',
})).get(vs);
}
};
pub const Arrangement = enum {
@"2d",
@"4s",
@"8h",
@"16b",
@"1d",
@"2s",
@"4h",
@"8b",
pub fn len(arrangement: Arrangement) u5 {
return switch (arrangement) {
.@"1d" => 1,
.@"2d", .@"2s" => 2,
.@"4s", .@"4h" => 4,
.@"8h", .@"8b" => 8,
.@"16b" => 16,
};
}
pub fn size(arrangement: Arrangement) Instruction.DataProcessingVector.Q {
return switch (arrangement) {
.@"2d", .@"4s", .@"8h", .@"16b" => .quad,
.@"1d", .@"2s", .@"4h", .@"8b" => .double,
};
}
pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size {
return switch (arrangement) {
.@"2d", .@"1d" => .double,
.@"4s", .@"2s" => .single,
.@"8h", .@"4h" => .half,
.@"16b", .@"8b" => .byte,
};
}
pub fn elemSz(arrangement: Arrangement) Instruction.DataProcessingVector.Sz {
return switch (arrangement) {
else => unreachable,
.@"2d", .@"1d" => .double,
.@"4s", .@"2s" => .single,
};
}
};
pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
pub const x1: Register = .{ .alias = .r1, .format = .{ .integer = .doubleword } };
pub const x2: Register = .{ .alias = .r2, .format = .{ .integer = .doubleword } };
pub const x3: Register = .{ .alias = .r3, .format = .{ .integer = .doubleword } };
pub const x4: Register = .{ .alias = .r4, .format = .{ .integer = .doubleword } };
pub const x5: Register = .{ .alias = .r5, .format = .{ .integer = .doubleword } };
pub const x6: Register = .{ .alias = .r6, .format = .{ .integer = .doubleword } };
pub const x7: Register = .{ .alias = .r7, .format = .{ .integer = .doubleword } };
pub const x8: Register = .{ .alias = .r8, .format = .{ .integer = .doubleword } };
pub const x9: Register = .{ .alias = .r9, .format = .{ .integer = .doubleword } };
pub const x10: Register = .{ .alias = .r10, .format = .{ .integer = .doubleword } };
pub const x11: Register = .{ .alias = .r11, .format = .{ .integer = .doubleword } };
pub const x12: Register = .{ .alias = .r12, .format = .{ .integer = .doubleword } };
pub const x13: Register = .{ .alias = .r13, .format = .{ .integer = .doubleword } };
pub const x14: Register = .{ .alias = .r14, .format = .{ .integer = .doubleword } };
pub const x15: Register = .{ .alias = .r15, .format = .{ .integer = .doubleword } };
pub const x16: Register = .{ .alias = .r16, .format = .{ .integer = .doubleword } };
pub const x17: Register = .{ .alias = .r17, .format = .{ .integer = .doubleword } };
pub const x18: Register = .{ .alias = .r18, .format = .{ .integer = .doubleword } };
pub const x19: Register = .{ .alias = .r19, .format = .{ .integer = .doubleword } };
pub const x20: Register = .{ .alias = .r20, .format = .{ .integer = .doubleword } };
pub const x21: Register = .{ .alias = .r21, .format = .{ .integer = .doubleword } };
pub const x22: Register = .{ .alias = .r22, .format = .{ .integer = .doubleword } };
pub const x23: Register = .{ .alias = .r23, .format = .{ .integer = .doubleword } };
pub const x24: Register = .{ .alias = .r24, .format = .{ .integer = .doubleword } };
pub const x25: Register = .{ .alias = .r25, .format = .{ .integer = .doubleword } };
pub const x26: Register = .{ .alias = .r26, .format = .{ .integer = .doubleword } };
pub const x27: Register = .{ .alias = .r27, .format = .{ .integer = .doubleword } };
pub const x28: Register = .{ .alias = .r28, .format = .{ .integer = .doubleword } };
pub const x29: Register = .{ .alias = .r29, .format = .{ .integer = .doubleword } };
pub const x30: Register = .{ .alias = .r30, .format = .{ .integer = .doubleword } };
pub const xzr: Register = .{ .alias = .zr, .format = .{ .integer = .doubleword } };
pub const sp: Register = .{ .alias = .sp, .format = .{ .integer = .doubleword } };
pub const w0: Register = .{ .alias = .r0, .format = .{ .integer = .word } };
pub const w1: Register = .{ .alias = .r1, .format = .{ .integer = .word } };
pub const w2: Register = .{ .alias = .r2, .format = .{ .integer = .word } };
pub const w3: Register = .{ .alias = .r3, .format = .{ .integer = .word } };
pub const w4: Register = .{ .alias = .r4, .format = .{ .integer = .word } };
pub const w5: Register = .{ .alias = .r5, .format = .{ .integer = .word } };
pub const w6: Register = .{ .alias = .r6, .format = .{ .integer = .word } };
pub const w7: Register = .{ .alias = .r7, .format = .{ .integer = .word } };
pub const w8: Register = .{ .alias = .r8, .format = .{ .integer = .word } };
pub const w9: Register = .{ .alias = .r9, .format = .{ .integer = .word } };
pub const w10: Register = .{ .alias = .r10, .format = .{ .integer = .word } };
pub const w11: Register = .{ .alias = .r11, .format = .{ .integer = .word } };
pub const w12: Register = .{ .alias = .r12, .format = .{ .integer = .word } };
pub const w13: Register = .{ .alias = .r13, .format = .{ .integer = .word } };
pub const w14: Register = .{ .alias = .r14, .format = .{ .integer = .word } };
pub const w15: Register = .{ .alias = .r15, .format = .{ .integer = .word } };
pub const w16: Register = .{ .alias = .r16, .format = .{ .integer = .word } };
pub const w17: Register = .{ .alias = .r17, .format = .{ .integer = .word } };
pub const w18: Register = .{ .alias = .r18, .format = .{ .integer = .word } };
pub const w19: Register = .{ .alias = .r19, .format = .{ .integer = .word } };
pub const w20: Register = .{ .alias = .r20, .format = .{ .integer = .word } };
pub const w21: Register = .{ .alias = .r21, .format = .{ .integer = .word } };
pub const w22: Register = .{ .alias = .r22, .format = .{ .integer = .word } };
pub const w23: Register = .{ .alias = .r23, .format = .{ .integer = .word } };
pub const w24: Register = .{ .alias = .r24, .format = .{ .integer = .word } };
pub const w25: Register = .{ .alias = .r25, .format = .{ .integer = .word } };
pub const w26: Register = .{ .alias = .r26, .format = .{ .integer = .word } };
pub const w27: Register = .{ .alias = .r27, .format = .{ .integer = .word } };
pub const w28: Register = .{ .alias = .r28, .format = .{ .integer = .word } };
pub const w29: Register = .{ .alias = .r29, .format = .{ .integer = .word } };
pub const w30: Register = .{ .alias = .r30, .format = .{ .integer = .word } };
pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
pub const ip = x16;
pub const ip0 = x16;
pub const ip1 = x17;
pub const fp = x29;
pub const lr = x30;
pub const pc: Register = .{ .alias = .pc, .format = .{ .integer = .doubleword } };
pub const q0: Register = .{ .alias = .v0, .format = .{ .scalar = .quad } };
pub const q1: Register = .{ .alias = .v1, .format = .{ .scalar = .quad } };
pub const q2: Register = .{ .alias = .v2, .format = .{ .scalar = .quad } };
pub const q3: Register = .{ .alias = .v3, .format = .{ .scalar = .quad } };
pub const q4: Register = .{ .alias = .v4, .format = .{ .scalar = .quad } };
pub const q5: Register = .{ .alias = .v5, .format = .{ .scalar = .quad } };
pub const q6: Register = .{ .alias = .v6, .format = .{ .scalar = .quad } };
pub const q7: Register = .{ .alias = .v7, .format = .{ .scalar = .quad } };
pub const q8: Register = .{ .alias = .v8, .format = .{ .scalar = .quad } };
pub const q9: Register = .{ .alias = .v9, .format = .{ .scalar = .quad } };
pub const q10: Register = .{ .alias = .v10, .format = .{ .scalar = .quad } };
pub const q11: Register = .{ .alias = .v11, .format = .{ .scalar = .quad } };
pub const q12: Register = .{ .alias = .v12, .format = .{ .scalar = .quad } };
pub const q13: Register = .{ .alias = .v13, .format = .{ .scalar = .quad } };
pub const q14: Register = .{ .alias = .v14, .format = .{ .scalar = .quad } };
pub const q15: Register = .{ .alias = .v15, .format = .{ .scalar = .quad } };
pub const q16: Register = .{ .alias = .v16, .format = .{ .scalar = .quad } };
pub const q17: Register = .{ .alias = .v17, .format = .{ .scalar = .quad } };
pub const q18: Register = .{ .alias = .v18, .format = .{ .scalar = .quad } };
pub const q19: Register = .{ .alias = .v19, .format = .{ .scalar = .quad } };
pub const q20: Register = .{ .alias = .v20, .format = .{ .scalar = .quad } };
pub const q21: Register = .{ .alias = .v21, .format = .{ .scalar = .quad } };
pub const q22: Register = .{ .alias = .v22, .format = .{ .scalar = .quad } };
pub const q23: Register = .{ .alias = .v23, .format = .{ .scalar = .quad } };
pub const q24: Register = .{ .alias = .v24, .format = .{ .scalar = .quad } };
pub const q25: Register = .{ .alias = .v25, .format = .{ .scalar = .quad } };
pub const q26: Register = .{ .alias = .v26, .format = .{ .scalar = .quad } };
pub const q27: Register = .{ .alias = .v27, .format = .{ .scalar = .quad } };
pub const q28: Register = .{ .alias = .v28, .format = .{ .scalar = .quad } };
pub const q29: Register = .{ .alias = .v29, .format = .{ .scalar = .quad } };
pub const q30: Register = .{ .alias = .v30, .format = .{ .scalar = .quad } };
pub const q31: Register = .{ .alias = .v31, .format = .{ .scalar = .quad } };
pub const d0: Register = .{ .alias = .v0, .format = .{ .scalar = .double } };
pub const d1: Register = .{ .alias = .v1, .format = .{ .scalar = .double } };
pub const d2: Register = .{ .alias = .v2, .format = .{ .scalar = .double } };
pub const d3: Register = .{ .alias = .v3, .format = .{ .scalar = .double } };
pub const d4: Register = .{ .alias = .v4, .format = .{ .scalar = .double } };
pub const d5: Register = .{ .alias = .v5, .format = .{ .scalar = .double } };
pub const d6: Register = .{ .alias = .v6, .format = .{ .scalar = .double } };
pub const d7: Register = .{ .alias = .v7, .format = .{ .scalar = .double } };
pub const d8: Register = .{ .alias = .v8, .format = .{ .scalar = .double } };
pub const d9: Register = .{ .alias = .v9, .format = .{ .scalar = .double } };
pub const d10: Register = .{ .alias = .v10, .format = .{ .scalar = .double } };
pub const d11: Register = .{ .alias = .v11, .format = .{ .scalar = .double } };
pub const d12: Register = .{ .alias = .v12, .format = .{ .scalar = .double } };
pub const d13: Register = .{ .alias = .v13, .format = .{ .scalar = .double } };
pub const d14: Register = .{ .alias = .v14, .format = .{ .scalar = .double } };
pub const d15: Register = .{ .alias = .v15, .format = .{ .scalar = .double } };
pub const d16: Register = .{ .alias = .v16, .format = .{ .scalar = .double } };
pub const d17: Register = .{ .alias = .v17, .format = .{ .scalar = .double } };
pub const d18: Register = .{ .alias = .v18, .format = .{ .scalar = .double } };
pub const d19: Register = .{ .alias = .v19, .format = .{ .scalar = .double } };
pub const d20: Register = .{ .alias = .v20, .format = .{ .scalar = .double } };
pub const d21: Register = .{ .alias = .v21, .format = .{ .scalar = .double } };
pub const d22: Register = .{ .alias = .v22, .format = .{ .scalar = .double } };
pub const d23: Register = .{ .alias = .v23, .format = .{ .scalar = .double } };
pub const d24: Register = .{ .alias = .v24, .format = .{ .scalar = .double } };
pub const d25: Register = .{ .alias = .v25, .format = .{ .scalar = .double } };
pub const d26: Register = .{ .alias = .v26, .format = .{ .scalar = .double } };
pub const d27: Register = .{ .alias = .v27, .format = .{ .scalar = .double } };
pub const d28: Register = .{ .alias = .v28, .format = .{ .scalar = .double } };
pub const d29: Register = .{ .alias = .v29, .format = .{ .scalar = .double } };
pub const d30: Register = .{ .alias = .v30, .format = .{ .scalar = .double } };
pub const d31: Register = .{ .alias = .v31, .format = .{ .scalar = .double } };
pub const s0: Register = .{ .alias = .v0, .format = .{ .scalar = .single } };
pub const s1: Register = .{ .alias = .v1, .format = .{ .scalar = .single } };
pub const s2: Register = .{ .alias = .v2, .format = .{ .scalar = .single } };
pub const s3: Register = .{ .alias = .v3, .format = .{ .scalar = .single } };
pub const s4: Register = .{ .alias = .v4, .format = .{ .scalar = .single } };
pub const s5: Register = .{ .alias = .v5, .format = .{ .scalar = .single } };
pub const s6: Register = .{ .alias = .v6, .format = .{ .scalar = .single } };
pub const s7: Register = .{ .alias = .v7, .format = .{ .scalar = .single } };
pub const s8: Register = .{ .alias = .v8, .format = .{ .scalar = .single } };
pub const s9: Register = .{ .alias = .v9, .format = .{ .scalar = .single } };
pub const s10: Register = .{ .alias = .v10, .format = .{ .scalar = .single } };
pub const s11: Register = .{ .alias = .v11, .format = .{ .scalar = .single } };
pub const s12: Register = .{ .alias = .v12, .format = .{ .scalar = .single } };
pub const s13: Register = .{ .alias = .v13, .format = .{ .scalar = .single } };
pub const s14: Register = .{ .alias = .v14, .format = .{ .scalar = .single } };
pub const s15: Register = .{ .alias = .v15, .format = .{ .scalar = .single } };
pub const s16: Register = .{ .alias = .v16, .format = .{ .scalar = .single } };
pub const s17: Register = .{ .alias = .v17, .format = .{ .scalar = .single } };
pub const s18: Register = .{ .alias = .v18, .format = .{ .scalar = .single } };
pub const s19: Register = .{ .alias = .v19, .format = .{ .scalar = .single } };
pub const s20: Register = .{ .alias = .v20, .format = .{ .scalar = .single } };
pub const s21: Register = .{ .alias = .v21, .format = .{ .scalar = .single } };
pub const s22: Register = .{ .alias = .v22, .format = .{ .scalar = .single } };
pub const s23: Register = .{ .alias = .v23, .format = .{ .scalar = .single } };
pub const s24: Register = .{ .alias = .v24, .format = .{ .scalar = .single } };
pub const s25: Register = .{ .alias = .v25, .format = .{ .scalar = .single } };
pub const s26: Register = .{ .alias = .v26, .format = .{ .scalar = .single } };
pub const s27: Register = .{ .alias = .v27, .format = .{ .scalar = .single } };
pub const s28: Register = .{ .alias = .v28, .format = .{ .scalar = .single } };
pub const s29: Register = .{ .alias = .v29, .format = .{ .scalar = .single } };
pub const s30: Register = .{ .alias = .v30, .format = .{ .scalar = .single } };
pub const s31: Register = .{ .alias = .v31, .format = .{ .scalar = .single } };
pub const h0: Register = .{ .alias = .v0, .format = .{ .scalar = .half } };
pub const h1: Register = .{ .alias = .v1, .format = .{ .scalar = .half } };
pub const h2: Register = .{ .alias = .v2, .format = .{ .scalar = .half } };
pub const h3: Register = .{ .alias = .v3, .format = .{ .scalar = .half } };
pub const h4: Register = .{ .alias = .v4, .format = .{ .scalar = .half } };
pub const h5: Register = .{ .alias = .v5, .format = .{ .scalar = .half } };
pub const h6: Register = .{ .alias = .v6, .format = .{ .scalar = .half } };
pub const h7: Register = .{ .alias = .v7, .format = .{ .scalar = .half } };
pub const h8: Register = .{ .alias = .v8, .format = .{ .scalar = .half } };
pub const h9: Register = .{ .alias = .v9, .format = .{ .scalar = .half } };
pub const h10: Register = .{ .alias = .v10, .format = .{ .scalar = .half } };
pub const h11: Register = .{ .alias = .v11, .format = .{ .scalar = .half } };
pub const h12: Register = .{ .alias = .v12, .format = .{ .scalar = .half } };
pub const h13: Register = .{ .alias = .v13, .format = .{ .scalar = .half } };
pub const h14: Register = .{ .alias = .v14, .format = .{ .scalar = .half } };
pub const h15: Register = .{ .alias = .v15, .format = .{ .scalar = .half } };
pub const h16: Register = .{ .alias = .v16, .format = .{ .scalar = .half } };
pub const h17: Register = .{ .alias = .v17, .format = .{ .scalar = .half } };
pub const h18: Register = .{ .alias = .v18, .format = .{ .scalar = .half } };
pub const h19: Register = .{ .alias = .v19, .format = .{ .scalar = .half } };
pub const h20: Register = .{ .alias = .v20, .format = .{ .scalar = .half } };
pub const h21: Register = .{ .alias = .v21, .format = .{ .scalar = .half } };
pub const h22: Register = .{ .alias = .v22, .format = .{ .scalar = .half } };
pub const h23: Register = .{ .alias = .v23, .format = .{ .scalar = .half } };
pub const h24: Register = .{ .alias = .v24, .format = .{ .scalar = .half } };
pub const h25: Register = .{ .alias = .v25, .format = .{ .scalar = .half } };
pub const h26: Register = .{ .alias = .v26, .format = .{ .scalar = .half } };
pub const h27: Register = .{ .alias = .v27, .format = .{ .scalar = .half } };
pub const h28: Register = .{ .alias = .v28, .format = .{ .scalar = .half } };
pub const h29: Register = .{ .alias = .v29, .format = .{ .scalar = .half } };
pub const h30: Register = .{ .alias = .v30, .format = .{ .scalar = .half } };
pub const h31: Register = .{ .alias = .v31, .format = .{ .scalar = .half } };
pub const b0: Register = .{ .alias = .v0, .format = .{ .scalar = .byte } };
pub const b1: Register = .{ .alias = .v1, .format = .{ .scalar = .byte } };
pub const b2: Register = .{ .alias = .v2, .format = .{ .scalar = .byte } };
pub const b3: Register = .{ .alias = .v3, .format = .{ .scalar = .byte } };
pub const b4: Register = .{ .alias = .v4, .format = .{ .scalar = .byte } };
pub const b5: Register = .{ .alias = .v5, .format = .{ .scalar = .byte } };
pub const b6: Register = .{ .alias = .v6, .format = .{ .scalar = .byte } };
pub const b7: Register = .{ .alias = .v7, .format = .{ .scalar = .byte } };
pub const b8: Register = .{ .alias = .v8, .format = .{ .scalar = .byte } };
pub const b9: Register = .{ .alias = .v9, .format = .{ .scalar = .byte } };
pub const b10: Register = .{ .alias = .v10, .format = .{ .scalar = .byte } };
pub const b11: Register = .{ .alias = .v11, .format = .{ .scalar = .byte } };
pub const b12: Register = .{ .alias = .v12, .format = .{ .scalar = .byte } };
pub const b13: Register = .{ .alias = .v13, .format = .{ .scalar = .byte } };
pub const b14: Register = .{ .alias = .v14, .format = .{ .scalar = .byte } };
pub const b15: Register = .{ .alias = .v15, .format = .{ .scalar = .byte } };
pub const b16: Register = .{ .alias = .v16, .format = .{ .scalar = .byte } };
pub const b17: Register = .{ .alias = .v17, .format = .{ .scalar = .byte } };
pub const b18: Register = .{ .alias = .v18, .format = .{ .scalar = .byte } };
pub const b19: Register = .{ .alias = .v19, .format = .{ .scalar = .byte } };
pub const b20: Register = .{ .alias = .v20, .format = .{ .scalar = .byte } };
pub const b21: Register = .{ .alias = .v21, .format = .{ .scalar = .byte } };
pub const b22: Register = .{ .alias = .v22, .format = .{ .scalar = .byte } };
pub const b23: Register = .{ .alias = .v23, .format = .{ .scalar = .byte } };
pub const b24: Register = .{ .alias = .v24, .format = .{ .scalar = .byte } };
pub const b25: Register = .{ .alias = .v25, .format = .{ .scalar = .byte } };
pub const b26: Register = .{ .alias = .v26, .format = .{ .scalar = .byte } };
pub const b27: Register = .{ .alias = .v27, .format = .{ .scalar = .byte } };
pub const b28: Register = .{ .alias = .v28, .format = .{ .scalar = .byte } };
pub const b29: Register = .{ .alias = .v29, .format = .{ .scalar = .byte } };
pub const b30: Register = .{ .alias = .v30, .format = .{ .scalar = .byte } };
pub const b31: Register = .{ .alias = .v31, .format = .{ .scalar = .byte } };
pub const fpcr: Register = .{ .alias = .fpcr, .format = .{ .integer = .doubleword } };
pub const fpsr: Register = .{ .alias = .fpsr, .format = .{ .integer = .doubleword } };
pub const z0: Register = .{ .alias = .v0, .format = .{ .scalar = .scalable } };
pub const z1: Register = .{ .alias = .v1, .format = .{ .scalar = .scalable } };
pub const z2: Register = .{ .alias = .v2, .format = .{ .scalar = .scalable } };
pub const z3: Register = .{ .alias = .v3, .format = .{ .scalar = .scalable } };
pub const z4: Register = .{ .alias = .v4, .format = .{ .scalar = .scalable } };
pub const z5: Register = .{ .alias = .v5, .format = .{ .scalar = .scalable } };
pub const z6: Register = .{ .alias = .v6, .format = .{ .scalar = .scalable } };
pub const z7: Register = .{ .alias = .v7, .format = .{ .scalar = .scalable } };
pub const z8: Register = .{ .alias = .v8, .format = .{ .scalar = .scalable } };
pub const z9: Register = .{ .alias = .v9, .format = .{ .scalar = .scalable } };
pub const z10: Register = .{ .alias = .v10, .format = .{ .scalar = .scalable } };
pub const z11: Register = .{ .alias = .v11, .format = .{ .scalar = .scalable } };
pub const z12: Register = .{ .alias = .v12, .format = .{ .scalar = .scalable } };
pub const z13: Register = .{ .alias = .v13, .format = .{ .scalar = .scalable } };
pub const z14: Register = .{ .alias = .v14, .format = .{ .scalar = .scalable } };
pub const z15: Register = .{ .alias = .v15, .format = .{ .scalar = .scalable } };
pub const z16: Register = .{ .alias = .v16, .format = .{ .scalar = .scalable } };
pub const z17: Register = .{ .alias = .v17, .format = .{ .scalar = .scalable } };
pub const z18: Register = .{ .alias = .v18, .format = .{ .scalar = .scalable } };
pub const z19: Register = .{ .alias = .v19, .format = .{ .scalar = .scalable } };
pub const z20: Register = .{ .alias = .v20, .format = .{ .scalar = .scalable } };
pub const z21: Register = .{ .alias = .v21, .format = .{ .scalar = .scalable } };
pub const z22: Register = .{ .alias = .v22, .format = .{ .scalar = .scalable } };
pub const z23: Register = .{ .alias = .v23, .format = .{ .scalar = .scalable } };
pub const z24: Register = .{ .alias = .v24, .format = .{ .scalar = .scalable } };
pub const z25: Register = .{ .alias = .v25, .format = .{ .scalar = .scalable } };
pub const z26: Register = .{ .alias = .v26, .format = .{ .scalar = .scalable } };
pub const z27: Register = .{ .alias = .v27, .format = .{ .scalar = .scalable } };
pub const z28: Register = .{ .alias = .v28, .format = .{ .scalar = .scalable } };
pub const z29: Register = .{ .alias = .v29, .format = .{ .scalar = .scalable } };
pub const z30: Register = .{ .alias = .v30, .format = .{ .scalar = .scalable } };
pub const z31: Register = .{ .alias = .v31, .format = .{ .scalar = .scalable } };
pub const p0: Register = .{ .alias = .v0, .format = .{ .scalar = .predicate } };
pub const p1: Register = .{ .alias = .v1, .format = .{ .scalar = .predicate } };
pub const p2: Register = .{ .alias = .v2, .format = .{ .scalar = .predicate } };
pub const p3: Register = .{ .alias = .v3, .format = .{ .scalar = .predicate } };
pub const p4: Register = .{ .alias = .v4, .format = .{ .scalar = .predicate } };
pub const p5: Register = .{ .alias = .v5, .format = .{ .scalar = .predicate } };
pub const p6: Register = .{ .alias = .v6, .format = .{ .scalar = .predicate } };
pub const p7: Register = .{ .alias = .v7, .format = .{ .scalar = .predicate } };
pub const p8: Register = .{ .alias = .v8, .format = .{ .scalar = .predicate } };
pub const p9: Register = .{ .alias = .v9, .format = .{ .scalar = .predicate } };
pub const p10: Register = .{ .alias = .v10, .format = .{ .scalar = .predicate } };
pub const p11: Register = .{ .alias = .v11, .format = .{ .scalar = .predicate } };
pub const p12: Register = .{ .alias = .v12, .format = .{ .scalar = .predicate } };
pub const p13: Register = .{ .alias = .v13, .format = .{ .scalar = .predicate } };
pub const p14: Register = .{ .alias = .v14, .format = .{ .scalar = .predicate } };
pub const p15: Register = .{ .alias = .v15, .format = .{ .scalar = .predicate } };
pub const ffr: Register = .{ .alias = .ffr, .format = .{ .integer = .doubleword } };
pub const Encoded = enum(u5) {
_,
pub fn decodeInteger(enc: Encoded, sf_enc: IntegerSize, opts: struct { sp: bool = false }) Register {
return switch (sf_enc) {
.word => switch (@intFromEnum(enc)) {
0 => .w0,
1 => .w1,
2 => .w2,
3 => .w3,
4 => .w4,
5 => .w5,
6 => .w6,
7 => .w7,
8 => .w8,
9 => .w9,
10 => .w10,
11 => .w11,
12 => .w12,
13 => .w13,
14 => .w14,
15 => .w15,
16 => .w16,
17 => .w17,
18 => .w18,
19 => .w19,
20 => .w20,
21 => .w21,
22 => .w22,
23 => .w23,
24 => .w24,
25 => .w25,
26 => .w26,
27 => .w27,
28 => .w28,
29 => .w29,
30 => .w30,
31 => if (opts.sp) .wsp else .wzr,
},
.doubleword => switch (@intFromEnum(enc)) {
0 => .x0,
1 => .x1,
2 => .x2,
3 => .x3,
4 => .x4,
5 => .x5,
6 => .x6,
7 => .x7,
8 => .x8,
9 => .x9,
10 => .x10,
11 => .x11,
12 => .x12,
13 => .x13,
14 => .x14,
15 => .x15,
16 => .x16,
17 => .x17,
18 => .x18,
19 => .x19,
20 => .x20,
21 => .x21,
22 => .x22,
23 => .x23,
24 => .x24,
25 => .x25,
26 => .x26,
27 => .x27,
28 => .x28,
29 => .x29,
30 => .x30,
31 => if (opts.sp) .sp else .xzr,
},
};
}
pub fn decodeVector(enc: Encoded, vs_enc: VectorSize) Register {
return switch (vs_enc) {
.byte => switch (@intFromEnum(enc)) {
0 => .b0,
1 => .b1,
2 => .b2,
3 => .b3,
4 => .b4,
5 => .b5,
6 => .b6,
7 => .b7,
8 => .b8,
9 => .b9,
10 => .b10,
11 => .b11,
12 => .b12,
13 => .b13,
14 => .b14,
15 => .b15,
16 => .b16,
17 => .b17,
18 => .b18,
19 => .b19,
20 => .b20,
21 => .b21,
22 => .b22,
23 => .b23,
24 => .b24,
25 => .b25,
26 => .b26,
27 => .b27,
28 => .b28,
29 => .b29,
30 => .b30,
31 => .b31,
},
.half => switch (@intFromEnum(enc)) {
0 => .h0,
1 => .h1,
2 => .h2,
3 => .h3,
4 => .h4,
5 => .h5,
6 => .h6,
7 => .h7,
8 => .h8,
9 => .h9,
10 => .h10,
11 => .h11,
12 => .h12,
13 => .h13,
14 => .h14,
15 => .h15,
16 => .h16,
17 => .h17,
18 => .h18,
19 => .h19,
20 => .h20,
21 => .h21,
22 => .h22,
23 => .h23,
24 => .h24,
25 => .h25,
26 => .h26,
27 => .h27,
28 => .h28,
29 => .h29,
30 => .h30,
31 => .h31,
},
.single => switch (@intFromEnum(enc)) {
0 => .s0,
1 => .s1,
2 => .s2,
3 => .s3,
4 => .s4,
5 => .s5,
6 => .s6,
7 => .s7,
8 => .s8,
9 => .s9,
10 => .s10,
11 => .s11,
12 => .s12,
13 => .s13,
14 => .s14,
15 => .s15,
16 => .s16,
17 => .s17,
18 => .s18,
19 => .s19,
20 => .s20,
21 => .s21,
22 => .s22,
23 => .s23,
24 => .s24,
25 => .s25,
26 => .s26,
27 => .s27,
28 => .s28,
29 => .s29,
30 => .s30,
31 => .s31,
},
.double => switch (@intFromEnum(enc)) {
0 => .d0,
1 => .d1,
2 => .d2,
3 => .d3,
4 => .d4,
5 => .d5,
6 => .d6,
7 => .d7,
8 => .d8,
9 => .d9,
10 => .d10,
11 => .d11,
12 => .d12,
13 => .d13,
14 => .d14,
15 => .d15,
16 => .d16,
17 => .d17,
18 => .d18,
19 => .d19,
20 => .d20,
21 => .d21,
22 => .d22,
23 => .d23,
24 => .d24,
25 => .d25,
26 => .d26,
27 => .d27,
28 => .d28,
29 => .d29,
30 => .d30,
31 => .d31,
},
.quad => switch (@intFromEnum(enc)) {
0 => .q0,
1 => .q1,
2 => .q2,
3 => .q3,
4 => .q4,
5 => .q5,
6 => .q6,
7 => .q7,
8 => .q8,
9 => .q9,
10 => .q10,
11 => .q11,
12 => .q12,
13 => .q13,
14 => .q14,
15 => .q15,
16 => .q16,
17 => .q17,
18 => .q18,
19 => .q19,
20 => .q20,
21 => .q21,
22 => .q22,
23 => .q23,
24 => .q24,
25 => .q25,
26 => .q26,
27 => .q27,
28 => .q28,
29 => .q29,
30 => .q30,
31 => .q31,
},
.scalable => switch (@intFromEnum(enc)) {
0 => .z0,
1 => .z1,
2 => .z2,
3 => .z3,
4 => .z4,
5 => .z5,
6 => .z6,
7 => .z7,
8 => .z8,
9 => .z9,
10 => .z10,
11 => .z11,
12 => .z12,
13 => .z13,
14 => .z14,
15 => .z15,
16 => .z16,
17 => .z17,
18 => .z18,
19 => .z19,
20 => .z20,
21 => .z21,
22 => .z22,
23 => .z23,
24 => .z24,
25 => .z25,
26 => .z26,
27 => .z27,
28 => .z28,
29 => .z29,
30 => .z30,
31 => .z31,
},
.predicate => switch (@as(u4, @intCast(@intFromEnum(enc)))) {
0 => .p0,
1 => .p1,
2 => .p2,
3 => .p3,
4 => .p4,
5 => .p5,
6 => .p6,
7 => .p7,
8 => .p8,
9 => .p9,
10 => .p10,
11 => .p11,
12 => .p12,
13 => .p13,
14 => .p14,
15 => .p15,
},
};
}
};
/// One tag per set of aliasing registers.
pub const Alias = enum(u7) {
r0,
r1,
r2,
r3,
r4,
r5,
r6,
r7,
r8,
r9,
r10,
r11,
r12,
r13,
r14,
r15,
r16,
r17,
r18,
r19,
r20,
r21,
r22,
r23,
r24,
r25,
r26,
r27,
r28,
r29,
r30,
zr,
sp,
pc,
v0,
v1,
v2,
v3,
v4,
v5,
v6,
v7,
v8,
v9,
v10,
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18,
v19,
v20,
v21,
v22,
v23,
v24,
v25,
v26,
v27,
v28,
v29,
v30,
v31,
fpcr,
fpsr,
p0,
p1,
p2,
p3,
p4,
p5,
p6,
p7,
p8,
p9,
p10,
p11,
p12,
p13,
p14,
p15,
ffr,
pub const ip: Alias = .r16;
pub const ip0: Alias = .r16;
pub const ip1: Alias = .r17;
pub const fp: Alias = .r29;
pub const lr: Alias = .r30;
pub fn r(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.pc));
return .{ .alias = ra, .format = .alias };
}
pub fn x(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
return .{ .alias = ra, .format = .{ .integer = .doubleword } };
}
pub fn w(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
return .{ .alias = ra, .format = .{ .integer = .word } };
}
pub fn v(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .alias };
}
pub fn q(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .quad } };
}
pub fn d(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .double } };
}
pub fn s(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .single } };
}
pub fn h(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .half } };
}
pub fn b(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .byte } };
}
pub fn z(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .scalar = .scalable } };
}
pub fn p(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15));
return .{ .alias = ra, .format = .{ .scalar = .predicate } };
}
pub fn @"2d"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"2d" } };
}
pub fn @"4s"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"4s" } };
}
pub fn @"8h"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"8h" } };
}
pub fn @"16b"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"16b" } };
}
pub fn @"1d"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"1d" } };
}
pub fn @"2s"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"2s" } };
}
pub fn @"4h"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"4h" } };
}
pub fn @"8b"(ra: Alias) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .vector = .@"8b" } };
}
pub fn @"d[]"(ra: Alias, index: u1) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .element = .{ .size = .double, .index = index } } };
}
pub fn @"s[]"(ra: Alias, index: u2) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .element = .{ .size = .single, .index = index } } };
}
pub fn @"h[]"(ra: Alias, index: u3) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .element = .{ .size = .half, .index = index } } };
}
pub fn @"b[]"(ra: Alias, index: u4) Register {
assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
return .{ .alias = ra, .format = .{ .element = .{ .size = .byte, .index = index } } };
}
pub fn isVector(ra: Alias) bool {
return switch (ra) {
.r0,
.r1,
.r2,
.r3,
.r4,
.r5,
.r6,
.r7,
.r8,
.r9,
.r10,
.r11,
.r12,
.r13,
.r14,
.r15,
.r16,
.r17,
.r18,
.r19,
.r20,
.r21,
.r22,
.r23,
.r24,
.r25,
.r26,
.r27,
.r28,
.r29,
.r30,
.zr,
.sp,
.pc,
.fpcr,
.fpsr,
.ffr,
=> false,
.v0,
.v1,
.v2,
.v3,
.v4,
.v5,
.v6,
.v7,
.v8,
.v9,
.v10,
.v11,
.v12,
.v13,
.v14,
.v15,
.v16,
.v17,
.v18,
.v19,
.v20,
.v21,
.v22,
.v23,
.v24,
.v25,
.v26,
.v27,
.v28,
.v29,
.v30,
.v31,
.p0,
.p1,
.p2,
.p3,
.p4,
.p5,
.p6,
.p7,
.p8,
.p9,
.p10,
.p11,
.p12,
.p13,
.p14,
.p15,
=> true,
};
}
pub fn encode(ra: Alias, comptime opts: struct { sp: bool = false, V: bool = false }) Encoded {
return @enumFromInt(@as(u5, switch (ra) {
.r0 => if (opts.V) unreachable else 0,
.r1 => if (opts.V) unreachable else 1,
.r2 => if (opts.V) unreachable else 2,
.r3 => if (opts.V) unreachable else 3,
.r4 => if (opts.V) unreachable else 4,
.r5 => if (opts.V) unreachable else 5,
.r6 => if (opts.V) unreachable else 6,
.r7 => if (opts.V) unreachable else 7,
.r8 => if (opts.V) unreachable else 8,
.r9 => if (opts.V) unreachable else 9,
.r10 => if (opts.V) unreachable else 10,
.r11 => if (opts.V) unreachable else 11,
.r12 => if (opts.V) unreachable else 12,
.r13 => if (opts.V) unreachable else 13,
.r14 => if (opts.V) unreachable else 14,
.r15 => if (opts.V) unreachable else 15,
.r16 => if (opts.V) unreachable else 16,
.r17 => if (opts.V) unreachable else 17,
.r18 => if (opts.V) unreachable else 18,
.r19 => if (opts.V) unreachable else 19,
.r20 => if (opts.V) unreachable else 20,
.r21 => if (opts.V) unreachable else 21,
.r22 => if (opts.V) unreachable else 22,
.r23 => if (opts.V) unreachable else 23,
.r24 => if (opts.V) unreachable else 24,
.r25 => if (opts.V) unreachable else 25,
.r26 => if (opts.V) unreachable else 26,
.r27 => if (opts.V) unreachable else 27,
.r28 => if (opts.V) unreachable else 28,
.r29 => if (opts.V) unreachable else 29,
.r30 => if (opts.V) unreachable else 30,
.zr => if (opts.sp or opts.V) unreachable else 31,
.sp => if (opts.sp and !opts.V) 31 else unreachable,
.pc => unreachable,
.v0 => if (opts.V) 0 else unreachable,
.v1 => if (opts.V) 1 else unreachable,
.v2 => if (opts.V) 2 else unreachable,
.v3 => if (opts.V) 3 else unreachable,
.v4 => if (opts.V) 4 else unreachable,
.v5 => if (opts.V) 5 else unreachable,
.v6 => if (opts.V) 6 else unreachable,
.v7 => if (opts.V) 7 else unreachable,
.v8 => if (opts.V) 8 else unreachable,
.v9 => if (opts.V) 9 else unreachable,
.v10 => if (opts.V) 10 else unreachable,
.v11 => if (opts.V) 11 else unreachable,
.v12 => if (opts.V) 12 else unreachable,
.v13 => if (opts.V) 13 else unreachable,
.v14 => if (opts.V) 14 else unreachable,
.v15 => if (opts.V) 15 else unreachable,
.v16 => if (opts.V) 16 else unreachable,
.v17 => if (opts.V) 17 else unreachable,
.v18 => if (opts.V) 18 else unreachable,
.v19 => if (opts.V) 19 else unreachable,
.v20 => if (opts.V) 20 else unreachable,
.v21 => if (opts.V) 21 else unreachable,
.v22 => if (opts.V) 22 else unreachable,
.v23 => if (opts.V) 23 else unreachable,
.v24 => if (opts.V) 24 else unreachable,
.v25 => if (opts.V) 25 else unreachable,
.v26 => if (opts.V) 26 else unreachable,
.v27 => if (opts.V) 27 else unreachable,
.v28 => if (opts.V) 28 else unreachable,
.v29 => if (opts.V) 29 else unreachable,
.v30 => if (opts.V) 30 else unreachable,
.v31 => if (opts.V) 31 else unreachable,
.fpcr, .fpsr => unreachable,
.p0, .p1, .p2, .p3, .p4, .p5, .p6, .p7, .p8, .p9, .p10, .p11, .p12, .p13, .p14, .p15 => unreachable,
.ffr => unreachable,
}));
}
};
pub fn isVector(reg: Register) bool {
return reg.alias.isVector();
}
pub fn size(reg: Register) ?u5 {
return format: switch (reg.format) {
.alias => unreachable,
.integer => |sf| switch (sf) {
.word => 4,
.doubleword => 8,
},
.vector => |vs| switch (vs) {
.byte => 1,
.word => 2,
.single => 4,
.double => 8,
.quad => 16,
.scalable, .predicate => null,
},
.arrangement => |arrangement| switch (arrangement) {
.@"2d", .@"4s", .@"8h", .@"16b" => 16,
.@"1d", .@"2s", .@"4h", .@"8b" => 8,
},
.element => |element| continue :format .{ .vector = element.size },
};
}
pub fn parse(reg: []const u8) ?Register {
return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) {
else => null,
'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
0...30 => .{
.alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
.format = .alias,
},
31 => null,
} else |_| null,
'x' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
0...30 => .{
.alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
.format = .{ .integer = .doubleword },
},
31 => null,
} else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null,
'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
0...30 => .{
.alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
.format = .{ .integer = .word },
},
31 => null,
} else |_| if (toLowerEqlAssertLower(reg, "wzr"))
.wzr
else if (toLowerEqlAssertLower(reg, "wsp"))
.wsp
else
null,
'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0"))
.ip0
else if (toLowerEqlAssertLower(reg, "ip1"))
.ip1
else
null,
'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null,
'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null,
'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .alias,
} else |_| null,
'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .{ .scalar = .quad },
} else |_| null,
'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .{ .scalar = .double },
} else |_| null,
's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .{ .scalar = .single },
} else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null,
'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .{ .scalar = .half },
} else |_| null,
'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
.alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
.format = .{ .scalar = .byte },
} else |_| null,
};
}
pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter {
return reg.fmtCase(.lower);
}
pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter {
return .{ .reg = reg, .case = case };
}
pub const System = packed struct(u16) {
op2: u3,
CRm: u4,
CRn: u4,
op1: u3,
op0: u2,
// D19.2 General system control registers
/// D19.2.1 ACCDATA_EL1, Accelerator Data
pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
/// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1)
pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2)
pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3)
pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1)
pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12)
pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2)
pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3)
pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1)
pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12)
pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2)
pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3)
pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.11 AIDR_EL1, Auxiliary ID Register
pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1)
pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12)
pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2)
pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3)
pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64])
pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 };
/// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0])
pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64])
pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 };
/// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0])
pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 };
/// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64])
pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 };
/// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0])
pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64])
pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0])
pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64])
pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 };
/// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0])
pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
/// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2
pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register
pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.27 CLIDR_EL1, Cache Level ID Register
pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1)
pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12)
pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2)
pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register
pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register
pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2)
pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
/// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3)
pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
/// D19.2.33 CSSELR_EL1, Cache Size Selection Register
pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.34 CTR_EL0, Cache Type Register
pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.35 DACR32_EL2, Domain Access Control Register
pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.36 DCZID_EL0, Data Cache Zero ID Register
pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1)
pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12)
pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2)
pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3)
pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.40 FAR_EL1, Fault Address Register (EL1)
pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.40 FAR_EL12, Fault Address Register (EL12)
pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.41 FAR_EL2, Fault Address Register (EL2)
pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.42 FAR_EL3, Fault Address Register (EL3)
pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register
pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.44 GCR_EL1, Tag Control Register
pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 };
/// D19.2.45 GMID_EL1, Tag Control Register
pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 };
/// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register
pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 };
/// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register
pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 };
/// D19.2.48 HCR_EL2, Hypervisor Configuration Register
pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register
pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 };
/// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register
pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 };
/// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register
pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 };
/// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register
pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 };
/// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register
pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 };
/// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register
pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 };
/// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register
pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 };
/// D19.2.56 HSTR_EL2, Hypervisor System Trap Register
pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 };
/// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0
pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 };
/// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1
pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 };
/// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0
pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 };
/// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1
pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 };
/// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0
pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1
pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 };
/// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2
pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 };
/// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0
pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 };
/// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1
pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 };
/// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2
pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 };
/// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3
pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 };
/// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4
pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 };
/// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0
pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 };
/// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1
pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 };
/// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2
pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 };
/// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0
pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 };
/// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0
pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 };
/// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0
pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 };
/// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0
pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 };
/// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1
pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 };
/// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0
pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1
pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 };
/// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2
pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 };
/// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3
pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 };
/// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4
pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 };
/// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5
pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 };
/// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6
pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 };
/// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0
pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 };
/// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1
pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 };
/// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2
pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 };
/// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3
pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 };
/// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4
pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 };
/// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5
pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 };
/// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0
pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1
pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 };
/// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2
pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 };
/// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2)
pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.94 ISR_EL1, Interrupt Status Register
pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.95 LORC_EL1, LORegion Control (EL1)
pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 };
/// D19.2.96 LOREA_EL1, LORegion End Address (EL1)
pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 };
/// D19.2.97 SORID_EL1, LORegionID (EL1)
pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 };
/// D19.2.98 LORN_EL1, LORegion Number (EL1)
pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 };
/// D19.2.99 LORSA_EL1, LORegion Start Address (EL1)
pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 };
/// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1)
pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12)
pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2)
pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3)
pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.103 MIDR_EL1, Main ID Register
pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register
pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
/// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0
pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 };
/// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1
pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 };
/// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2
pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 };
/// D19.2.108 PAR_EL1, Physical Address Register
pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 };
/// D19.2.109 REVIDR_EL1, Revision ID Register
pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
/// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register
pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 };
/// D19.2.111 RMR_EL1, Reset Management Register (EL1)
pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.112 RMR_EL2, Reset Management Register (EL2)
pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.113 RMR_EL3, Reset Management Register (EL3)
pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.114 RNDR, Random Number
pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 };
/// D19.2.115 RNDRRS, Reseeded Random Number
pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 };
/// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented)
pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented)
pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented)
pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.120 SCR_EL3, Secure Configuration Register
pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.121 SCTLR2_EL1, System Control Register (EL1)
pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.121 SCTLR2_EL12, System Control Register (EL12)
pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.122 SCTLR2_EL2, System Control Register (EL2)
pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.123 SCTLR2_EL3, System Control Register (EL3)
pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.124 SCTLR_EL1, System Control Register (EL1)
pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.124 SCTLR_EL12, System Control Register (EL12)
pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.125 SCTLR_EL2, System Control Register (EL2)
pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.126 SCTLR_EL3, System Control Register (EL3)
pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number
pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number
pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number
pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number
pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number
pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
/// D19.2.131 SMCR_EL1, SME Control Register (EL1)
pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
/// D19.2.131 SMCR_EL12, SME Control Register (EL12)
pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
/// D19.2.132 SMCR_EL2, SME Control Register (EL2)
pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
/// D19.2.133 SMCR_EL3, SME Control Register (EL3)
pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
/// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register
pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
/// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register
pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 };
/// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register
pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 };
/// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1)
pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12)
pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2)
pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.139 TCR_EL1, Translation Control Register (EL1)
pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.139 TCR_EL12, Translation Control Register (EL12)
pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.140 TCR_EL2, Translation Control Register (EL2)
pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.141 TCR_EL3, Translation Control Register (EL3)
pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0)
pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 };
/// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1)
pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12)
pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2)
pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3)
pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2
pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
/// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register
pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register
pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 };
/// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register
pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register
pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
/// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register
pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 };
/// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1)
pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12)
pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2)
pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3)
pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1)
pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12)
pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2)
pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
/// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1)
pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12)
pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2)
pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3)
pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register
pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
/// D19.2.161 VNCR_EL2, Virtual Nested Control Register
pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register
pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
/// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register
pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 };
/// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register
pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 };
/// D19.2.165 VTCR_EL2, Virtualization Translation Control Register
pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
/// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register
pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
/// D19.2.167 ZCR_EL1, SVE Control Register (EL1)
pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.167 ZCR_EL12, SVE Control Register (EL12)
pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.168 ZCR_EL2, SVE Control Register (EL2)
pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
/// D19.2.169 ZCR_EL3, SVE Control Register (EL3)
pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
pub fn parse(reg: []const u8) ?System {
if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: {
var symbol_it = std.mem.splitScalar(u8, reg[1..], '_');
const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
if (op0 < 0b10) break :encoded;
const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
const n = symbol_it.next() orelse break :encoded;
if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded;
const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded;
const m = symbol_it.next() orelse break :encoded;
if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded;
const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded;
const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
if (symbol_it.next() != null) break :encoded;
return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 };
}
inline for (@typeInfo(System).@"struct".decls) |decl| {
if (@TypeOf(@field(System, decl.name)) != System) continue;
if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name);
}
return null;
}
};
fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool {
if (lhs.len != rhs.len) return false;
for (lhs, rhs) |l, r| {
assert(!std.ascii.isUpper(r));
if (std.ascii.toLower(l) != r) return false;
}
return true;
}
};
/// C1.2.4 Condition code
pub const ConditionCode = enum(u4) {
/// integer: Equal
/// floating-point: Equal
/// Z == 1
eq = 0b0000,
/// integer: Not equal
/// floating-point: Not equal or unordered
/// Z == 0
ne = 0b0001,
/// integer: Unsigned higher or same
/// floating-point: Greater than, equal, or unordered
/// C == 1
hs = 0b0010,
/// integer: Unsigned lower
/// floating-point: Less than
/// C == 0
lo = 0b0011,
/// integer: Minus, negative
/// floating-point: Less than
/// N == 1
mi = 0b0100,
/// integer: Plus, positive or zero
/// floating-point: Greater than, equal, or unordered
/// N == 0
pl = 0b0101,
/// integer: Overflow
/// floating-point: Unordered
/// V == 1
vs = 0b0110,
/// integer: No overflow
/// floating-point: Ordered
/// V == 0
vc = 0b0111,
/// integer: Unsigned higher
/// floating-point: Greater than, or unordered
/// C == 1 and Z == 0
hi = 0b1000,
/// integer: Unsigned lower or same
/// floating-point: Less than or equal
/// C == 0 or Z == 1
ls = 0b1001,
/// integer: Signed greater than or equal
/// floating-point: Greater than or equal
/// N == V
ge = 0b1010,
/// integer: Signed less than
/// floating-point: Less than, or unordered
/// N != V
lt = 0b1011,
/// integer: Signed greater than
/// floating-point: Greater than
/// Z == 0 and N == V
gt = 0b1100,
/// integer: Signed less than or equal
/// floating-point: Less than, equal, or unordered
/// Z == 1 or N != V
le = 0b1101,
/// integer: Always
/// floating-point: Always
/// true
al = 0b1110,
/// integer: Always
/// floating-point: Always
/// true
nv = 0b1111,
/// Carry set
/// C == 1
pub const cs: ConditionCode = .hs;
/// Carry clear
/// C == 0
pub const cc: ConditionCode = .lo;
pub fn invert(cond: ConditionCode) ConditionCode {
return @enumFromInt(@intFromEnum(cond) ^ 0b0001);
}
};
/// C4.1 A64 instruction set encoding
pub const Instruction = packed union {
group: Group,
reserved: Reserved,
sme: Sme,
sve: Sve,
data_processing_immediate: DataProcessingImmediate,
branch_exception_generating_system: BranchExceptionGeneratingSystem,
load_store: LoadStore,
data_processing_register: DataProcessingRegister,
data_processing_vector: DataProcessingVector,
/// Table C4-1 Main encoding table for the A64 instruction set
pub const Group = packed struct {
encoded0: u25,
op1: u4,
encoded29: u2,
op0: u1,
};
/// C4.1.1 Reserved
pub const Reserved = packed union {
group: @This().Group,
udf: Udf,
/// Table C4-2 Encoding table for the Reserved group
pub const Group = packed struct {
encoded0: u16,
op1: u9,
decoded25: u4 = 0b0000,
op0: u2,
decoded31: u1 = 0b0,
};
/// C6.2.387 UDF
pub const Udf = packed struct {
imm16: u16,
decoded16: u16 = 0b0000000000000000,
};
pub const Decoded = union(enum) {
unallocated,
udf: Udf,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op0) {
0b00 => switch (inst.group.op1) {
0b000000000 => .{ .udf = inst.udf },
else => .unallocated,
},
else => .unallocated,
};
}
};
/// C4.1.2 SME encodings
pub const Sme = packed union {
group: @This().Group,
/// Table C4-3 Encodings table for the SME encodings group
pub const Group = packed struct {
encoded0: u2,
op2: u3,
encoded5: u5,
op1: u15,
decoded25: u4 = 0b0000,
op0: u2,
decoded31: u1 = 0b1,
};
};
/// C4.1.30 SVE encodings
pub const Sve = packed union {
group: @This().Group,
/// Table C4-31 Encoding table for the SVE encodings group
pub const Group = packed struct {
encoded0: u4,
op2: u1,
encoded5: u5,
op1: u15,
decoded25: u4 = 0b0010,
op0: u3,
};
};
/// C4.1.86 Data Processing -- Immediate
pub const DataProcessingImmediate = packed union {
group: @This().Group,
pc_relative_addressing: PcRelativeAddressing,
add_subtract_immediate: AddSubtractImmediate,
add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
logical_immediate: LogicalImmediate,
move_wide_immediate: MoveWideImmediate,
bitfield: Bitfield,
extract: Extract,
/// Table C4-87 Encoding table for the Data Processing -- Immediate group
pub const Group = packed struct {
encoded0: u23,
op0: u3,
decoded26: u3 = 0b100,
encoded29: u3,
};
/// PC-rel. addressing
pub const PcRelativeAddressing = packed union {
group: @This().Group,
adr: Adr,
adrp: Adrp,
pub const Group = packed struct {
Rd: Register.Encoded,
immhi: i19,
decoded24: u5 = 0b10000,
immlo: u2,
op: Op,
};
/// C6.2.10 ADR
pub const Adr = packed struct {
Rd: Register.Encoded,
immhi: i19,
decoded24: u5 = 0b10000,
immlo: u2,
op: Op = .adr,
};
/// C6.2.11 ADRP
pub const Adrp = packed struct {
Rd: Register.Encoded,
immhi: i19,
decoded24: u5 = 0b10000,
immlo: u2,
op: Op = .adrp,
};
pub const Op = enum(u1) {
adr = 0b0,
adrp = 0b1,
};
};
/// Add/subtract (immediate)
pub const AddSubtractImmediate = packed union {
group: @This().Group,
add: Add,
adds: Adds,
sub: Sub,
subs: Subs,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
sh: Shift,
decoded23: u6 = 0b100010,
S: bool,
op: AddSubtractOp,
sf: Register.IntegerSize,
};
/// C6.2.4 ADD (immediate)
pub const Add = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
sh: Shift,
decoded23: u6 = 0b100010,
S: bool = false,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.8 ADDS (immediate)
pub const Adds = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
sh: Shift,
decoded23: u6 = 0b100010,
S: bool = true,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.357 SUB (immediate)
pub const Sub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
sh: Shift,
decoded23: u6 = 0b100010,
S: bool = false,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
/// C6.2.363 SUBS (immediate)
pub const Subs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
sh: Shift,
decoded23: u6 = 0b100010,
S: bool = true,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
pub const Shift = enum(u1) {
@"0" = 0b0,
@"12" = 0b1,
};
};
/// Add/subtract (immediate, with tags)
pub const AddSubtractImmediateWithTags = packed union {
group: @This().Group,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
uimm4: u4,
op3: u2,
uimm6: u6,
o2: u1,
decoded23: u6 = 0b100011,
S: bool,
op: AddSubtractOp,
sf: Register.IntegerSize,
};
};
/// Logical (immediate)
pub const LogicalImmediate = packed union {
group: @This().Group,
@"and": And,
orr: Orr,
eor: Eor,
ands: Ands,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100100,
opc: LogicalOpc,
sf: Register.IntegerSize,
};
/// C6.2.12 AND (immediate)
pub const And = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100100,
opc: LogicalOpc = .@"and",
sf: Register.IntegerSize,
};
/// C6.2.240 ORR (immediate)
pub const Orr = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100100,
opc: LogicalOpc = .orr,
sf: Register.IntegerSize,
};
/// C6.2.119 EOR (immediate)
pub const Eor = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100100,
opc: LogicalOpc = .eor,
sf: Register.IntegerSize,
};
/// C6.2.14 ANDS (immediate)
pub const Ands = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100100,
opc: LogicalOpc = .ands,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
@"and": And,
orr: Orr,
eor: Eor,
ands: Ands,
};
pub fn decode(inst: @This()) @This().Decoded {
return if (!inst.group.imm.validImmediate(inst.group.sf))
.unallocated
else switch (inst.group.opc) {
.@"and" => .{ .@"and" = inst.@"and" },
.orr => .{ .orr = inst.orr },
.eor => .{ .eor = inst.eor },
.ands => .{ .ands = inst.ands },
};
}
};
/// Move wide (immediate)
pub const MoveWideImmediate = packed union {
group: @This().Group,
movn: Movn,
movz: Movz,
movk: Movk,
pub const Group = packed struct {
Rd: Register.Encoded,
imm16: u16,
hw: Hw,
decoded23: u6 = 0b100101,
opc: Opc,
sf: Register.IntegerSize,
};
/// C6.2.226 MOVN
pub const Movn = packed struct {
Rd: Register.Encoded,
imm16: u16,
hw: Hw,
decoded23: u6 = 0b100101,
opc: Opc = .movn,
sf: Register.IntegerSize,
};
/// C6.2.227 MOVZ
pub const Movz = packed struct {
Rd: Register.Encoded,
imm16: u16,
hw: Hw,
decoded23: u6 = 0b100101,
opc: Opc = .movz,
sf: Register.IntegerSize,
};
/// C6.2.225 MOVK
pub const Movk = packed struct {
Rd: Register.Encoded,
imm16: u16,
hw: Hw,
decoded23: u6 = 0b100101,
opc: Opc = .movk,
sf: Register.IntegerSize,
};
pub const Hw = enum(u2) {
@"0" = 0b00,
@"16" = 0b01,
@"32" = 0b10,
@"48" = 0b11,
pub fn int(hw: Hw) u6 {
return switch (hw) {
.@"0" => 0,
.@"16" => 16,
.@"32" => 32,
.@"48" => 48,
};
}
pub fn sf(hw: Hw) Register.IntegerSize {
return switch (hw) {
.@"0", .@"16" => .word,
.@"32", .@"48" => .doubleword,
};
}
};
pub const Opc = enum(u2) {
movn = 0b00,
movz = 0b10,
movk = 0b11,
_,
};
pub const Decoded = union(enum) {
unallocated,
movn: Movn,
movz: Movz,
movk: Movk,
};
pub fn decode(inst: @This()) @This().Decoded {
return if (inst.group.sf == .word and inst.group.hw.sf() == .doubleword)
.unallocated
else switch (inst.group.opc) {
_ => .unallocated,
.movn => .{ .movn = inst.movn },
.movz => .{ .movz = inst.movz },
.movk => .{ .movk = inst.movk },
};
}
};
/// Bitfield
pub const Bitfield = packed union {
group: @This().Group,
sbfm: Sbfm,
bfm: Bfm,
ubfm: Ubfm,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100110,
opc: Opc,
sf: Register.IntegerSize,
};
pub const Sbfm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100110,
opc: Opc = .sbfm,
sf: Register.IntegerSize,
};
pub const Bfm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100110,
opc: Opc = .bfm,
sf: Register.IntegerSize,
};
pub const Ubfm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm: Bitmask,
decoded23: u6 = 0b100110,
opc: Opc = .ubfm,
sf: Register.IntegerSize,
};
pub const Opc = enum(u2) {
sbfm = 0b00,
bfm = 0b01,
ubfm = 0b10,
_,
};
pub const Decoded = union(enum) {
unallocated,
sbfm: Sbfm,
bfm: Bfm,
ubfm: Ubfm,
};
pub fn decode(inst: @This()) @This().Decoded {
return if (!inst.group.imm.validBitfield(inst.group.sf))
.unallocated
else switch (inst.group.opc) {
_ => .unallocated,
.sbfm => .{ .sbfm = inst.sbfm },
.bfm => .{ .bfm = inst.bfm },
.ubfm => .{ .ubfm = inst.ubfm },
};
}
};
/// Extract
pub const Extract = packed union {
group: @This().Group,
extr: Extr,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imms: u6,
Rm: Register.Encoded,
o0: u1,
N: Register.IntegerSize,
decoded23: u6 = 0b100111,
op21: u2,
sf: Register.IntegerSize,
};
pub const Extr = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imms: u6,
Rm: Register.Encoded,
o0: u1 = 0b0,
N: Register.IntegerSize,
decoded23: u6 = 0b100111,
op21: u2 = 0b00,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
extr: Extr,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op21) {
0b01, 0b10...0b11 => .unallocated,
0b00 => switch (inst.group.o0) {
0b1 => .unallocated,
0b0 => if ((inst.group.sf == .word and @as(u1, @truncate(inst.group.imms >> 5)) == 0b1) or
inst.group.sf != inst.group.N)
.unallocated
else
.{ .extr = inst.extr },
},
};
}
};
pub const Bitmask = packed struct {
imms: u6,
immr: u6,
N: Register.IntegerSize,
fn lenHsb(bitmask: Bitmask) u7 {
return @bitCast(packed struct {
not_imms: u6,
N: Register.IntegerSize,
}{ .not_imms = ~bitmask.imms, .N = bitmask.N });
}
fn validImmediate(bitmask: Bitmask, sf: Register.IntegerSize) bool {
if (sf == .word and bitmask.N == .doubleword) return false;
const len_hsb = bitmask.lenHsb();
return (len_hsb -% 1) & len_hsb != 0b0_000000;
}
fn validBitfield(bitmask: Bitmask, sf: Register.IntegerSize) bool {
if (sf != bitmask.N) return false;
if (sf == .word and (@as(u1, @truncate(bitmask.immr >> 5)) != 0b0 or
@as(u1, @truncate(bitmask.imms >> 5)) != 0b0)) return false;
const len_hsb = bitmask.lenHsb();
return len_hsb >= 0b0_000010;
}
fn decode(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
const esize = @as(u7, 1 << 6) >> @clz(bitmask.lenHsb());
const levels: u6 = @intCast(esize - 1);
const s = bitmask.imms & levels;
const r = bitmask.immr & levels;
const d = (s -% r) & levels;
const welem = @as(u64, std.math.maxInt(u64)) >> (63 - s);
const telem = @as(u64, std.math.maxInt(u64)) >> (63 - d);
const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - esize);
const rmask = @divExact(std.math.maxInt(u64), emask);
const wmask = std.math.rotr(u64, welem * rmask, r);
const tmask = telem * rmask;
return switch (sf) {
.word => .{ @as(u32, @truncate(wmask)), @as(u32, @truncate(tmask)) },
.doubleword => .{ wmask, tmask },
};
}
pub fn decodeImmediate(bitmask: Bitmask, sf: Register.IntegerSize) u64 {
assert(bitmask.validImmediate(sf));
const imm, _ = bitmask.decode(sf);
return imm;
}
pub fn decodeBitfield(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
assert(bitmask.validBitfield(sf));
return bitmask.decode(sf);
}
pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.IntegerSize) bool {
const s = bitmask.imms;
const r = bitmask.immr;
const width: u7 = switch (sf) {
.word => 32,
.doubleword => 64,
};
if (sf != bitmask.N) return false;
if (sf == .word and @as(u1, @truncate(s >> 5)) != 0b0) return false;
if (s < 16) return (-%r % 16) <= (15 - s);
if (s >= width - 15) return (r % 16) <= (s - (width - 15));
return false;
}
};
pub const Decoded = union(enum) {
unallocated,
pc_relative_addressing: PcRelativeAddressing,
add_subtract_immediate: AddSubtractImmediate,
add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
logical_immediate: LogicalImmediate,
move_wide_immediate: MoveWideImmediate,
bitfield: Bitfield,
extract: Extract,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op0) {
0b000, 0b001 => .{ .pc_relative_addressing = inst.pc_relative_addressing },
0b010 => .{ .add_subtract_immediate = inst.add_subtract_immediate },
0b011 => .{ .add_subtract_immediate_with_tags = inst.add_subtract_immediate_with_tags },
0b100 => .{ .logical_immediate = inst.logical_immediate },
0b101 => .{ .move_wide_immediate = inst.move_wide_immediate },
0b110 => .{ .bitfield = inst.bitfield },
0b111 => .{ .extract = inst.extract },
};
}
};
/// C4.1.87 Branches, Exception Generating and System instructions
pub const BranchExceptionGeneratingSystem = packed union {
group: @This().Group,
conditional_branch_immediate: ConditionalBranchImmediate,
exception_generating: ExceptionGenerating,
system_register_argument: SystemRegisterArgument,
hints: Hints,
barriers: Barriers,
pstate: Pstate,
system_result: SystemResult,
system: System,
system_register_move: SystemRegisterMove,
unconditional_branch_register: UnconditionalBranchRegister,
unconditional_branch_immediate: UnconditionalBranchImmediate,
compare_branch_immediate: CompareBranchImmediate,
test_branch_immediate: TestBranchImmediate,
/// Table C4-88 Encoding table for the Branches, Exception Generating and System instructions group
pub const Group = packed struct {
op2: u5,
encoded5: u7,
op1: u14,
decoded26: u3 = 0b101,
op0: u3,
};
/// Conditional branch (immediate)
pub const ConditionalBranchImmediate = packed union {
group: @This().Group,
b: B,
bc: Bc,
pub const Group = packed struct {
cond: ConditionCode,
o0: u1,
imm19: i19,
o1: u1,
decoded25: u7 = 0b0101010,
};
/// C6.2.26 B.cond
pub const B = packed struct {
cond: ConditionCode,
o0: u1 = 0b0,
imm19: i19,
o1: u1 = 0b0,
decoded25: u7 = 0b0101010,
};
/// C6.2.27 BC.cond
pub const Bc = packed struct {
cond: ConditionCode,
o0: u1 = 0b1,
imm19: i19,
o1: u1 = 0b0,
decoded25: u7 = 0b0101010,
};
pub const Decoded = union(enum) {
unallocated,
b: B,
bc: Bc,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.o1) {
0b0 => switch (inst.group.o0) {
0b0 => .{ .b = inst.b },
0b1 => .{ .bc = inst.bc },
},
0b1 => .unallocated,
};
}
};
/// Exception generating
pub const ExceptionGenerating = packed union {
group: @This().Group,
svc: Svc,
hvc: Hvc,
smc: Smc,
brk: Brk,
hlt: Hlt,
tcancel: Tcancel,
dcps1: Dcps1,
dcps2: Dcps2,
dcps3: Dcps3,
pub const Group = packed struct {
LL: u2,
op2: u3,
imm16: u16,
opc: u3,
decoded24: u8 = 0b11010100,
};
/// C6.2.365 SVC
pub const Svc = packed struct {
decoded0: u2 = 0b01,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b000,
decoded24: u8 = 0b11010100,
};
/// C6.2.128 HVC
pub const Hvc = packed struct {
decoded0: u2 = 0b10,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b000,
decoded24: u8 = 0b11010100,
};
/// C6.2.283 SMC
pub const Smc = packed struct {
decoded0: u2 = 0b11,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b000,
decoded24: u8 = 0b11010100,
};
/// C6.2.40 BRK
pub const Brk = packed struct {
decoded0: u2 = 0b00,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b001,
decoded24: u8 = 0b11010100,
};
/// C6.2.127 HLT
pub const Hlt = packed struct {
decoded0: u2 = 0b00,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b010,
decoded24: u8 = 0b11010100,
};
/// C6.2.376 TCANCEL
pub const Tcancel = packed struct {
decoded0: u2 = 0b00,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b011,
decoded24: u8 = 0b11010100,
};
/// C6.2.110 DCPS1
pub const Dcps1 = packed struct {
LL: u2 = 0b01,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b101,
decoded24: u8 = 0b11010100,
};
/// C6.2.110 DCPS2
pub const Dcps2 = packed struct {
LL: u2 = 0b10,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b101,
decoded24: u8 = 0b11010100,
};
/// C6.2.110 DCPS3
pub const Dcps3 = packed struct {
LL: u2 = 0b11,
decoded2: u3 = 0b000,
imm16: u16,
decoded21: u3 = 0b101,
decoded24: u8 = 0b11010100,
};
pub const Decoded = union(enum) {
unallocated,
svc: Svc,
hvc: Hvc,
smc: Smc,
brk: Brk,
hlt: Hlt,
tcancel: Tcancel,
dcps1: Dcps1,
dcps2: Dcps2,
dcps3: Dcps3,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op2) {
0b001 => .unallocated,
0b010...0b011 => .unallocated,
0b100...0b111 => .unallocated,
0b000 => switch (inst.group.opc) {
0b000 => switch (inst.group.LL) {
0b00 => .unallocated,
0b01 => .{ .svc = inst.svc },
0b10 => .{ .hvc = inst.hvc },
0b11 => .{ .smc = inst.smc },
},
0b001 => switch (inst.group.LL) {
0b01 => .unallocated,
0b00 => .{ .brk = inst.brk },
0b10...0b11 => .unallocated,
},
0b010 => switch (inst.group.LL) {
0b01 => .unallocated,
0b00 => .{ .hlt = inst.hlt },
0b10...0b11 => .unallocated,
},
0b011 => switch (inst.group.LL) {
0b00 => .{ .tcancel = inst.tcancel },
0b01 => .unallocated,
0b10...0b11 => .unallocated,
},
0b100 => .unallocated,
0b101 => switch (inst.group.LL) {
0b00 => .unallocated,
0b01 => .{ .dcps1 = inst.dcps1 },
0b10 => .{ .dcps2 = inst.dcps2 },
0b11 => .{ .dcps3 = inst.dcps3 },
},
0b110 => .unallocated,
0b111 => .unallocated,
},
};
}
};
/// System instructions with register argument
pub const SystemRegisterArgument = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
decoded12: u20 = 0b11010101000000110001,
};
/// Hints
pub const Hints = packed union {
group: @This().Group,
hint: Hint,
nop: Nop,
yield: Yield,
wfe: Wfe,
wfi: Wfi,
sev: Sev,
sevl: Sevl,
pub const Group = packed struct {
decoded0: u5 = 0b11111,
op2: u3,
CRm: u4,
decoded12: u20 = 0b11010101000000110010,
};
/// C6.2.126 HINT
pub const Hint = packed struct {
decoded0: u5 = 0b11111,
op2: u3,
CRm: u4,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.238 NOP
pub const Nop = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b000,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.402 YIELD
pub const Yield = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b001,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.396 WFE
pub const Wfe = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b010,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.398 WFI
pub const Wfi = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b011,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.280 SEV
pub const Sev = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b100,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.280 SEVL
pub const Sevl = packed struct {
decoded0: u5 = 0b11111,
op2: u3 = 0b101,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0010,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
pub const Decoded = union(enum) {
hint: Hint,
nop: Nop,
yield: Yield,
wfe: Wfe,
wfi: Wfi,
sev: Sev,
sevl: Sevl,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.CRm) {
else => .{ .hint = inst.hint },
0b0000 => switch (inst.group.op2) {
else => .{ .hint = inst.hint },
0b000 => .{ .nop = inst.nop },
0b001 => .{ .yield = inst.yield },
0b010 => .{ .wfe = inst.wfe },
0b011 => .{ .wfi = inst.wfi },
0b100 => .{ .sev = inst.sev },
0b101 => .{ .sevl = inst.sevl },
},
};
}
};
/// Barriers
pub const Barriers = packed union {
group: @This().Group,
clrex: Clrex,
dsb: Dsb,
dmb: Dmb,
isb: Isb,
sb: Sb,
pub const Group = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.56 CLREX
pub const Clrex = packed struct {
Rt: Register.Encoded = @enumFromInt(0b11111),
op2: u3 = 0b010,
CRm: u4,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.116 DSB
pub const Dsb = packed struct {
Rt: Register.Encoded = @enumFromInt(0b11111),
opc: u2 = 0b00,
decoded7: u1 = 0b1,
CRm: Option,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.114 DMB
pub const Dmb = packed struct {
Rt: Register.Encoded = @enumFromInt(0b11111),
opc: u2 = 0b01,
decoded7: u1 = 0b1,
CRm: Option,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.131 ISB
pub const Isb = packed struct {
Rt: Register.Encoded = @enumFromInt(0b11111),
opc: u2 = 0b10,
decoded7: u1 = 0b1,
CRm: Option,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
/// C6.2.264 SB
pub const Sb = packed struct {
Rt: Register.Encoded = @enumFromInt(0b11111),
opc: u2 = 0b11,
decoded7: u1 = 0b1,
CRm: u4 = 0b0000,
decoded12: u4 = 0b0011,
decoded16: u3 = 0b011,
decoded19: u2 = 0b00,
decoded21: u1 = 0b0,
decoded22: u10 = 0b1101010100,
};
pub const Option = enum(u4) {
oshld = 0b0001,
oshst = 0b0010,
osh = 0b0011,
nshld = 0b0101,
nshst = 0b0110,
nsh = 0b0111,
ishld = 0b1001,
ishst = 0b1010,
ish = 0b1011,
ld = 0b1101,
st = 0b1110,
sy = 0b1111,
_,
};
};
/// PSTATE
pub const Pstate = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
decoded12: u4 = 0b0100,
op1: u3,
decoded19: u13 = 0b1101010100000,
};
/// System with result
pub const SystemResult = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
CRn: u4,
op1: u3,
decoded19: u13 = 0b1101010100100,
};
/// System instructions
pub const System = packed union {
group: @This().Group,
sys: Sys,
sysl: Sysl,
pub const Group = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
CRn: u4,
op1: u3,
decoded19: u2 = 0b01,
L: L,
decoded22: u10 = 0b1101010100,
};
/// C6.2.372 SYS
pub const Sys = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
CRn: u4,
op1: u3,
decoded19: u2 = 0b01,
L: L = .sys,
decoded22: u10 = 0b1101010100,
};
/// C6.2.373 SYSL
pub const Sysl = packed struct {
Rt: Register.Encoded,
op2: u3,
CRm: u4,
CRn: u4,
op1: u3,
decoded19: u2 = 0b01,
L: L = .sysl,
decoded22: u10 = 0b1101010100,
};
const L = enum(u1) {
sys = 0b0,
sysl = 0b1,
};
pub const Decoded = union(enum) {
sys: Sys,
sysl: Sysl,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.L) {
.sys => .{ .sys = inst.sys },
.sysl => .{ .sysl = inst.sysl },
};
}
};
/// System register move
pub const SystemRegisterMove = packed union {
group: @This().Group,
msr: Msr,
mrs: Mrs,
pub const Group = packed struct {
Rt: Register.Encoded,
systemreg: Register.System,
L: L,
decoded22: u10 = 0b1101010100,
};
/// C6.2.230 MSR (register)
pub const Msr = packed struct {
Rt: Register.Encoded,
systemreg: Register.System,
L: L = .msr,
decoded22: u10 = 0b1101010100,
};
/// C6.2.228 MRS
pub const Mrs = packed struct {
Rt: Register.Encoded,
systemreg: Register.System,
L: L = .mrs,
decoded22: u10 = 0b1101010100,
};
pub const L = enum(u1) {
msr = 0b0,
mrs = 0b1,
};
pub const Decoded = union(enum) {
msr: Msr,
mrs: Mrs,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.L) {
.msr => .{ .msr = inst.msr },
.mrs => .{ .mrs = inst.mrs },
};
}
};
/// Unconditional branch (register)
pub const UnconditionalBranchRegister = packed union {
group: @This().Group,
br: Br,
blr: Blr,
ret: Ret,
pub const Group = packed struct {
op4: u5,
Rn: Register.Encoded,
op3: u6,
op2: u5,
opc: u4,
decoded25: u7 = 0b1101011,
};
/// C6.2.37 BR
pub const Br = packed struct {
Rm: Register.Encoded = @enumFromInt(0),
Rn: Register.Encoded,
M: bool = false,
A: bool = false,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b11111,
op: u2 = 0b00,
decoded23: u1 = 0b0,
Z: bool = false,
decoded25: u7 = 0b1101011,
};
/// C6.2.35 BLR
pub const Blr = packed struct {
Rm: Register.Encoded = @enumFromInt(0),
Rn: Register.Encoded,
M: bool = false,
A: bool = false,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b11111,
op: u2 = 0b01,
decoded23: u1 = 0b0,
Z: bool = false,
decoded25: u7 = 0b1101011,
};
/// C6.2.254 RET
pub const Ret = packed struct {
Rm: Register.Encoded = @enumFromInt(0),
Rn: Register.Encoded,
M: bool = false,
A: bool = false,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b11111,
op: u2 = 0b10,
decoded23: u1 = 0b0,
Z: bool = false,
decoded25: u7 = 0b1101011,
};
pub const Decoded = union(enum) {
unallocated,
br: Br,
blr: Blr,
ret: Ret,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op2) {
else => .unallocated,
0b11111 => switch (inst.group.opc) {
0b0000 => switch (inst.group.op4) {
else => .unallocated,
0b00000 => .{ .br = inst.br },
},
0b0001 => switch (inst.group.op4) {
else => .unallocated,
0b00000 => .{ .blr = inst.blr },
},
0b0010 => switch (inst.group.op4) {
else => .unallocated,
0b00000 => .{ .ret = inst.ret },
},
else => .unallocated,
},
};
}
};
/// Unconditional branch (immediate)
pub const UnconditionalBranchImmediate = packed union {
group: @This().Group,
b: B,
bl: Bl,
pub const Group = packed struct {
imm26: i26,
decoded26: u5 = 0b00101,
op: Op,
};
/// C6.2.25 B
pub const B = packed struct {
imm26: i26,
decoded26: u5 = 0b00101,
op: Op = .b,
};
/// C6.2.34 BL
pub const Bl = packed struct {
imm26: i26,
decoded26: u5 = 0b00101,
op: Op = .bl,
};
pub const Op = enum(u1) {
b = 0b0,
bl = 0b1,
};
};
/// Compare and branch (immediate)
pub const CompareBranchImmediate = packed union {
group: @This().Group,
cbz: Cbz,
cbnz: Cbnz,
pub const Group = packed struct {
Rt: Register.Encoded,
imm19: i19,
op: Op,
decoded25: u6 = 0b011010,
sf: Register.IntegerSize,
};
/// C6.2.47 CBZ
pub const Cbz = packed struct {
Rt: Register.Encoded,
imm19: i19,
op: Op = .cbz,
decoded25: u6 = 0b011010,
sf: Register.IntegerSize,
};
/// C6.2.46 CBNZ
pub const Cbnz = packed struct {
Rt: Register.Encoded,
imm19: i19,
op: Op = .cbnz,
decoded25: u6 = 0b011010,
sf: Register.IntegerSize,
};
pub const Op = enum(u1) {
cbz = 0b0,
cbnz = 0b1,
};
};
/// Test and branch (immediate)
pub const TestBranchImmediate = packed union {
group: @This().Group,
tbz: Tbz,
tbnz: Tbnz,
pub const Group = packed struct {
Rt: Register.Encoded,
imm14: i14,
b40: u5,
op: Op,
decoded25: u6 = 0b011011,
b5: u1,
};
/// C6.2.375 TBZ
pub const Tbz = packed struct {
Rt: Register.Encoded,
imm14: i14,
b40: u5,
op: Op = .tbz,
decoded25: u6 = 0b011011,
b5: u1,
};
/// C6.2.374 TBNZ
pub const Tbnz = packed struct {
Rt: Register.Encoded,
imm14: i14,
b40: u5,
op: Op = .tbnz,
decoded25: u6 = 0b011011,
b5: u1,
};
pub const Op = enum(u1) {
tbz = 0b0,
tbnz = 0b1,
};
};
pub const Decoded = union(enum) {
unallocated,
conditional_branch_immediate: ConditionalBranchImmediate,
exception_generating: ExceptionGenerating,
system_register_argument: SystemRegisterArgument,
hints: Hints,
barriers: Barriers,
pstate: Pstate,
system_result: SystemResult,
system: System,
system_register_move: SystemRegisterMove,
unconditional_branch_register: UnconditionalBranchRegister,
unconditional_branch_immediate: UnconditionalBranchImmediate,
compare_branch_immediate: CompareBranchImmediate,
test_branch_immediate: TestBranchImmediate,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op0) {
0b010 => switch (inst.group.op1) {
0b000000000000000...0b01111111111111 => .{ .conditional_branch_immediate = inst.conditional_branch_immediate },
else => .unallocated,
},
0b110 => switch (inst.group.op1) {
0b00000000000000...0b00111111111111 => .{ .exception_generating = inst.exception_generating },
0b01000000110001 => .{ .system_register_argument = inst.system_register_argument },
0b01000000110010 => switch (inst.group.op2) {
0b11111 => .{ .hints = inst.hints },
else => .unallocated,
},
0b01000000110011 => .{ .barriers = inst.barriers },
0b01000000000100,
0b01000000010100,
0b01000000100100,
0b01000000110100,
0b01000001000100,
0b01000001010100,
0b01000001100100,
0b01000001110100,
=> .{ .pstate = inst.pstate },
0b01001000000000...0b01001001111111 => .{ .system_result = inst.system_result },
0b01000010000000...0b01000011111111, 0b01001010000000...0b01001011111111 => .{ .system = inst.system },
0b01000100000000...0b01000111111111, 0b01001100000000...0b01001111111111 => .{ .system_register_move = inst.system_register_move },
0b10000000000000...0b11111111111111 => .{ .unconditional_branch_register = inst.unconditional_branch_register },
else => .unallocated,
},
0b000, 0b100 => .{ .unconditional_branch_immediate = inst.unconditional_branch_immediate },
0b001, 0b101 => switch (inst.group.op1) {
0b00000000000000...0b01111111111111 => .{ .compare_branch_immediate = inst.compare_branch_immediate },
0b10000000000000...0b11111111111111 => .{ .test_branch_immediate = inst.test_branch_immediate },
},
else => .unallocated,
};
}
};
/// C4.1.88 Loads and Stores
pub const LoadStore = packed union {
group: @This().Group,
register_literal: RegisterLiteral,
memory: Memory,
no_allocate_pair_offset: NoAllocatePairOffset,
register_pair_post_indexed: RegisterPairPostIndexed,
register_pair_offset: RegisterPairOffset,
register_pair_pre_indexed: RegisterPairPreIndexed,
register_unscaled_immediate: RegisterUnscaledImmediate,
register_immediate_post_indexed: RegisterImmediatePostIndexed,
register_unprivileged: RegisterUnprivileged,
register_immediate_pre_indexed: RegisterImmediatePreIndexed,
register_register_offset: RegisterRegisterOffset,
register_unsigned_immediate: RegisterUnsignedImmediate,
/// Table C4-89 Encoding table for the Loads and Stores group
pub const Group = packed struct {
encoded0: u10,
op4: u2,
encoded12: u4,
op3: u6,
encoded22: u1,
op2: u2,
decoded25: u1 = 0b0,
op1: bool,
decoded27: u1 = 0b1,
op0: u4,
};
/// Load register (literal)
pub const RegisterLiteral = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b011,
opc: u2,
};
pub const Integer = packed union {
group: @This().Group,
ldr: Ldr,
ldrsw: Ldrsw,
prfm: Prfm,
pub const Group = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b011,
opc: u2,
};
/// C6.2.167 LDR (literal)
pub const Ldr = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b011,
sf: Register.IntegerSize,
opc1: u1 = 0b0,
};
/// C6.2.179 LDRSW (literal)
pub const Ldrsw = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b011,
opc: u2 = 0b10,
};
/// C6.2.248 PRFM (literal)
pub const Prfm = packed struct {
prfop: PrfOp,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b011,
opc: u2 = 0b11,
};
};
pub const Vector = packed union {
group: @This().Group,
ldr: Ldr,
pub const Group = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b011,
opc: VectorSize,
};
/// C7.2.192 LDR (literal, SIMD&FP)
pub const Ldr = packed struct {
Rt: Register.Encoded,
imm19: i19,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b011,
opc: VectorSize,
};
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Memory Copy and Memory Set
pub const Memory = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
op2: u4,
Rs: Register.Encoded,
decoded21: u1 = 0b0,
op1: u2,
decoded24: u2 = 0b01,
o0: u1,
decoded27: u3 = 0b011,
size: IntegerSize,
};
/// Load/store no-allocate pair (offset)
pub const NoAllocatePairOffset = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b000,
V: bool,
decoded27: u3 = 0b101,
opc: u2,
};
/// Load/store register pair (post-indexed)
pub const RegisterPairPostIndexed = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b001,
V: bool,
decoded27: u3 = 0b101,
opc: u2,
};
pub const Integer = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b001,
V: bool = false,
decoded27: u3 = 0b101,
opc: u2,
};
/// C6.2.321 STP
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b001,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.164 LDP
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b001,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.165 LDPSW
pub const Ldpsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b001,
V: bool = false,
decoded27: u3 = 0b101,
opc: u2 = 0b01,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
0b00, 0b10 => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
0b01 => switch (inst.group.L) {
else => .unallocated,
.load => .{ .ldpsw = inst.ldpsw },
},
else => .unallocated,
};
}
};
pub const Vector = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b001,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.330 STP (SIMD&FP)
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b001,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.190 LDP (SIMD&FP)
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b001,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
.single, .double, .quad => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
_ => .unallocated,
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register pair (offset)
pub const RegisterPairOffset = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b010,
V: bool,
decoded27: u3 = 0b101,
opc: u2,
};
pub const Integer = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b010,
V: bool = false,
decoded27: u3 = 0b101,
opc: u2,
};
/// C6.2.321 STP
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b010,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.164 LDP
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b010,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.165 LDPSW
pub const Ldpsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b010,
V: bool = false,
decoded27: u3 = 0b101,
opc: u2 = 0b01,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
0b00, 0b10 => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
0b01 => switch (inst.group.L) {
else => .unallocated,
.load => .{ .ldpsw = inst.ldpsw },
},
else => .unallocated,
};
}
};
pub const Vector = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b010,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.330 STP (SIMD&FP)
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b010,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.190 LDP (SIMD&FP)
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b010,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
.single, .double, .quad => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
_ => .unallocated,
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register pair (pre-indexed)
pub const RegisterPairPreIndexed = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b011,
V: bool,
decoded27: u3 = 0b101,
opc: u2,
};
pub const Integer = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b011,
V: bool = false,
decoded27: u3 = 0b101,
opc: u2,
};
/// C6.2.321 STP
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b011,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.164 LDP
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b011,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.165 LDPSW
pub const Ldpsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b011,
V: bool = false,
decoded27: u3 = 0b101,
opc0: u2 = 0b01,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
ldpsw: Ldpsw,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
0b00, 0b10 => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
0b01 => switch (inst.group.L) {
else => .unallocated,
.load => .{ .ldpsw = inst.ldpsw },
},
else => .unallocated,
};
}
};
pub const Vector = packed union {
group: @This().Group,
stp: Stp,
ldp: Ldp,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L,
decoded23: u3 = 0b011,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.330 STP (SIMD&FP)
pub const Stp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .store,
decoded23: u3 = 0b011,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
/// C7.2.190 LDP (SIMD&FP)
pub const Ldp = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
Rt2: Register.Encoded,
imm7: i7,
L: L = .load,
decoded23: u3 = 0b011,
V: bool = true,
decoded27: u3 = 0b101,
opc: VectorSize,
};
pub const Decoded = union(enum) {
unallocated,
stp: Stp,
ldp: Ldp,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.opc) {
.single, .double, .quad => switch (inst.group.L) {
.store => .{ .stp = inst.stp },
.load => .{ .ldp = inst.ldp },
},
_ => .unallocated,
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register (unscaled immediate)
pub const RegisterUnscaledImmediate = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b111,
size: u2,
};
pub const Integer = packed union {
group: @This().Group,
sturb: Sturb,
ldurb: Ldurb,
ldursb: Ldursb,
sturh: Sturh,
ldurh: Ldurh,
ldursh: Ldursh,
stur: Stur,
ldur: Ldur,
ldursw: Ldursw,
prfum: Prfum,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// C6.2.347 STURB
pub const Sturb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.203 LDURB
pub const Ldurb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.205 LDURSB
pub const Ldursb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.348 STURH
pub const Sturh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.204 LDURH
pub const Ldurh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.206 LDURSH
pub const Ldursh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.346 STUR
pub const Stur = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.202 LDUR
pub const Ldur = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.207 LDURSW
pub const Ldursw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .word,
};
/// C6.2.250 PRFUM
pub const Prfum = packed struct {
prfop: PrfOp,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .doubleword,
};
pub const Decoded = union(enum) {
unallocated,
sturb: Sturb,
ldurb: Ldurb,
ldursb: Ldursb,
sturh: Sturh,
ldurh: Ldurh,
ldursh: Ldursh,
stur: Stur,
ldur: Ldur,
ldursw: Ldursw,
prfum: Prfum,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size) {
.byte => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .sturb = inst.sturb },
0b01 => .{ .ldurb = inst.ldurb },
0b10, 0b11 => .{ .ldursb = inst.ldursb },
},
true => .unallocated,
},
.halfword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .sturh = inst.sturh },
0b01 => .{ .ldurh = inst.ldurh },
0b10, 0b11 => .{ .ldursh = inst.ldursh },
},
true => .unallocated,
},
.word => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .stur = inst.stur },
0b01 => .{ .ldur = inst.ldur },
0b10 => .{ .ldursw = inst.ldursw },
0b11 => .unallocated,
},
true => .unallocated,
},
.doubleword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .stur = inst.stur },
0b01 => .{ .ldur = inst.ldur },
0b10 => .{ .prfum = inst.prfum },
0b11 => .unallocated,
},
true => .unallocated,
},
};
}
};
pub const Vector = packed union {
group: @This().Group,
stur: Stur,
ldur: Ldur,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.333 STUR (SIMD&FP)
pub const Stur = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .store,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.194 LDUR (SIMD&FP)
pub const Ldur = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .load,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
pub const Opc1 = packed struct {
encoded: u1,
pub fn encode(vs: Register.VectorSize) Opc1 {
return .{ .encoded = switch (vs) {
.byte, .half, .single, .double => 0b0,
.quad => 0b1,
else => unreachable,
} };
}
pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
return switch (enc_size.encoded) {
0b00 => switch (enc_opc1.encoded) {
0b0 => .byte,
0b1 => .quad,
},
0b01 => switch (enc_opc1.encoded) {
0b0 => .half,
0b1 => unreachable,
},
0b10 => switch (enc_opc1.encoded) {
0b0 => .single,
0b1 => unreachable,
},
0b11 => switch (enc_opc1.encoded) {
0b0 => .double,
0b1 => unreachable,
},
};
}
};
pub const Size = packed struct {
encoded: u2,
pub fn encode(vs: Register.VectorSize) Size {
return .{ .encoded = switch (vs) {
.byte, .quad => 0b00,
.half => 0b01,
.single => 0b10,
.double => 0b11,
else => unreachable,
} };
}
};
pub const Decoded = union(enum) {
unallocated,
stur: Stur,
ldur: Ldur,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size.encoded) {
0b00 => switch (inst.group.opc0) {
.store => .{ .stur = inst.stur },
.load => .{ .ldur = inst.ldur },
},
0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
0b0 => switch (inst.group.opc0) {
.store => .{ .stur = inst.stur },
.load => .{ .ldur = inst.ldur },
},
0b1 => .unallocated,
},
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register (immediate post-indexed)
pub const RegisterImmediatePostIndexed = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b111,
size: u2,
};
pub const Integer = packed union {
group: @This().Group,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// C6.2.324 STRB (immediate)
pub const Strb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.170 LDRB (immediate)
pub const Ldrb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.174 LDRSB (immediate)
pub const Ldrsb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.326 STRH (immediate)
pub const Strh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.172 LDRH (immediate)
pub const Ldrh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.176 LDRSH (immediate)
pub const Ldrsh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.322 STR (immediate)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.166 LDR (immediate)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.178 LDRSW (immediate)
pub const Ldrsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .word,
};
pub const Decoded = union(enum) {
unallocated,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size) {
.byte => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strb = inst.strb },
0b01 => .{ .ldrb = inst.ldrb },
0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
},
true => .unallocated,
},
.halfword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strh = inst.strh },
0b01 => .{ .ldrh = inst.ldrh },
0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
},
true => .unallocated,
},
.word => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .ldrsw = inst.ldrsw },
0b11 => .unallocated,
},
true => .unallocated,
},
.doubleword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10, 0b11 => .unallocated,
},
true => .unallocated,
},
};
}
};
pub const Vector = packed union {
group: @This().Group,
str: Str,
ldr: Ldr,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.331 STR (immediate, SIMD&FP)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .store,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.191 LDR (immediate, SIMD&FP)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b01,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .load,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
pub const Opc1 = packed struct {
encoded: u1,
pub fn encode(vs: Register.VectorSize) Opc1 {
return .{ .encoded = switch (vs) {
.byte, .half, .single, .double => 0b0,
.quad => 0b1,
else => unreachable,
} };
}
pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
return switch (enc_size.encoded) {
0b00 => switch (enc_opc1.encoded) {
0b0 => .byte,
0b1 => .quad,
},
0b01 => switch (enc_opc1.encoded) {
0b0 => .half,
0b1 => unreachable,
},
0b10 => switch (enc_opc1.encoded) {
0b0 => .single,
0b1 => unreachable,
},
0b11 => switch (enc_opc1.encoded) {
0b0 => .double,
0b1 => unreachable,
},
};
}
};
pub const Size = packed struct {
encoded: u2,
pub fn encode(vs: Register.VectorSize) Size {
return .{ .encoded = switch (vs) {
.byte, .quad => 0b00,
.half => 0b01,
.single => 0b10,
.double => 0b11,
else => unreachable,
} };
}
};
pub const Decoded = union(enum) {
unallocated,
str: Str,
ldr: Ldr,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size.encoded) {
0b00 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
0b0 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b1 => .unallocated,
},
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register (unprivileged)
pub const RegisterUnprivileged = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// Load/store register (immediate pre-indexed)
pub const RegisterImmediatePreIndexed = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b111,
size: u2,
};
pub const Integer = packed union {
group: @This().Group,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// C6.2.324 STRB (immediate)
pub const Strb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.170 LDRB (immediate)
pub const Ldrb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.174 LDRSB (immediate)
pub const Ldrsb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.326 STRH (immediate)
pub const Strh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.172 LDRH (immediate)
pub const Ldrh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.176 LDRSH (immediate)
pub const Ldrsh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.322 STR (immediate)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.166 LDR (immediate)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.178 LDRSW (immediate)
pub const Ldrsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .word,
};
pub const Decoded = union(enum) {
unallocated,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size) {
.byte => switch (inst.group.opc) {
0b00 => .{ .strb = inst.strb },
0b01 => .{ .ldrb = inst.ldrb },
0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
},
.halfword => switch (inst.group.opc) {
0b00 => .{ .strh = inst.strh },
0b01 => .{ .ldrh = inst.ldrh },
0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
},
.word => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .ldrsw = inst.ldrsw },
0b11 => .unallocated,
},
.doubleword => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10, 0b11 => .unallocated,
},
};
}
};
pub const Vector = packed union {
group: @This().Group,
str: Str,
ldr: Ldr,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.331 STR (immediate, SIMD&FP)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .store,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.191 LDR (immediate, SIMD&FP)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
imm9: i9,
decoded21: u1 = 0b0,
opc0: L = .load,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
pub const Opc1 = packed struct {
encoded: u1,
pub fn encode(vs: Register.VectorSize) Opc1 {
return .{ .encoded = switch (vs) {
.byte, .half, .single, .double => 0b0,
.quad => 0b1,
else => unreachable,
} };
}
pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
return switch (enc_size.encoded) {
0b00 => switch (enc_opc1.encoded) {
0b0 => .byte,
0b1 => .quad,
},
0b01 => switch (enc_opc1.encoded) {
0b0 => .half,
0b1 => unreachable,
},
0b10 => switch (enc_opc1.encoded) {
0b0 => .single,
0b1 => unreachable,
},
0b11 => switch (enc_opc1.encoded) {
0b0 => .double,
0b1 => unreachable,
},
};
}
};
pub const Size = packed struct {
encoded: u2,
pub fn encode(vs: Register.VectorSize) Size {
return .{ .encoded = switch (vs) {
.byte, .quad => 0b00,
.half => 0b01,
.single => 0b10,
.double => 0b11,
else => unreachable,
} };
}
};
pub const Decoded = union(enum) {
unallocated,
str: Str,
ldr: Ldr,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size.encoded) {
0b00 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
0b0 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b1 => .unallocated,
},
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register (register offset)
pub const RegisterRegisterOffset = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2,
decoded24: u2 = 0b00,
V: bool,
decoded27: u3 = 0b111,
size: u2,
};
pub const Integer = packed union {
group: @This().Group,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
prfm: Prfm,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// C6.2.325 STRB (register)
pub const Strb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.171 LDRB (register)
pub const Ldrb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.175 LDRSB (register)
pub const Ldrsb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.327 STRH (register)
pub const Strh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.173 LDRH (register)
pub const Ldrh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.177 LDRSH (register)
pub const Ldrsh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.323 STR (register)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b00,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.168 LDR (register)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b01,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.180 LDRSW (register)
pub const Ldrsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .word,
};
/// C6.2.249 PRFM (register)
pub const Prfm = packed struct {
prfop: PrfOp,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2 = 0b10,
decoded24: u2 = 0b00,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .doubleword,
};
pub const Decoded = union(enum) {
unallocated,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
prfm: Prfm,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size) {
.byte => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strb = inst.strb },
0b01 => .{ .ldrb = inst.ldrb },
0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
},
true => .unallocated,
},
.halfword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strh = inst.strh },
0b01 => .{ .ldrh = inst.ldrh },
0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
},
true => .unallocated,
},
.word => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .ldrsw = inst.ldrsw },
0b11 => .unallocated,
},
true => .unallocated,
},
.doubleword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .prfm = inst.prfm },
0b11 => .unallocated,
},
true => .unallocated,
},
};
}
};
pub const Vector = packed union {
group: @This().Group,
str: Str,
ldr: Ldr,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc: u2,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.332 STR (register, SIMD&FP)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc0: L = .store,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.193 LDR (register, SIMD&FP)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
S: bool,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opc0: L = .load,
opc1: Opc1,
decoded24: u2 = 0b00,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
pub const Opc1 = packed struct {
encoded: u1,
pub fn encode(vs: Register.VectorSize) Opc1 {
return .{ .encoded = switch (vs) {
.byte, .half, .single, .double => 0b0,
.quad => 0b1,
else => unreachable,
} };
}
pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
return switch (enc_size.encoded) {
0b00 => switch (enc_opc1.encoded) {
0b0 => .byte,
0b1 => .quad,
},
0b01 => switch (enc_opc1.encoded) {
0b0 => .half,
0b1 => unreachable,
},
0b10 => switch (enc_opc1.encoded) {
0b0 => .single,
0b1 => unreachable,
},
0b11 => switch (enc_opc1.encoded) {
0b0 => .double,
0b1 => unreachable,
},
};
}
};
pub const Size = packed struct {
encoded: u2,
pub fn encode(vs: Register.VectorSize) Size {
return .{ .encoded = switch (vs) {
.byte, .quad => 0b00,
.half => 0b01,
.single => 0b10,
.double => 0b11,
else => unreachable,
} };
}
};
};
pub const Option = enum(u3) {
uxtw = 0b010,
lsl = 0b011,
sxtw = 0b110,
sxtx = 0b111,
_,
pub fn sf(option: Option) Register.IntegerSize {
return switch (option) {
.uxtw, .sxtw => .word,
.lsl, .sxtx => .doubleword,
_ => unreachable,
};
}
};
pub const Extend = union(Option) {
uxtw: Amount,
lsl: Amount,
sxtw: Amount,
sxtx: Amount,
pub const Amount = u3;
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
/// Load/store register (unsigned immediate)
pub const RegisterUnsignedImmediate = packed union {
group: @This().Group,
integer: Integer,
vector: Vector,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2,
decoded24: u2 = 0b01,
V: bool,
decoded27: u3 = 0b111,
size: u2,
};
pub const Integer = packed union {
group: @This().Group,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
prfm: Prfm,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize,
};
/// C6.2.324 STRB (immediate)
pub const Strb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b00,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.170 LDRB (immediate)
pub const Ldrb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b01,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.174 LDRSB (immediate)
pub const Ldrsb = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .byte,
};
/// C6.2.326 STRH (immediate)
pub const Strh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b00,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.172 LDRH (immediate)
pub const Ldrh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b01,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.176 LDRSH (immediate)
pub const Ldrsh = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc0: u1,
opc1: u1 = 0b1,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .halfword,
};
/// C6.2.322 STR (immediate)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b00,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.166 LDR (immediate)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b01,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
sf: Register.IntegerSize,
size1: u1 = 0b1,
};
/// C6.2.178 LDRSW (immediate)
pub const Ldrsw = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b10,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .word,
};
/// C6.2.247 PRFM (immediate)
pub const Prfm = packed struct {
prfop: PrfOp,
Rn: Register.Encoded,
imm12: u12,
opc: u2 = 0b10,
decoded24: u2 = 0b01,
V: bool = false,
decoded27: u3 = 0b111,
size: IntegerSize = .doubleword,
};
pub const Decoded = union(enum) {
unallocated,
strb: Strb,
ldrb: Ldrb,
ldrsb: Ldrsb,
strh: Strh,
ldrh: Ldrh,
ldrsh: Ldrsh,
str: Str,
ldr: Ldr,
ldrsw: Ldrsw,
prfm: Prfm,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size) {
.byte => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strb = inst.strb },
0b01 => .{ .ldrb = inst.ldrb },
0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
},
true => .unallocated,
},
.halfword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .strh = inst.strh },
0b01 => .{ .ldrh = inst.ldrh },
0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
},
true => .unallocated,
},
.word => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .ldrsw = inst.ldrsw },
0b11 => .unallocated,
},
true => .unallocated,
},
.doubleword => switch (inst.group.V) {
false => switch (inst.group.opc) {
0b00 => .{ .str = inst.str },
0b01 => .{ .ldr = inst.ldr },
0b10 => .{ .prfm = inst.prfm },
0b11 => .unallocated,
},
true => .unallocated,
},
};
}
};
pub const Vector = packed union {
group: @This().Group,
str: Str,
ldr: Ldr,
pub const Group = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc0: L,
opc1: Opc1,
decoded24: u2 = 0b01,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.331 STR (immediate, SIMD&FP)
pub const Str = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc0: L = .store,
opc1: Opc1,
decoded24: u2 = 0b01,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
/// C7.2.191 LDR (immediate, SIMD&FP)
pub const Ldr = packed struct {
Rt: Register.Encoded,
Rn: Register.Encoded,
imm12: u12,
opc0: L = .load,
opc1: Opc1,
decoded24: u2 = 0b01,
V: bool = true,
decoded27: u3 = 0b111,
size: Size,
};
pub const Opc1 = packed struct {
encoded: u1,
pub fn encode(vs: Register.VectorSize) Opc1 {
return .{ .encoded = switch (vs) {
.byte, .half, .single, .double => 0b0,
.quad => 0b1,
else => unreachable,
} };
}
pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
return switch (enc_size.encoded) {
0b00 => switch (enc_opc1.encoded) {
0b0 => .byte,
0b1 => .quad,
},
0b01 => switch (enc_opc1.encoded) {
0b0 => .half,
0b1 => unreachable,
},
0b10 => switch (enc_opc1.encoded) {
0b0 => .single,
0b1 => unreachable,
},
0b11 => switch (enc_opc1.encoded) {
0b0 => .double,
0b1 => unreachable,
},
};
}
};
pub const Size = packed struct {
encoded: u2,
pub fn encode(vs: Register.VectorSize) Size {
return .{ .encoded = switch (vs) {
.byte, .quad => 0b00,
.half => 0b01,
.single => 0b10,
.double => 0b11,
else => unreachable,
} };
}
};
pub const Decoded = union(enum) {
unallocated,
str: Str,
ldr: Ldr,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.size.encoded) {
0b00 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
0b0 => switch (inst.group.opc0) {
.store => .{ .str = inst.str },
.load => .{ .ldr = inst.ldr },
},
0b1 => .unallocated,
},
};
}
};
pub const Decoded = union(enum) {
integer: Integer,
vector: Vector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.V) {
false => .{ .integer = inst.integer },
true => .{ .vector = inst.vector },
};
}
};
pub const L = enum(u1) {
store = 0b0,
load = 0b1,
};
pub const IntegerSize = enum(u2) {
byte = 0b00,
halfword = 0b01,
word = 0b10,
doubleword = 0b11,
};
pub const VectorSize = enum(u2) {
single = 0b00,
double = 0b01,
quad = 0b10,
_,
pub fn decode(vs: VectorSize) Register.VectorSize {
return switch (vs) {
.single => .single,
.double => .double,
.quad => .quad,
_ => unreachable,
};
}
pub fn encode(vs: Register.VectorSize) VectorSize {
return switch (vs) {
else => unreachable,
.single => .single,
.double => .double,
.quad => .quad,
};
}
};
pub const PrfOp = packed struct {
policy: Policy,
target: Target,
type: Type,
pub const Policy = enum(u1) {
keep = 0b0,
strm = 0b1,
};
pub const Target = enum(u2) {
l1 = 0b00,
l2 = 0b01,
l3 = 0b10,
_,
};
pub const Type = enum(u2) {
pld = 0b00,
pli = 0b01,
pst = 0b10,
_,
};
pub const pldl1keep: PrfOp = .{ .type = .pld, .target = .l1, .policy = .keep };
pub const pldl1strm: PrfOp = .{ .type = .pld, .target = .l1, .policy = .strm };
pub const pldl2keep: PrfOp = .{ .type = .pld, .target = .l2, .policy = .keep };
pub const pldl2strm: PrfOp = .{ .type = .pld, .target = .l2, .policy = .strm };
pub const pldl3keep: PrfOp = .{ .type = .pld, .target = .l3, .policy = .keep };
pub const pldl3strm: PrfOp = .{ .type = .pld, .target = .l3, .policy = .strm };
pub const plil1keep: PrfOp = .{ .type = .pli, .target = .l1, .policy = .keep };
pub const plil1strm: PrfOp = .{ .type = .pli, .target = .l1, .policy = .strm };
pub const plil2keep: PrfOp = .{ .type = .pli, .target = .l2, .policy = .keep };
pub const plil2strm: PrfOp = .{ .type = .pli, .target = .l2, .policy = .strm };
pub const plil3keep: PrfOp = .{ .type = .pli, .target = .l3, .policy = .keep };
pub const plil3strm: PrfOp = .{ .type = .pli, .target = .l3, .policy = .strm };
pub const pstl1keep: PrfOp = .{ .type = .pst, .target = .l1, .policy = .keep };
pub const pstl1strm: PrfOp = .{ .type = .pst, .target = .l1, .policy = .strm };
pub const pstl2keep: PrfOp = .{ .type = .pst, .target = .l2, .policy = .keep };
pub const pstl2strm: PrfOp = .{ .type = .pst, .target = .l2, .policy = .strm };
pub const pstl3keep: PrfOp = .{ .type = .pst, .target = .l3, .policy = .keep };
pub const pstl3strm: PrfOp = .{ .type = .pst, .target = .l3, .policy = .strm_ };
};
pub const Decoded = union(enum) {
unallocated,
register_literal: RegisterLiteral,
memory: Memory,
no_allocate_pair_offset: NoAllocatePairOffset,
register_pair_post_indexed: RegisterPairPostIndexed,
register_pair_offset: RegisterPairOffset,
register_pair_pre_indexed: RegisterPairPreIndexed,
register_unscaled_immediate: RegisterUnscaledImmediate,
register_immediate_post_indexed: RegisterImmediatePostIndexed,
register_unprivileged: RegisterUnprivileged,
register_immediate_pre_indexed: RegisterImmediatePreIndexed,
register_register_offset: RegisterRegisterOffset,
register_unsigned_immediate: RegisterUnsignedImmediate,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op0) {
else => .unallocated,
0b0010, 0b0110, 0b1010, 0b1110 => switch (inst.group.op2) {
0b00 => .{ .no_allocate_pair_offset = inst.no_allocate_pair_offset },
0b01 => .{ .register_pair_post_indexed = inst.register_pair_post_indexed },
0b10 => .{ .register_pair_offset = inst.register_pair_offset },
0b11 => .{ .register_pair_pre_indexed = inst.register_pair_pre_indexed },
},
0b0011, 0b0111, 0b1011, 0b1111 => switch (inst.group.op2) {
0b00...0b01 => switch (inst.group.op3) {
0b000000...0b011111 => switch (inst.group.op4) {
0b00 => .{ .register_unscaled_immediate = inst.register_unscaled_immediate },
0b01 => .{ .register_immediate_post_indexed = inst.register_immediate_post_indexed },
0b10 => .{ .register_unprivileged = inst.register_unprivileged },
0b11 => .{ .register_immediate_pre_indexed = inst.register_immediate_pre_indexed },
},
0b100000...0b111111 => switch (inst.group.op4) {
0b00 => .unallocated,
0b10 => .{ .register_register_offset = inst.register_register_offset },
0b01, 0b11 => .unallocated,
},
},
0b10...0b11 => .{ .register_unsigned_immediate = inst.register_unsigned_immediate },
},
};
}
};
/// C4.1.89 Data Processing -- Register
pub const DataProcessingRegister = packed union {
group: @This().Group,
data_processing_two_source: DataProcessingTwoSource,
data_processing_one_source: DataProcessingOneSource,
logical_shifted_register: LogicalShiftedRegister,
add_subtract_shifted_register: AddSubtractShiftedRegister,
add_subtract_extended_register: AddSubtractExtendedRegister,
add_subtract_with_carry: AddSubtractWithCarry,
rotate_right_into_flags: RotateRightIntoFlags,
evaluate_into_flags: EvaluateIntoFlags,
conditional_compare_register: ConditionalCompareRegister,
conditional_compare_immediate: ConditionalCompareImmediate,
conditional_select: ConditionalSelect,
data_processing_three_source: DataProcessingThreeSource,
/// Table C4-90 Encoding table for the Data Processing -- Register group
pub const Group = packed struct {
encoded0: u10,
op3: u6,
encoded16: u5,
op2: u4,
decoded25: u3 = 0b101,
op1: u1,
encoded29: u1,
op0: u1,
encoded31: u1,
};
/// Data-processing (2 source)
pub const DataProcessingTwoSource = packed union {
group: @This().Group,
udiv: Udiv,
sdiv: Sdiv,
lslv: Lslv,
lsrv: Lsrv,
asrv: Asrv,
rorv: Rorv,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
opcode: u6,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.388 UDIV
pub const Udiv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
o1: DivOp = .udiv,
decoded11: u5 = 0b00001,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.270 SDIV
pub const Sdiv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
o1: DivOp = .sdiv,
decoded11: u5 = 0b00001,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.214 LSLV
pub const Lslv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: ShiftOp = .lslv,
decoded12: u4 = 0b0010,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.217 LSRV
pub const Lsrv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: ShiftOp = .lsrv,
decoded12: u4 = 0b0010,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.18 ASRV
pub const Asrv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: ShiftOp = .asrv,
decoded12: u4 = 0b0010,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.263 RORV
pub const Rorv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: ShiftOp = .rorv,
decoded12: u4 = 0b0010,
Rm: Register.Encoded,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
pub const DivOp = enum(u1) {
udiv = 0b0,
sdiv = 0b1,
};
pub const ShiftOp = enum(u2) {
lslv = 0b00,
lsrv = 0b01,
asrv = 0b10,
rorv = 0b11,
};
pub const Decoded = union(enum) {
unallocated,
udiv: Udiv,
sdiv: Sdiv,
lslv: Lslv,
lsrv: Lsrv,
asrv: Asrv,
rorv: Rorv,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.S) {
false => switch (inst.group.opcode) {
else => .unallocated,
0b000010 => .{ .udiv = inst.udiv },
0b000011 => .{ .sdiv = inst.sdiv },
0b001000 => .{ .lslv = inst.lslv },
0b001001 => .{ .lsrv = inst.lsrv },
0b001010 => .{ .asrv = inst.asrv },
0b001011 => .{ .rorv = inst.rorv },
},
true => .unallocated,
};
}
};
/// Data-processing (1 source)
pub const DataProcessingOneSource = packed union {
group: @This().Group,
rbit: Rbit,
rev16: Rev16,
rev32: Rev32,
rev: Rev,
clz: Clz,
cls: Cls,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
opcode: u6,
opcode2: u5,
decoded21: u8 = 0b11010110,
S: bool,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.253 RBIT
pub const Rbit = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b00,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.257 REV16
pub const Rev16 = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
opc: u2 = 0b01,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.258 REV32
pub const Rev32 = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
opc: u2 = 0b10,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.256 REV
pub const Rev = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
opc0: Register.IntegerSize,
opc1: u1 = 0b1,
decoded12: u4 = 0b0000,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.58 CLZ
pub const Clz = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op: u1 = 0b0,
decoded11: u5 = 0b00010,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.57 CLS
pub const Cls = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op: u1 = 0b1,
decoded11: u5 = 0b00010,
decoded16: u5 = 0b00000,
decoded21: u8 = 0b11010110,
S: bool = false,
decoded30: u1 = 0b1,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
rbit: Rbit,
rev16: Rev16,
rev32: Rev32,
rev: Rev,
clz: Clz,
cls: Cls,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.S) {
true => .unallocated,
false => switch (inst.group.opcode2) {
else => .unallocated,
0b00000 => switch (inst.group.opcode) {
else => .unallocated,
0b000000 => .{ .rbit = inst.rbit },
0b000001 => .{ .rev16 = inst.rev16 },
0b000010 => switch (inst.group.sf) {
.word => .{ .rev = inst.rev },
.doubleword => .{ .rev32 = inst.rev32 },
},
0b000011 => switch (inst.group.sf) {
.word => .unallocated,
.doubleword => .{ .rev = inst.rev },
},
0b000100 => .{ .clz = inst.clz },
0b000101 => .{ .cls = inst.cls },
},
},
};
}
};
/// Logical (shifted register)
pub const LogicalShiftedRegister = packed union {
group: @This().Group,
@"and": And,
bic: Bic,
orr: Orr,
orn: Orn,
eor: Eor,
eon: Eon,
ands: Ands,
bics: Bics,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc,
sf: Register.IntegerSize,
};
/// C6.2.13 AND (shifted register)
pub const And = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = false,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .@"and",
sf: Register.IntegerSize,
};
/// C6.2.32 BIC (shifted register)
pub const Bic = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = true,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .@"and",
sf: Register.IntegerSize,
};
/// C6.2.241 ORR (shifted register)
pub const Orr = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = false,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .orr,
sf: Register.IntegerSize,
};
/// C6.2.239 ORN (shifted register)
pub const Orn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = true,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .orr,
sf: Register.IntegerSize,
};
/// C6.2.120 EOR (shifted register)
pub const Eor = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = false,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .eor,
sf: Register.IntegerSize,
};
/// C6.2.118 EON (shifted register)
pub const Eon = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = true,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .eor,
sf: Register.IntegerSize,
};
/// C6.2.15 ANDS (shifted register)
pub const Ands = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = false,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .ands,
sf: Register.IntegerSize,
};
/// C6.2.33 BICS (shifted register)
pub const Bics = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
N: bool = true,
shift: Shift.Op,
decoded24: u5 = 0b01010,
opc: LogicalOpc = .ands,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
@"and": And,
bic: Bic,
orr: Orr,
orn: Orn,
eor: Eor,
eon: Eon,
ands: Ands,
bics: Bics,
};
pub fn decode(inst: @This()) @This().Decoded {
return if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
.unallocated
else switch (inst.group.opc) {
.@"and" => switch (inst.group.N) {
false => .{ .@"and" = inst.@"and" },
true => .{ .bic = inst.bic },
},
.orr => switch (inst.group.N) {
false => .{ .orr = inst.orr },
true => .{ .orn = inst.orn },
},
.eor => switch (inst.group.N) {
false => .{ .eor = inst.eor },
true => .{ .eon = inst.eon },
},
.ands => switch (inst.group.N) {
false => .{ .ands = inst.ands },
true => .{ .bics = inst.bics },
},
};
}
};
/// Add/subtract (shifted register)
pub const AddSubtractShiftedRegister = packed union {
group: @This().Group,
add: Add,
adds: Adds,
sub: Sub,
subs: Subs,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
decoded21: u1 = 0b0,
shift: Shift.Op,
decoded24: u5 = 0b01011,
S: bool,
op: AddSubtractOp,
sf: Register.IntegerSize,
};
/// C6.2.5 ADD (shifted register)
pub const Add = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
decoded21: u1 = 0b0,
shift: Shift.Op,
decoded24: u5 = 0b01011,
S: bool = false,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.9 ADDS (shifted register)
pub const Adds = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
decoded21: u1 = 0b0,
shift: Shift.Op,
decoded24: u5 = 0b01011,
S: bool = true,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.5 SUB (shifted register)
pub const Sub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
decoded21: u1 = 0b0,
shift: Shift.Op,
decoded24: u5 = 0b01011,
S: bool = false,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
/// C6.2.9 SUBS (shifted register)
pub const Subs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm6: Shift.Amount,
Rm: Register.Encoded,
decoded21: u1 = 0b0,
shift: Shift.Op,
decoded24: u5 = 0b01011,
S: bool = true,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
add: Add,
adds: Adds,
sub: Sub,
subs: Subs,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.shift) {
.ror => .unallocated,
.lsl, .lsr, .asr => if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
.unallocated
else switch (inst.group.op) {
.add => switch (inst.group.S) {
false => .{ .add = inst.add },
true => .{ .adds = inst.adds },
},
.sub => switch (inst.group.S) {
false => .{ .sub = inst.sub },
true => .{ .subs = inst.subs },
},
},
};
}
};
/// Add/subtract (extended register)
pub const AddSubtractExtendedRegister = packed union {
group: @This().Group,
add: Add,
adds: Adds,
sub: Sub,
subs: Subs,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm3: Extend.Amount,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opt: u2,
decoded24: u5 = 0b01011,
S: bool,
op: AddSubtractOp,
sf: Register.IntegerSize,
};
/// C6.2.3 ADD (extended register)
pub const Add = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm3: Extend.Amount,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opt: u2 = 0b00,
decoded24: u5 = 0b01011,
S: bool = false,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.7 ADDS (extended register)
pub const Adds = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm3: Extend.Amount,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opt: u2 = 0b00,
decoded24: u5 = 0b01011,
S: bool = true,
op: AddSubtractOp = .add,
sf: Register.IntegerSize,
};
/// C6.2.356 SUB (extended register)
pub const Sub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm3: Extend.Amount,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opt: u2 = 0b00,
decoded24: u5 = 0b01011,
S: bool = false,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
/// C6.2.362 SUBS (extended register)
pub const Subs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
imm3: Extend.Amount,
option: Option,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
opt: u2 = 0b00,
decoded24: u5 = 0b01011,
S: bool = true,
op: AddSubtractOp = .sub,
sf: Register.IntegerSize,
};
pub const Option = enum(u3) {
uxtb = 0b000,
uxth = 0b001,
uxtw = 0b010,
uxtx = 0b011,
sxtb = 0b100,
sxth = 0b101,
sxtw = 0b110,
sxtx = 0b111,
pub fn sf(option: Option) Register.IntegerSize {
return switch (option) {
.uxtb, .uxth, .uxtw, .sxtb, .sxth, .sxtw => .word,
.uxtx, .sxtx => .doubleword,
};
}
};
pub const Extend = union(Option) {
uxtb: Amount,
uxth: Amount,
uxtw: Amount,
uxtx: Amount,
sxtb: Amount,
sxth: Amount,
sxtw: Amount,
sxtx: Amount,
pub const Amount = u3;
};
pub const Decoded = union(enum) {
unallocated,
add: Add,
adds: Adds,
sub: Sub,
subs: Subs,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.imm3) {
0b101 => .unallocated,
0b110...0b111 => .unallocated,
0b000...0b100 => switch (inst.group.opt) {
0b01 => .unallocated,
0b10...0b11 => .unallocated,
0b00 => switch (inst.group.op) {
.add => switch (inst.group.S) {
false => .{ .add = inst.add },
true => .{ .adds = inst.adds },
},
.sub => switch (inst.group.S) {
false => .{ .sub = inst.sub },
true => .{ .subs = inst.subs },
},
},
},
};
}
};
/// Add/subtract (with carry)
pub const AddSubtractWithCarry = packed union {
group: @This().Group,
adc: Adc,
adcs: Adcs,
sbc: Sbc,
sbcs: Sbcs,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
Rm: Register.Encoded,
decoded21: u8 = 0b11010000,
S: bool,
op: Op,
sf: Register.IntegerSize,
};
/// C6.2.1 ADC
pub const Adc = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
Rm: Register.Encoded,
decoded21: u8 = 0b11010000,
S: bool = false,
op: Op = .adc,
sf: Register.IntegerSize,
};
/// C6.2.2 ADCS
pub const Adcs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
Rm: Register.Encoded,
decoded21: u8 = 0b11010000,
S: bool = true,
op: Op = .adc,
sf: Register.IntegerSize,
};
/// C6.2.265 SBC
pub const Sbc = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
Rm: Register.Encoded,
decoded21: u8 = 0b11010000,
S: bool = false,
op: Op = .sbc,
sf: Register.IntegerSize,
};
/// C6.2.266 SBCS
pub const Sbcs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
Rm: Register.Encoded,
decoded21: u8 = 0b11010000,
S: bool = true,
op: Op = .sbc,
sf: Register.IntegerSize,
};
pub const Op = enum(u1) {
adc = 0b0,
sbc = 0b1,
};
pub const Decoded = union(enum) {
adc: Adc,
adcs: Adcs,
sbc: Sbc,
sbcs: Sbcs,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op) {
.adc => switch (inst.group.S) {
false => .{ .adc = inst.adc },
true => .{ .adcs = inst.adcs },
},
.sbc => switch (inst.group.S) {
false => .{ .sbc = inst.sbc },
true => .{ .sbcs = inst.sbcs },
},
};
}
};
/// Rotate right into flags
pub const RotateRightIntoFlags = packed union {
group: @This().Group,
pub const Group = packed struct {
mask: Nzcv,
o2: u1,
Rn: Register.Encoded,
decoded10: u5 = 0b0001,
imm6: u6,
decoded21: u8 = 0b11010000,
S: bool,
op: u1,
sf: Register.IntegerSize,
};
};
/// Evaluate into flags
pub const EvaluateIntoFlags = packed union {
group: @This().Group,
pub const Group = packed struct {
mask: Nzcv,
o3: u1,
Rn: Register.Encoded,
decoded10: u4 = 0b0010,
sz: enum(u1) {
byte = 0b0,
word = 0b1,
},
opcode2: u6,
decoded21: u8 = 0b11010000,
S: bool,
op: u1,
sf: Register.IntegerSize,
};
};
/// Conditional compare (register)
pub const ConditionalCompareRegister = packed union {
group: @This().Group,
ccmn: Ccmn,
ccmp: Ccmp,
pub const Group = packed struct {
nzcv: Nzcv,
o3: u1,
Rn: Register.Encoded,
o2: u1,
decoded11: u1 = 0b0,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010010,
S: bool,
op: Op,
sf: Register.IntegerSize,
};
/// C6.2.49 CCMN (register)
pub const Ccmn = packed struct {
nzcv: Nzcv,
o3: u1 = 0b0,
Rn: Register.Encoded,
o2: u1 = 0b0,
decoded11: u1 = 0b0,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010010,
S: bool = true,
op: Op = .ccmn,
sf: Register.IntegerSize,
};
/// C6.2.51 CCMP (register)
pub const Ccmp = packed struct {
nzcv: Nzcv,
o3: u1 = 0b0,
Rn: Register.Encoded,
o2: u1 = 0b0,
decoded11: u1 = 0b0,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010010,
S: bool = true,
op: Op = .ccmp,
sf: Register.IntegerSize,
};
pub const Op = enum(u1) {
ccmn = 0b0,
ccmp = 0b1,
};
};
/// Conditional compare (immediate)
pub const ConditionalCompareImmediate = packed union {
group: @This().Group,
ccmn: Ccmn,
ccmp: Ccmp,
pub const Group = packed struct {
nzcv: Nzcv,
o3: u1,
Rn: Register.Encoded,
o2: u1,
decoded11: u1 = 0b1,
cond: ConditionCode,
imm5: u5,
decoded21: u8 = 0b11010010,
S: bool,
op: Op,
sf: Register.IntegerSize,
};
/// C6.2.48 CCMN (immediate)
pub const Ccmn = packed struct {
nzcv: Nzcv,
o3: u1 = 0b0,
Rn: Register.Encoded,
o2: u1 = 0b0,
decoded11: u1 = 0b1,
cond: ConditionCode,
imm5: u5,
decoded21: u8 = 0b11010010,
S: bool = true,
op: Op = .ccmn,
sf: Register.IntegerSize,
};
/// C6.2.50 CCMP (immediate)
pub const Ccmp = packed struct {
nzcv: Nzcv,
o3: u1 = 0b0,
Rn: Register.Encoded,
o2: u1 = 0b0,
decoded11: u1 = 0b1,
cond: ConditionCode,
imm5: u5,
decoded21: u8 = 0b11010010,
S: bool = true,
op: Op = .ccmp,
sf: Register.IntegerSize,
};
pub const Op = enum(u1) {
ccmn = 0b0,
ccmp = 0b1,
};
};
/// Conditional select
pub const ConditionalSelect = packed union {
group: @This().Group,
csel: Csel,
csinc: Csinc,
csinv: Csinv,
csneg: Csneg,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: u2,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010100,
S: bool,
op: u1,
sf: Register.IntegerSize,
};
/// C6.2.103 CSEL
pub const Csel = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: u2 = 0b00,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010100,
S: bool = false,
op: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.106 CSINC
pub const Csinc = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: u2 = 0b01,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010100,
S: bool = false,
op: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C6.2.107 CSINV
pub const Csinv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: u2 = 0b00,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010100,
S: bool = false,
op: u1 = 0b1,
sf: Register.IntegerSize,
};
/// C6.2.108 CSNEG
pub const Csneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
op2: u2 = 0b01,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u8 = 0b11010100,
S: bool = false,
op: u1 = 0b1,
sf: Register.IntegerSize,
};
pub const Decoded = union(enum) {
unallocated,
csel: Csel,
csinc: Csinc,
csinv: Csinv,
csneg: Csneg,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.S) {
true => .unallocated,
false => switch (inst.group.op) {
0b0 => switch (inst.group.op2) {
0b10...0b11 => .unallocated,
0b00 => .{ .csel = inst.csel },
0b01 => .{ .csinc = inst.csinc },
},
0b1 => switch (inst.group.op2) {
0b10...0b11 => .unallocated,
0b00 => .{ .csinv = inst.csinv },
0b01 => .{ .csneg = inst.csneg },
},
},
};
}
};
/// Data-processing (3 source)
pub const DataProcessingThreeSource = packed union {
group: @This().Group,
madd: Madd,
msub: Msub,
smaddl: Smaddl,
smsubl: Smsubl,
smulh: Smulh,
umaddl: Umaddl,
umsubl: Umsubl,
umulh: Umulh,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp,
Rm: Register.Encoded,
op31: u3,
decoded24: u5 = 0b11011,
op54: u2,
sf: Register.IntegerSize,
};
/// C6.2.218 MADD
pub const Madd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op31: u3 = 0b000,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize,
};
/// C6.2.231 MSUB
pub const Msub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
op31: u3 = 0b000,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize,
};
/// C6.2.282 SMADDL
pub const Smaddl = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b01,
U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.287 SMSUBL
pub const Smsubl = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
op21: u2 = 0b01,
U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.288 SMULH
pub const Smulh = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded = @enumFromInt(0b11111),
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b10,
U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.389 UMADDL
pub const Umaddl = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b01,
U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.391 UMSUBL
pub const Umsubl = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
op21: u2 = 0b01,
U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
/// C6.2.392 UMULH
pub const Umulh = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded = @enumFromInt(0b11111),
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b10,
U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
};
pub const Decoded = union(enum) {
unallocated,
madd: Madd,
msub: Msub,
smaddl: Smaddl,
smsubl: Smsubl,
smulh: Smulh,
umaddl: Umaddl,
umsubl: Umsubl,
umulh: Umulh,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op54) {
0b01, 0b10...0b11 => .unallocated,
0b00 => switch (inst.group.op31) {
0b011, 0b100, 0b111 => .unallocated,
0b000 => switch (inst.group.o0) {
.add => .{ .madd = inst.madd },
.sub => .{ .msub = inst.msub },
},
0b001 => switch (inst.group.sf) {
.word => .unallocated,
.doubleword => switch (inst.group.o0) {
.add => .{ .smaddl = inst.smaddl },
.sub => .{ .smsubl = inst.smsubl },
},
},
0b010 => switch (inst.group.sf) {
.word => .unallocated,
.doubleword => switch (inst.group.o0) {
.add => .{ .smulh = inst.smulh },
.sub => .unallocated,
},
},
0b101 => switch (inst.group.sf) {
.word => .unallocated,
.doubleword => switch (inst.group.o0) {
.add => .{ .umaddl = inst.umaddl },
.sub => .{ .umsubl = inst.umsubl },
},
},
0b110 => switch (inst.group.sf) {
.word => .unallocated,
.doubleword => switch (inst.group.o0) {
.add => .{ .umulh = inst.umulh },
.sub => .unallocated,
},
},
},
};
}
};
pub const Shift = union(enum(u2)) {
lsl: Amount = 0b00,
lsr: Amount = 0b01,
asr: Amount = 0b10,
ror: Amount = 0b11,
pub const Op = @typeInfo(Shift).@"union".tag_type.?;
pub const Amount = u6;
pub const none: Shift = .{ .lsl = 0 };
};
pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool };
pub const Decoded = union(enum) {
unallocated,
data_processing_two_source: DataProcessingTwoSource,
data_processing_one_source: DataProcessingOneSource,
logical_shifted_register: LogicalShiftedRegister,
add_subtract_shifted_register: AddSubtractShiftedRegister,
add_subtract_extended_register: AddSubtractExtendedRegister,
add_subtract_with_carry: AddSubtractWithCarry,
rotate_right_into_flags: RotateRightIntoFlags,
evaluate_into_flags: EvaluateIntoFlags,
conditional_compare_register: ConditionalCompareRegister,
conditional_compare_immediate: ConditionalCompareImmediate,
conditional_select: ConditionalSelect,
data_processing_three_source: DataProcessingThreeSource,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op1) {
0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) {
0b0 => .{ .logical_shifted_register = inst.logical_shifted_register },
0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) {
0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register },
0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register },
},
},
0b1 => switch (inst.group.op2) {
0b0000 => switch (inst.group.op3) {
0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry },
0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags },
0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags },
else => .unallocated,
},
0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) {
0b0 => .{ .conditional_compare_register = inst.conditional_compare_register },
0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate },
},
0b0100 => .{ .conditional_select = inst.conditional_select },
0b0110 => switch (inst.group.op0) {
0b0 => .{ .data_processing_two_source = inst.data_processing_two_source },
0b1 => .{ .data_processing_one_source = inst.data_processing_one_source },
},
0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source },
else => .unallocated,
},
};
}
};
/// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
pub const DataProcessingVector = packed union {
group: @This().Group,
simd_scalar_copy: SimdScalarCopy,
simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16,
simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous,
simd_scalar_pairwise: SimdScalarPairwise,
simd_copy: SimdCopy,
simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16,
simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
simd_across_lanes: SimdAcrossLanes,
simd_three_same: SimdThreeSame,
simd_modified_immediate: SimdModifiedImmediate,
convert_float_integer: ConvertFloatInteger,
float_data_processing_one_source: FloatDataProcessingOneSource,
float_compare: FloatCompare,
float_immediate: FloatImmediate,
float_data_processing_two_source: FloatDataProcessingTwoSource,
float_conditional_select: FloatConditionalSelect,
float_data_processing_three_source: FloatDataProcessingThreeSource,
/// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group
pub const Group = packed struct {
encoded0: u10,
op3: u9,
op2: u4,
op1: u2,
decoded25: u3 = 0b111,
op0: u4,
};
/// Advanced SIMD scalar copy
pub const SimdScalarCopy = packed union {
group: @This().Group,
dup: Dup,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: u4,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b11110000,
op: u1,
decoded30: u2 = 0b01,
};
/// C7.2.39 DUP (element)
pub const Dup = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: u4 = 0b0000,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b11110000,
op: u1 = 0b0,
decoded30: u2 = 0b01,
};
pub const Decoded = union(enum) {
unallocated,
dup: Dup,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op) {
0b0 => switch (inst.group.imm4) {
else => .unallocated,
0b0000 => .{ .dup = inst.dup },
},
0b1 => .unallocated,
};
}
};
/// Advanced SIMD scalar two-register miscellaneous FP16
pub const SimdScalarTwoRegisterMiscellaneousFp16 = packed union {
group: @This().Group,
fcvtns: Fcvtns,
fcvtms: Fcvtms,
fcvtas: Fcvtas,
scvtf: Scvtf,
fcmgt: Fcmgt,
fcmeq: Fcmeq,
fcmlt: Fcmlt,
fcvtps: Fcvtps,
fcvtzs: Fcvtzs,
frecpe: Frecpe,
frecpx: Frecpx,
fcvtnu: Fcvtnu,
fcvtmu: Fcvtmu,
fcvtau: Fcvtau,
ucvtf: Ucvtf,
fcmge: Fcmge,
fcmle: Fcmle,
fcvtpu: Fcvtpu,
fcvtzu: Fcvtzu,
frsqrte: Frsqrte,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u6 = 0b111100,
a: u1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness,
decoded30: u2 = 0b01,
};
/// C7.2.80 FCVTNS (vector)
pub const Fcvtns = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.75 FCVTMS (vector)
pub const Fcvtms = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.70 FCVTAS (vector)
pub const Fcvtas = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.234 SCVTF (vector, integer)
pub const Scvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.61 FCMGT (zero)
pub const Fcmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.57 FCMEQ (zero)
pub const Fcmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.65 FCMLT (zero)
pub const Fcmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01110,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.84 FCVTPS (vector)
pub const Fcvtps = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.90 FCVTZS (vector, integer)
pub const Fcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.144 FRECPE
pub const Frecpe = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.146 FRECPX
pub const Frecpx = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11111,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.82 FCVTNU (vector)
pub const Fcvtnu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.77 FCVTMU (vector)
pub const Fcvtmu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.72 FCVTAU (vector)
pub const Fcvtau = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.353 UCVTF (vector, integer)
pub const Ucvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.59 FCMGE (zero)
pub const Fcmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.64 FCMLE (zero)
pub const Fcmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.86 FCVTPU (vector)
pub const Fcvtpu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.94 FCVTZU (vector, integer)
pub const Fcvtzu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.169 FRSQRTE
pub const Frsqrte = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
};
/// Advanced SIMD scalar two-register miscellaneous
pub const SimdScalarTwoRegisterMiscellaneous = packed union {
group: @This().Group,
suqadd: Suqadd,
sqabs: Sqabs,
cmgt: Cmgt,
cmeq: Cmeq,
cmlt: Cmlt,
abs: Abs,
sqxtn: Sqxtn,
fcvtns: Fcvtns,
fcvtms: Fcvtms,
fcvtas: Fcvtas,
scvtf: Scvtf,
fcmgt: Fcmgt,
fcmeq: Fcmeq,
fcmlt: Fcmlt,
fcvtps: Fcvtps,
fcvtzs: Fcvtzs,
frecpe: Frecpe,
frecpx: Frecpx,
usqadd: Usqadd,
sqneg: Sqneg,
cmge: Cmge,
cmle: Cmle,
neg: Neg,
sqxtun: Sqxtun,
uqxtn: Uqxtn,
fcvtxn: Fcvtxn,
fcvtnu: Fcvtnu,
fcvtmu: Fcvtmu,
fcvtau: Fcvtau,
ucvtf: Ucvtf,
fcmge: Fcmge,
fcmle: Fcmle,
fcvtpu: Fcvtpu,
fcvtzu: Fcvtzu,
frsqrte: Frsqrte,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness,
decoded30: u2 = 0b01,
};
/// C7.2.337 SUQADD
pub const Suqadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.282 SQABS
pub const Sqabs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00111,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.32 CMGT (zero)
pub const Cmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01000,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.28 CMEQ (zero)
pub const Cmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01001,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.36 CMLT (zero)
pub const Cmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01010,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.1 ABS
pub const Abs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.308 SQXTN
pub const Sqxtn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10100,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.80 FCVTNS (vector)
pub const Fcvtns = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.75 FCVTMS (vector)
pub const Fcvtms = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.70 FCVTAS (vector)
pub const Fcvtas = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.234 SCVTF (vector, integer)
pub const Scvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.61 FCMGT (zero)
pub const Fcmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.57 FCMEQ (zero)
pub const Fcmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.65 FCMLT (zero)
pub const Fcmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01110,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.84 FCVTPS (vector)
pub const Fcvtps = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.90 FCVTZS (vector, integer)
pub const Fcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.144 FRECPE
pub const Frecpe = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.146 FRECPX
pub const Frecpx = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11111,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
/// C7.2.394 USQADD
pub const Usqadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.292 SQNEG
pub const Sqneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00111,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.30 CMGE (zero)
pub const Cmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01000,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.35 CMLE (zero)
pub const Cmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01001,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.209 NEG (vector)
pub const Neg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.309 SQXTUN
pub const Sqxtun = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10010,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.381 UQXTN
pub const Uqxtn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10100,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.88 FCVTXN
pub const Fcvtxn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10110,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.82 FCVTNU (vector)
pub const Fcvtnu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.77 FCVTMU (vector)
pub const Fcvtmu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.72 FCVTAU (vector)
pub const Fcvtau = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.353 UCVTF (vector, integer)
pub const Ucvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.59 FCMGE (zero)
pub const Fcmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.64 FCMLE (zero)
pub const Fcmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.86 FCVTPU (vector)
pub const Fcvtpu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.94 FCVTZU (vector, integer)
pub const Fcvtzu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
/// C7.2.169 FRSQRTE
pub const Frsqrte = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .unsigned,
decoded30: u2 = 0b01,
};
};
/// Advanced SIMD scalar pairwise
pub const SimdScalarPairwise = packed union {
group: @This().Group,
addp: Addp,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness,
decoded30: u2 = 0b01,
};
/// C7.2.4 ADDP (scalar)
pub const Addp = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b11110,
U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
};
/// Advanced SIMD copy
pub const SimdCopy = packed union {
group: @This().Group,
dup: Dup,
smov: Smov,
umov: Umov,
ins: Ins,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: u4,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
op: u1,
Q: u1,
decoded31: u1 = 0b0,
};
/// C7.2.39 DUP (element)
/// C7.2.40 DUP (general)
pub const Dup = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: Imm4,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
op: u1 = 0b0,
Q: Q,
decoded31: u1 = 0b0,
pub const Imm4 = enum(u4) {
element = 0b0000,
general = 0b0001,
_,
};
};
/// C7.2.279 SMOV
pub const Smov = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: u4 = 0b0101,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
op: u1 = 0b0,
Q: Register.IntegerSize,
decoded31: u1 = 0b0,
};
/// C7.2.371 UMOV
pub const Umov = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: u4 = 0b0111,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
op: u1 = 0b0,
Q: Register.IntegerSize,
decoded31: u1 = 0b0,
};
/// C7.2.175 INS (element)
/// C7.2.176 INS (general)
pub const Ins = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
imm4: Imm4,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
op: Op,
Q: u1 = 0b1,
decoded31: u1 = 0b0,
pub const Imm4 = packed union {
general: General,
element: u4,
pub const General = enum(u4) {
general = 0b0011,
_,
};
};
pub const Op = enum(u1) {
general = 0b0,
element = 0b1,
};
};
pub const Decoded = union(enum) {
unallocated,
dup: Dup,
smov: Smov,
umov: Umov,
ins: Ins,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op) {
0b0 => switch (inst.group.imm4) {
0b0000, 0b0001 => .{ .dup = inst.dup },
else => .unallocated,
0b0101 => switch (@ctz(inst.group.imm5)) {
0, 1 => .{ .smov = inst.smov },
2 => switch (inst.group.Q) {
0b1 => .{ .smov = inst.smov },
0b0 => .unallocated,
},
else => .unallocated,
},
0b0111 => switch (@ctz(inst.group.imm5)) {
0, 1, 2 => switch (inst.group.Q) {
0b0 => .{ .umov = inst.umov },
0b1 => .unallocated,
},
3 => switch (inst.group.Q) {
0b1 => .{ .umov = inst.umov },
0b0 => .unallocated,
},
else => .unallocated,
},
},
0b1 => switch (inst.group.Q) {
0b0 => .unallocated,
0b1 => .{ .ins = inst.ins },
},
};
}
};
/// Advanced SIMD two-register miscellaneous (FP16)
pub const SimdTwoRegisterMiscellaneousFp16 = packed union {
group: @This().Group,
frintn: Frintn,
frintm: Frintm,
fcvtns: Fcvtns,
fcvtms: Fcvtms,
fcvtas: Fcvtas,
scvtf: Scvtf,
fcmgt: Fcmgt,
fcmeq: Fcmeq,
fcmlt: Fcmlt,
fabs: Fabs,
frintp: Frintp,
frintz: Frintz,
fcvtps: Fcvtps,
fcvtzs: Fcvtzs,
frecpe: Frecpe,
frinta: Frinta,
frintx: Frintx,
fcvtnu: Fcvtnu,
fcvtmu: Fcvtmu,
fcvtau: Fcvtau,
ucvtf: Ucvtf,
fcmge: Fcmge,
fcmle: Fcmle,
fneg: Fneg,
frinti: Frinti,
fcvtpu: Fcvtpu,
fcvtzu: Fcvtzu,
frsqrte: Frsqrte,
fsqrt: Fsqrt,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u6 = 0b111100,
a: u1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.161 FRINTN (vector)
pub const Frintn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.159 FRINTM (vector)
pub const Frintm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.80 FCVTNS (vector)
pub const Fcvtns = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.75 FCVTMS (vector)
pub const Fcvtms = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.70 FCVTAS (vector)
pub const Fcvtas = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.234 SCVTF (vector, integer)
pub const Scvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.61 FCMGT (zero)
pub const Fcmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.57 FCMEQ (zero)
pub const Fcmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.65 FCMLT (zero)
pub const Fcmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01110,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.45 FABS (vector)
pub const Fabs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01111,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.163 FRINTP (vector)
pub const Frintp = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.167 FRINTZ (vector)
pub const Frintz = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.84 FCVTPS (vector)
pub const Fcvtps = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.90 FCVTZS (vector, integer)
pub const Fcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.144 FRECPE
pub const Frecpe = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.155 FRINTA (vector)
pub const Frinta = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.159 FRINTX (vector)
pub const Frintx = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.82 FCVTNU (vector)
pub const Fcvtnu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.77 FCVTMU (vector)
pub const Fcvtmu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.72 FCVTAU (vector)
pub const Fcvtau = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.353 UCVTF (vector, integer)
pub const Ucvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.59 FCMGE (zero)
pub const Fcmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.64 FCMLE (zero)
pub const Fcmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.139 FNEG (vector)
pub const Fneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01111,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.157 FRINTI (vector)
pub const Frinti = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.86 FCVTPU (vector)
pub const Fcvtpu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.94 FCVTZU (vector, integer)
pub const Fcvtzu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.169 FRSQRTE
pub const Frsqrte = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.171 FSQRT
pub const Fsqrt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11111,
decoded17: u6 = 0b111100,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
};
/// Advanced SIMD two-register miscellaneous
pub const SimdTwoRegisterMiscellaneous = packed union {
group: @This().Group,
suqadd: Suqadd,
cnt: Cnt,
sqabs: Sqabs,
cmgt: Cmgt,
cmeq: Cmeq,
cmlt: Cmlt,
abs: Abs,
sqxtn: Sqxtn,
frintn: Frintn,
frintm: Frintm,
fcvtns: Fcvtns,
fcvtms: Fcvtms,
fcvtas: Fcvtas,
scvtf: Scvtf,
fcmgt: Fcmgt,
fcmeq: Fcmeq,
fcmlt: Fcmlt,
fabs: Fabs,
frintp: Frintp,
frintz: Frintz,
fcvtps: Fcvtps,
fcvtzs: Fcvtzs,
frecpe: Frecpe,
usqadd: Usqadd,
sqneg: Sqneg,
cmge: Cmge,
cmle: Cmle,
neg: Neg,
sqxtun: Sqxtun,
uqxtn: Uqxtn,
fcvtxn: Fcvtxn,
frinta: Frinta,
frintx: Frintx,
fcvtnu: Fcvtnu,
fcvtmu: Fcvtmu,
fcvtau: Fcvtau,
ucvtf: Ucvtf,
not: Not,
fcmge: Fcmge,
fcmle: Fcmle,
fneg: Fneg,
frinti: Frinti,
fcvtpu: Fcvtpu,
fcvtzu: Fcvtzu,
frsqrte: Frsqrte,
fsqrt: Fsqrt,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.337 SUQADD
pub const Suqadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.38 CNT
pub const Cnt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00101,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.282 SQABS
pub const Sqabs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00111,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.32 CMGT (zero)
pub const Cmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01000,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.28 CMEQ (zero)
pub const Cmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01001,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.36 CMLT (zero)
pub const Cmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01010,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.1 ABS
pub const Abs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.308 SQXTN
pub const Sqxtn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10100,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.161 FRINTN (vector)
pub const Frintn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.159 FRINTM (vector)
pub const Frintm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.80 FCVTNS (vector)
pub const Fcvtns = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.75 FCVTMS (vector)
pub const Fcvtms = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.70 FCVTAS (vector)
pub const Fcvtas = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.234 SCVTF (vector, integer)
pub const Scvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.61 FCMGT (zero)
pub const Fcmgt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.57 FCMEQ (zero)
pub const Fcmeq = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.65 FCMLT (zero)
pub const Fcmlt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01110,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.45 FABS (vector)
pub const Fabs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01111,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.163 FRINTP (vector)
pub const Frintp = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.167 FRINTZ (vector)
pub const Frintz = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.84 FCVTPS (vector)
pub const Fcvtps = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.90 FCVTZS (vector, integer)
pub const Fcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.144 FRECPE
pub const Frecpe = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.394 USQADD
pub const Usqadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.292 SQNEG
pub const Sqneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00111,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.30 CMGE (zero)
pub const Cmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01000,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.35 CMLE (zero)
pub const Cmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01001,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.209 NEG (vector)
pub const Neg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01011,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.309 SQXTUN
pub const Sqxtun = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10010,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.381 UQXTN
pub const Uqxtn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10100,
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.88 FCVTXN
pub const Fcvtxn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b10110,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.155 FRINTA (vector)
pub const Frinta = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11000,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.165 FRINTX (vector)
pub const Frintx = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.82 FCVTNU (vector)
pub const Fcvtnu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.77 FCVTMU (vector)
pub const Fcvtmu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.72 FCVTAU (vector)
pub const Fcvtau = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.353 UCVTF (vector, integer)
pub const Ucvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b0,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.210 NOT
pub const Not = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b00101,
decoded17: u5 = 0b10000,
size: Size = .byte,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.59 FCMGE (zero)
pub const Fcmge = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01100,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.64 FCMLE (zero)
pub const Fcmle = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.139 FNEG (vector)
pub const Fneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b01111,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.157 FRINTI (vector)
pub const Frinti = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11001,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.86 FCVTPU (vector)
pub const Fcvtpu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11010,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.94 FCVTZU (vector, integer)
pub const Fcvtzu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.169 FRSQRTE
pub const Frsqrte = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11101,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.171 FSQRT (vector)
pub const Fsqrt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11111,
decoded17: u5 = 0b10000,
sz: Sz,
o2: u1 = 0b1,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
};
/// Advanced SIMD across lanes
pub const SimdAcrossLanes = packed union {
group: @This().Group,
addv: Addv,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5,
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.6 ADDV
pub const Addv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: u5 = 0b11011,
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
};
/// Advanced SIMD three same
pub const SimdThreeSame = packed union {
group: @This().Group,
addp: Addp,
@"and": And,
bic: Bic,
orr: Orr,
orn: Orn,
eor: Eor,
bsl: Bsl,
bit: Bit,
bif: Bif,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.5 ADDP (vector)
pub const Addp = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b10111,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.11 AND (vector)
pub const And = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .byte,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.21 BIC (vector, register)
pub const Bic = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .half,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.213 ORR (vector, register)
pub const Orr = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .single,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.211 ORN (vector)
pub const Orn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .double,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.41 EOR (vector)
pub const Eor = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .byte,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.24 BSL
pub const Bsl = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .half,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.23 BIT
pub const Bit = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .single,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.22 BIF
pub const Bif = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
opcode: u5 = 0b00011,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
size: Size = .double,
decoded24: u5 = 0b01110,
U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
};
/// Advanced SIMD modified immediate
pub const SimdModifiedImmediate = packed union {
group: @This().Group,
movi: Movi,
orr: Orr,
fmov: Fmov,
mvni: Mvni,
bic: Bic,
pub const Group = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1,
cmode: u4,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.204 MOVI
pub const Movi = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1 = 0b0,
cmode: u4,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.212 ORR (vector, immediate)
pub const Orr = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1 = 0b0,
cmode0: u1 = 0b1,
cmode: u3,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1 = 0b0,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.129 FMOV (vector, immediate)
pub const Fmov = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1 = 0b1,
cmode: u4 = 0b1111,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1 = 0b0,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.208 MVNI
pub const Mvni = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1 = 0b0,
cmode: u4,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1 = 0b1,
Q: Q,
decoded31: u1 = 0b0,
};
/// C7.2.20 BIC (vector, immediate)
pub const Bic = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u1 = 0b1,
o2: u1 = 0b0,
cmode0: u1 = 0b1,
cmode: u3,
imm3: u3,
decoded19: u10 = 0b0111100000,
op: u1 = 0b1,
Q: Q,
decoded31: u1 = 0b0,
};
};
/// Conversion between floating-point and integer
pub const ConvertFloatInteger = packed union {
group: @This().Group,
fcvtns: Fcvtns,
fcvtnu: Fcvtnu,
scvtf: Scvtf,
ucvtf: Ucvtf,
fcvtas: Fcvtas,
fcvtau: Fcvtau,
fmov: Fmov,
fcvtps: Fcvtps,
fcvtpu: Fcvtpu,
fcvtms: Fcvtms,
fcvtmu: Fcvtmu,
fcvtzs: Fcvtzs,
fcvtzu: Fcvtzu,
fjcvtzs: Fjcvtzs,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3,
rmode: u2,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.81 FCVTNS (scalar)
pub const Fcvtns = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b000,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.83 FCVTNU (scalar)
pub const Fcvtnu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b001,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.236 SCVTF (scalar, integer)
pub const Scvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b010,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.355 UCVTF (scalar, integer)
pub const Ucvtf = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b011,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.71 FCVTAS (scalar)
pub const Fcvtas = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b100,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.73 FCVTAU (scalar)
pub const Fcvtau = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b101,
rmode: Rmode = .n,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.131 FMOV (general)
pub const Fmov = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: Opcode,
rmode: Fmov.Rmode,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
pub const Opcode = enum(u3) {
float_to_integer = 0b110,
integer_to_float = 0b111,
_,
};
pub const Rmode = enum(u2) {
@"0" = 0b00,
@"1" = 0b01,
_,
};
};
/// C7.2.85 FCVTPS (scalar)
pub const Fcvtps = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b000,
rmode: Rmode = .p,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.87 FCVTPU (scalar)
pub const Fcvtpu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b001,
rmode: Rmode = .p,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.76 FCVTMS (scalar)
pub const Fcvtms = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b000,
rmode: Rmode = .m,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.78 FCVTMU (scalar)
pub const Fcvtmu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b001,
rmode: Rmode = .m,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.92 FCVTZS (scalar, integer)
pub const Fcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b000,
rmode: Rmode = .z,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.96 FCVTZU (scalar, integer)
pub const Fcvtzu = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b001,
rmode: Rmode = .z,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize,
};
/// C7.2.99 FJCVTZS
pub const Fjcvtzs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u6 = 0b000000,
opcode: u3 = 0b110,
rmode: Rmode = .z,
decoded21: u1 = 0b1,
ftype: Ftype = .double,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
sf: Register.IntegerSize = .word,
};
pub const Rmode = enum(u2) {
/// to nearest
n = 0b00,
/// toward plus infinity
p = 0b01,
/// toward minus infinity
m = 0b10,
/// toward zero
z = 0b11,
};
};
/// Floating-point data-processing (1 source)
pub const FloatDataProcessingOneSource = packed union {
group: @This().Group,
fmov: Fmov,
fabs: Fabs,
fneg: Fneg,
fsqrt: Fsqrt,
fcvt: Fcvt,
frintn: Frintn,
frintp: Frintp,
frintm: Frintm,
frintz: Frintz,
frinta: Frinta,
frintx: Frintx,
frinti: Frinti,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opcode: u6,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.130 FMOV (register)
pub const Fmov = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opc: u2 = 0b00,
decoded17: u4 = 0b0000,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.46 FABS (scalar)
pub const Fabs = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opc: u2 = 0b01,
decoded17: u4 = 0b0000,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.140 FNEG (scalar)
pub const Fneg = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opc: u2 = 0b10,
decoded17: u4 = 0b0000,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.172 FSQRT (scalar)
pub const Fsqrt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opc: u2 = 0b11,
decoded17: u4 = 0b0000,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.69 FCVT
pub const Fcvt = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
opc: Ftype,
decoded17: u4 = 0b0001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.162 FRINTN (scalar)
pub const Frintn = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .n,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.164 FRINTP (scalar)
pub const Frintp = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .p,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.160 FRINTM (scalar)
pub const Frintm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .m,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.168 FRINTZ (scalar)
pub const Frintz = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .z,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.156 FRINTA (scalar)
pub const Frinta = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .a,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.166 FRINTX (scalar)
pub const Frintx = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .x,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.158 FRINTI (scalar)
pub const Frinti = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u5 = 0b10000,
rmode: Rmode = .i,
decoded18: u3 = 0b001,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
pub const Rmode = enum(u3) {
/// to nearest with ties to even
n = 0b000,
/// toward plus infinity
p = 0b001,
/// toward minus infinity
m = 0b010,
/// toward zero
z = 0b011,
/// to nearest with ties to away
a = 0b100,
/// exact, using current rounding mode
x = 0b110,
/// using current rounding mode
i = 0b111,
_,
};
};
/// Floating-point compare
pub const FloatCompare = packed union {
group: @This().Group,
fcmp: Fcmp,
fcmpe: Fcmpe,
pub const Group = packed struct {
opcode2: u5,
Rn: Register.Encoded,
decoded10: u4 = 0b1000,
op: u2,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.66 FCMP
pub const Fcmp = packed struct {
decoded0: u3 = 0b000,
opc0: Opc0,
opc1: u1 = 0b0,
Rn: Register.Encoded,
decoded10: u4 = 0b1000,
op: u2 = 0b00,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.67 FCMPE
pub const Fcmpe = packed struct {
decoded0: u3 = 0b000,
opc0: Opc0,
opc1: u1 = 0b1,
Rn: Register.Encoded,
decoded10: u4 = 0b1000,
op: u2 = 0b00,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
pub const Opc0 = enum(u1) {
register = 0b00,
zero = 0b01,
};
};
/// Floating-point immediate
pub const FloatImmediate = packed union {
group: @This().Group,
fmov: Fmov,
pub const Group = packed struct {
Rd: Register.Encoded,
imm5: u5,
decoded10: u3 = 0b100,
imm8: u8,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.132 FMOV (scalar, immediate)
pub const Fmov = packed struct {
Rd: Register.Encoded,
imm5: u5 = 0b00000,
decoded10: u3 = 0b100,
imm8: u8,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
};
/// Floating-point data-processing (2 source)
pub const FloatDataProcessingTwoSource = packed union {
group: @This().Group,
fmul: Fmul,
fdiv: Fdiv,
fadd: Fadd,
fsub: Fsub,
fmax: Fmax,
fmin: Fmin,
fmaxnm: Fmaxnm,
fminnm: Fminnm,
fnmul: Fnmul,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.136 FMUL (scalar)
pub const Fmul = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fmul,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.98 FDIV (scalar)
pub const Fdiv = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fdiv,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.50 FADD (scalar)
pub const Fadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fadd,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.174 FSUB (scalar)
pub const Fsub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fsub,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.102 FMAX (scalar)
pub const Fmax = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fmax,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.112 FMIN (scalar)
pub const Fmin = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fmin,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.104 FMAXNM (scalar)
pub const Fmaxnm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fmaxnm,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.114 FMINNM (scalar)
pub const Fminnm = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fminnm,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.143 FNMUL (scalar)
pub const Fnmul = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b10,
opcode: Opcode = .fnmul,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
pub const Opcode = enum(u4) {
fmul = 0b0000,
fdiv = 0b0001,
fadd = 0b0010,
fsub = 0b0011,
fmax = 0b0100,
fmin = 0b0101,
fmaxnm = 0b0110,
fminnm = 0b0111,
fnmul = 0b1000,
_,
};
};
/// Floating-point conditional select
pub const FloatConditionalSelect = packed union {
group: @This().Group,
fcsel: Fcsel,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ptype: Ftype,
decoded24: u5 = 0b11110,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.68 FCSEL
pub const Fcsel = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u2 = 0b11,
cond: ConditionCode,
Rm: Register.Encoded,
decoded21: u1 = 0b1,
ftype: Ftype,
decoded24: u5 = 0b11110,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
pub const Decoded = union(enum) {
unallocated,
fcsel: Fcsel,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.ptype) {
.quad => .unallocated,
.single, .double, .half => switch (inst.group.S) {
true => .unallocated,
false => switch (inst.group.M) {
0b0 => .{ .fcsel = inst.fcsel },
0b1 => .unallocated,
},
},
};
}
};
/// Floating-point data-processing (3 source)
pub const FloatDataProcessingThreeSource = packed union {
group: @This().Group,
fmadd: Fmadd,
fmsub: Fmsub,
fnmadd: Fnmadd,
fnmsub: Fnmsub,
pub const Group = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp,
Rm: Register.Encoded,
o1: u1,
ptype: Ftype,
decoded24: u5 = 0b11111,
S: bool,
decoded30: u1 = 0b0,
M: u1,
};
/// C7.2.100 FMADD
pub const Fmadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
o1: O1 = .fm,
ftype: Ftype,
decoded24: u5 = 0b11111,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.133 FMSUB
pub const Fmsub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
o1: O1 = .fm,
ftype: Ftype,
decoded24: u5 = 0b11111,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.141 FNMADD
pub const Fnmadd = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
o1: O1 = .fnm,
ftype: Ftype,
decoded24: u5 = 0b11111,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
/// C7.2.142 FNMSUB
pub const Fnmsub = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
Ra: Register.Encoded,
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
o1: O1 = .fnm,
ftype: Ftype,
decoded24: u5 = 0b11111,
S: bool = false,
decoded30: u1 = 0b0,
M: u1 = 0b0,
};
pub const O1 = enum(u1) {
fm = 0b0,
fnm = 0b1,
};
};
pub const Size = enum(u2) {
byte = 0b00,
half = 0b01,
single = 0b10,
double = 0b11,
pub fn toVectorSize(s: Size) Register.VectorSize {
return switch (s) {
.byte => .byte,
.half => .half,
.single => .single,
.double => .double,
};
}
pub fn fromVectorSize(vs: Register.VectorSize) Size {
return switch (vs) {
else => unreachable,
.byte => .byte,
.half => .half,
.single => .single,
.double => .double,
};
}
};
pub const Sz = enum(u1) {
single = 0b0,
double = 0b1,
pub fn toVectorSize(sz: Sz) Register.VectorSize {
return switch (sz) {
.single => .single,
.double => .double,
};
}
pub fn fromVectorSize(vs: Register.VectorSize) Sz {
return switch (vs) {
else => unreachable,
.single => .single,
.double => .double,
};
}
};
pub const Q = enum(u1) {
double = 0b0,
quad = 0b1,
};
pub const Ftype = enum(u2) {
single = 0b00,
double = 0b01,
quad = 0b10,
half = 0b11,
pub fn toVectorSize(ftype: Ftype) Register.VectorSize {
return switch (ftype) {
_ => unreachable,
.single => .single,
.double => .double,
.half => .half,
};
}
pub fn fromVectorSize(vs: Register.VectorSize) Ftype {
return switch (vs) {
else => unreachable,
.single => .single,
.double => .double,
.half => .half,
};
}
};
};
pub const AddSubtractOp = enum(u1) {
add = 0b0,
sub = 0b1,
};
pub const LogicalOpc = enum(u2) {
@"and" = 0b00,
orr = 0b01,
eor = 0b10,
ands = 0b11,
};
pub const Decoded = union(enum) {
unallocated,
reserved: Reserved,
sme: Sme,
sve: Sve,
data_processing_immediate: DataProcessingImmediate,
branch_exception_generating_system: BranchExceptionGeneratingSystem,
load_store: LoadStore,
data_processing_register: DataProcessingRegister,
data_processing_vector: DataProcessingVector,
};
pub fn decode(inst: @This()) @This().Decoded {
return switch (inst.group.op1) {
0b0000 => switch (inst.group.op0) {
0b0 => .{ .reserved = inst.reserved },
0b1 => .{ .sme = inst.sme },
},
0b0001 => .unallocated,
0b0010 => .{ .sve = inst.sve },
0b0011 => .unallocated,
0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate },
0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system },
0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store },
0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register },
0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector },
};
}
/// C7.2.1 ABS (zero)
pub fn abs(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.abs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.abs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.1 ADC
pub fn adc(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
.adc = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.2 ADCS
pub fn adcs(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
.adcs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.3 ADD (extended register)
/// C6.2.4 ADD (immediate)
/// C6.2.5 ADD (shifted register)
pub fn add(d: Register, n: Register, form: union(enum) {
extended_register_explicit: struct {
register: Register,
option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
},
extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
immediate: u12,
shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.add = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm3 = switch (extended_register_explicit.amount) {
0...4 => |amount| amount,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.register.alias.encode(.{}),
.sf = sf,
},
} } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.register = extended_register.register,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
},
} },
.immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
.shifted_immediate => |shifted_immediate| {
return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
.add = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm12 = shifted_immediate.immediate,
.sh = shifted_immediate.lsl,
.sf = sf,
},
} } };
},
.register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
.{ .extended_register = .{ .register = register, .extend = switch (sf) {
.word => .{ .uxtw = 0 },
.doubleword => .{ .uxtx = 0 },
} } }
else
.{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
.add = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = switch (shifted_register_explicit.shift) {
.lsl, .lsr, .asr => |shift| shift,
.ror => unreachable,
},
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr => |amount| amount,
.ror => unreachable,
},
} },
}
}
/// C7.2.4 ADDP (scalar)
/// C7.2.5 ADDP (vector)
pub fn addp(d: Register, n: Register, form: union(enum) {
scalar,
vector: Register,
}) Instruction {
switch (form) {
.scalar => {
assert(d.format.scalar == .double and n.format.vector == .@"2d");
return .{ .data_processing_vector = .{ .simd_scalar_pairwise = .{
.addp = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .double,
},
} } };
},
.vector => |m| {
const arrangement = d.format.vector;
assert(arrangement != .@"1d" and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.addp = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.7 ADDS (extended register)
/// C6.2.8 ADDS (immediate)
/// C6.2.9 ADDS (shifted register)
pub fn adds(d: Register, n: Register, form: union(enum) {
extended_register_explicit: struct {
register: Register,
option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
},
extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
immediate: u12,
shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.adds = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm3 = switch (extended_register_explicit.amount) {
0...4 => |amount| amount,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.register.alias.encode(.{}),
.sf = sf,
},
} } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.register = extended_register.register,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
},
} },
.immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
.shifted_immediate => |shifted_immediate| {
return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
.adds = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm12 = shifted_immediate.immediate,
.sh = shifted_immediate.lsl,
.sf = sf,
},
} } };
},
.register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
.{ .extended_register = .{ .register = register, .extend = switch (sf) {
.word => .{ .uxtw = 0 },
.doubleword => .{ .uxtx = 0 },
} } }
else
.{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
.adds = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = switch (shifted_register_explicit.shift) {
.lsl, .lsr, .asr => |shift| shift,
.ror => unreachable,
},
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr => |amount| amount,
.ror => unreachable,
},
} },
}
}
/// C7.2.6 ADDV
pub fn addv(d: Register, n: Register) Instruction {
const arrangement = n.format.vector;
assert(arrangement.len() > 2 and d.format.scalar == arrangement.elemSize().toVectorSize());
return .{ .data_processing_vector = .{ .simd_across_lanes = .{
.addv = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
}
/// C6.2.10 ADR
pub fn adr(d: Register, label: i21) Instruction {
assert(d.format.integer == .doubleword);
return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
.adr = .{
.Rd = d.alias.encode(.{}),
.immhi = @intCast(label >> 2),
.immlo = @truncate(@as(u21, @bitCast(label))),
},
} } };
}
/// C6.2.11 ADRP
pub fn adrp(d: Register, label: i33) Instruction {
assert(d.format.integer == .doubleword);
const imm: i21 = @intCast(@shrExact(label, 12));
return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
.adrp = .{
.Rd = d.alias.encode(.{}),
.immhi = @intCast(imm >> 2),
.immlo = @truncate(@as(u21, @bitCast(imm))),
},
} } };
}
/// C6.2.12 AND (immediate)
/// C6.2.13 AND (shifted register)
/// C7.2.11 AND (vector)
pub fn @"and"(d: Register, n: Register, form: union(enum) {
immediate: DataProcessingImmediate.Bitmask,
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| {
assert(n.format.integer == sf);
form: switch (form) {
.immediate => |bitmask| {
assert(bitmask.validImmediate(sf));
return .{ .data_processing_immediate = .{ .logical_immediate = .{
.@"and" = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
},
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.@"and" = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
},
.vector => |arrangement| {
const m = form.register;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.@"and" = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.14 ANDS (immediate)
/// C6.2.15 ANDS (shifted register)
pub fn ands(d: Register, n: Register, form: union(enum) {
immediate: DataProcessingImmediate.Bitmask,
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.immediate => |bitmask| {
assert(bitmask.validImmediate(sf));
return .{ .data_processing_immediate = .{ .logical_immediate = .{
.ands = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
},
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.ands = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
}
/// C6.2.18 ASRV
pub fn asrv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.asrv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.25 B
pub fn b(label: i28) Instruction {
return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
.b = .{ .imm26 = @intCast(@shrExact(label, 2)) },
} } };
}
/// C6.2.26 B.cond
pub fn @"b."(cond: ConditionCode, label: i21) Instruction {
return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
.b = .{
.cond = cond,
.imm19 = @intCast(@shrExact(label, 2)),
},
} } };
}
/// C6.2.27 BC.cond
pub fn @"bc."(cond: ConditionCode, label: i21) Instruction {
return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
.bc = .{
.cond = cond,
.imm19 = @intCast(@shrExact(label, 2)),
},
} } };
}
/// C6.2.30 BFM
pub fn bfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and bitmask.validBitfield(sf));
return .{ .data_processing_immediate = .{ .bitfield = .{
.bfm = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
}
/// C6.2.32 BIC (shifted register)
/// C7.2.20 BIC (vector, immediate)
/// C7.2.21 BIC (vector, register)
pub fn bic(d: Register, n: Register, form: union(enum) {
shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| {
assert(n.format.integer == sf);
form: switch (form) {
else => unreachable,
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.bic = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
},
.vector => |arrangement| switch (form) {
else => unreachable,
.shifted_immediate => |shifted_immediate| {
assert(n.alias == d.alias and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
.bic = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm5 = @truncate(shifted_immediate.immediate >> 0),
.cmode = switch (arrangement) {
else => unreachable,
.@"4h", .@"8h" => @as(u3, 0b100) |
@as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
.@"2s", .@"4s" => @as(u3, 0b000) |
@as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
},
.imm3 = @intCast(shifted_immediate.immediate >> 5),
.Q = arrangement.size(),
},
} } };
},
.register => |m| {
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.bic = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C6.2.33 BICS (shifted register)
pub fn bics(d: Register, n: Register, form: union(enum) {
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.bics = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
}
/// C7.2.22 BIF
pub fn bif(d: Register, n: Register, m: Register) Instruction {
const arrangement = d.format.vector;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.bif = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
}
/// C7.2.23 BIT
pub fn bit(d: Register, n: Register, m: Register) Instruction {
const arrangement = d.format.vector;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.bit = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
}
/// C7.2.24 BSL
pub fn bsl(d: Register, n: Register, m: Register) Instruction {
const arrangement = d.format.vector;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.bsl = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
}
/// C6.2.34 BL
pub fn bl(label: i28) Instruction {
return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
.bl = .{ .imm26 = @intCast(@shrExact(label, 2)) },
} } };
}
/// C6.2.35 BLR
pub fn blr(n: Register) Instruction {
assert(n.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
.blr = .{ .Rn = n.alias.encode(.{}) },
} } };
}
/// C6.2.37 BR
pub fn br(n: Register) Instruction {
assert(n.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
.br = .{ .Rn = n.alias.encode(.{}) },
} } };
}
/// C6.2.40 BRK
pub fn brk(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.brk = .{ .imm16 = imm },
} } };
}
/// C6.2.46 CBNZ
pub fn cbnz(t: Register, label: i21) Instruction {
return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
.cbnz = .{
.Rt = t.alias.encode(.{}),
.imm19 = @intCast(@shrExact(label, 2)),
.sf = t.format.integer,
},
} } };
}
/// C6.2.47 CBZ
pub fn cbz(t: Register, label: i21) Instruction {
return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
.cbz = .{
.Rt = t.alias.encode(.{}),
.imm19 = @intCast(@shrExact(label, 2)),
.sf = t.format.integer,
},
} } };
}
/// C6.2.48 CCMN (immediate)
/// C6.2.49 CCMN (register)
pub fn ccmn(
n: Register,
form: union(enum) { register: Register, immediate: u5 },
nzcv: DataProcessingRegister.Nzcv,
cond: ConditionCode,
) Instruction {
const sf = n.format.integer;
switch (form) {
.register => |m| {
assert(m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_compare_register = .{
.ccmn = .{
.nzcv = nzcv,
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
},
.immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
.ccmn = .{
.nzcv = nzcv,
.Rn = n.alias.encode(.{}),
.cond = cond,
.imm5 = imm,
.sf = sf,
},
} } },
}
}
/// C6.2.50 CCMP (immediate)
/// C6.2.51 CCMP (register)
pub fn ccmp(
n: Register,
form: union(enum) { register: Register, immediate: u5 },
nzcv: DataProcessingRegister.Nzcv,
cond: ConditionCode,
) Instruction {
const sf = n.format.integer;
switch (form) {
.register => |m| {
assert(m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_compare_register = .{
.ccmp = .{
.nzcv = nzcv,
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
},
.immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
.ccmp = .{
.nzcv = nzcv,
.Rn = n.alias.encode(.{}),
.cond = cond,
.imm5 = imm,
.sf = sf,
},
} } },
}
}
/// C6.2.56 CLREX
pub fn clrex(imm: u4) Instruction {
return .{ .branch_exception_generating_system = .{ .barriers = .{
.clrex = .{
.CRm = imm,
},
} } };
}
/// C6.2.58 CLZ
pub fn clz(d: Register, n: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_one_source = .{
.clz = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C7.2.28 CMEQ (zero)
pub fn cmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.cmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C7.2.30 CMGE (zero)
pub fn cmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.cmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C7.2.32 CMGT (zero)
pub fn cmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.cmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C7.2.35 CMLE (zero)
pub fn cmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.cmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C7.2.36 CMLT (zero)
pub fn cmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.cmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C7.2.38 CNT
pub fn cnt(d: Register, n: Register) Instruction {
const arrangement = d.format.vector;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.cnt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
}
/// C6.2.103 CSEL
pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_select = .{
.csel = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.106 CSINC
pub fn csinc(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_select = .{
.csinc = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.107 CSINV
pub fn csinv(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_select = .{
.csinv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.108 CSNEG
pub fn csneg(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .conditional_select = .{
.csneg = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.cond = cond,
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.110 DCPS1
pub fn dcps1(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.dcps1 = .{ .imm16 = imm },
} } };
}
/// C6.2.111 DCPS2
pub fn dcps2(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.dcps2 = .{ .imm16 = imm },
} } };
}
/// C6.2.112 DCPS3
pub fn dcps3(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.dcps3 = .{ .imm16 = imm },
} } };
}
/// C6.2.116 DSB
pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
return .{ .branch_exception_generating_system = .{ .barriers = .{
.dsb = .{
.CRm = option,
},
} } };
}
/// C7.2.39 DUP (element)
/// C7.2.40 DUP (general)
pub fn dup(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(@intFromEnum(elem_size) <= @intFromEnum(Register.VectorSize.double) and elem_size == n.format.element.size);
return .{ .data_processing_vector = .{ .simd_scalar_copy = .{
.dup = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.imm5 = @shlExact(@as(u5, n.format.element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d");
const elem_size = arrangement.elemSize();
switch (n.format) {
else => unreachable,
.element => |element| {
assert(elem_size.toVectorSize() == element.size);
return .{ .data_processing_vector = .{ .simd_copy = .{
.dup = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.imm4 = .element,
.imm5 = @shlExact(@as(u5, element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
.Q = arrangement.size(),
},
} } };
},
.integer => |sf| {
assert(sf == @as(Register.IntegerSize, switch (elem_size) {
.byte, .half, .single => .word,
.double => .doubleword,
}));
return .{ .data_processing_vector = .{ .simd_copy = .{
.dup = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{}),
.imm4 = .general,
.imm5 = @shlExact(@as(u5, 0b1), @intFromEnum(elem_size)),
.Q = arrangement.size(),
},
} } };
},
}
},
}
}
/// C6.2.118 EON (shifted register)
pub fn eon(d: Register, n: Register, form: union(enum) {
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.eon = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
}
/// C6.2.119 EOR (immediate)
/// C6.2.120 EOR (shifted register)
/// C7.2.41 EOR (vector)
pub fn eor(d: Register, n: Register, form: union(enum) {
immediate: DataProcessingImmediate.Bitmask,
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| {
assert(n.format.integer == sf);
form: switch (form) {
.immediate => |bitmask| {
assert(bitmask.validImmediate(sf));
return .{ .data_processing_immediate = .{ .logical_immediate = .{
.eor = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
},
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.eor = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
},
.vector => |arrangement| {
const m = form.register;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.eor = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.124 EXTR
pub fn extr(d: Register, n: Register, m: Register, lsb: u6) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_immediate = .{ .extract = .{
.extr = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imms = switch (sf) {
.word => @as(u5, @intCast(lsb)),
.doubleword => @as(u6, @intCast(lsb)),
},
.Rm = m.alias.encode(.{}),
.N = sf,
.sf = sf,
},
} } };
}
/// C7.2.45 FABS (vector)
/// C7.2.46 FABS (scalar)
pub fn fabs(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fabs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fabs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.fabs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.50 FADD (scalar)
pub fn fadd(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fadd = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.57 FCMEQ (zero)
pub fn fcmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |n_scalar| {
assert(n_scalar == ftype);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcmeq = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
},
}
}
/// C7.2.59 FCMGE (zero)
pub fn fcmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |n_scalar| {
assert(n_scalar == ftype);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcmge = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
},
}
}
/// C7.2.61 FCMGT (zero)
pub fn fcmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |n_scalar| {
assert(n_scalar == ftype);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcmgt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
},
}
}
/// C7.2.64 FCMLE (zero)
pub fn fcmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |n_scalar| {
assert(n_scalar == ftype);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcmle = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
},
}
}
/// C7.2.65 FCMLT (zero)
pub fn fcmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
switch (form) {
.zero => switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |n_scalar| {
assert(n_scalar == ftype);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcmlt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
},
}
}
/// C7.2.66 FCMP
pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
const ftype = n.format.scalar;
switch (form) {
.register => |m| {
assert(m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_compare = .{
.fcmp = .{
.opc0 = .register,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
.zero => return .{ .data_processing_vector = .{ .float_compare = .{
.fcmp = .{
.opc0 = .register,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = @enumFromInt(0b00000),
.ftype = .fromVectorSize(ftype),
},
} } },
}
}
/// C7.2.67 FCMPE
pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction {
const ftype = n.format.scalar;
switch (form) {
.register => |m| {
assert(m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_compare = .{
.fcmpe = .{
.opc0 = .zero,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
.zero => return .{ .data_processing_vector = .{ .float_compare = .{
.fcmpe = .{
.opc0 = .zero,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = @enumFromInt(0b00000),
.ftype = .fromVectorSize(ftype),
},
} } },
}
}
/// C7.2.68 FCSEL
pub fn fcsel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_conditional_select = .{
.fcsel = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.cond = cond,
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.69 FCVT
pub fn fcvt(d: Register, n: Register) Instruction {
assert(d.format.scalar != n.format.scalar);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.fcvt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.opc = switch (d.format.scalar) {
else => unreachable,
.single => .single,
.double => .double,
.half => .half,
},
.ftype = .fromVectorSize(n.format.scalar),
},
} } };
}
/// C7.2.70 FCVTAS (vector)
/// C7.2.71 FCVTAS (scalar)
pub fn fcvtas(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtas = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtas = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtas = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtas = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtas = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.72 FCVTAU (vector)
/// C7.2.73 FCVTAU (scalar)
pub fn fcvtau(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtau = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtau = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtau = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtau = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtau = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.75 FCVTMS (vector)
/// C7.2.76 FCVTMS (scalar)
pub fn fcvtms(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtms = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtms = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtms = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtms = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtms = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.77 FCVTMU (vector)
/// C7.2.78 FCVTMU (scalar)
pub fn fcvtmu(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtmu = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtmu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtmu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtmu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtmu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.80 FCVTNS (vector)
/// C7.2.81 FCVTNS (scalar)
pub fn fcvtns(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtns = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtns = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtns = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtns = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtns = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.82 FCVTNU (vector)
/// C7.2.83 FCVTNU (scalar)
pub fn fcvtnu(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtnu = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtnu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtnu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtnu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtnu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.84 FCVTPS (vector)
/// C7.2.85 FCVTPS (scalar)
pub fn fcvtps(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtps = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtps = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtps = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtps = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtps = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.86 FCVTPU (vector)
/// C7.2.87 FCVTPU (scalar)
pub fn fcvtpu(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtpu = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtpu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtpu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtpu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtpu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.90 FCVTZS (vector, integer)
/// C7.2.92 FCVTZS (scalar, integer)
pub fn fcvtzs(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtzs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtzs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtzs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtzs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtzs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.94 FCVTZU (vector, integer)
/// C7.2.96 FCVTZU (scalar, integer)
pub fn fcvtzu(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fcvtzu = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(n.format.scalar),
.sf = sf,
},
} } },
.scalar => |elem_size| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
assert(ftype == elem_size);
switch (elem_size) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.fcvtzu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.fcvtzu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(elem_size),
},
} } },
}
},
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fcvtzu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fcvtzu = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C7.2.98 FDIV (scalar)
pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fdiv = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.99 FJCVTZS
pub fn fjcvtzs(d: Register, n: Register) Instruction {
assert(d.format.integer == .word);
assert(n.format.scalar == .double);
return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fjcvtzs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
},
} } };
}
/// C7.2.100 FMADD
pub fn fmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
.fmadd = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.102 FMAX (scalar)
pub fn fmax(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fmax = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.104 FMAXNM (scalar)
pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fmaxnm = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.112 FMIN (scalar)
pub fn fmin(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fmin = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.114 FMINNM (scalar)
pub fn fminnm(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fminnm = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.129 FMOV (vector, immediate)
/// C7.2.130 FMOV (register)
/// C7.2.131 FMOV (general)
/// C7.2.132 FMOV (scalar, immediate)
pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction {
switch (form) {
.immediate => |immediate| {
const repr: std.math.FloatRepr(f16) = @bitCast(immediate);
const imm: u8 = @bitCast(@as(packed struct(u8) {
mantissa: u4,
exponent: i3,
sign: std.math.Sign,
}, .{
.mantissa = @intCast(@shrExact(repr.mantissa, 6)),
.exponent = @intCast(repr.exponent.unbias() - 1),
.sign = repr.sign,
}));
switch (d.format) {
else => unreachable,
.scalar => |ftype| return .{ .data_processing_vector = .{ .float_immediate = .{
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm8 = imm,
.ftype = .fromVectorSize(ftype),
},
} } },
.vector => |arrangement| {
assert(arrangement.len() > 1 and arrangement.elemSize() != .byte);
return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm5 = @truncate(imm >> 0),
.imm3 = @intCast(imm >> 5),
.Q = arrangement.size(),
},
} } };
},
}
},
.register => |n| switch (d.format) {
else => unreachable,
.integer => |sf| switch (n.format) {
else => unreachable,
.scalar => |ftype| {
switch (ftype) {
else => unreachable,
.half => {},
.single => assert(sf == .word),
.double => assert(sf == .doubleword),
}
return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fmov = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.opcode = .float_to_integer,
.rmode = .@"0",
.ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } };
},
.element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fmov = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.opcode = .float_to_integer,
.rmode = switch (element.index) {
else => unreachable,
1 => .@"1",
},
.ftype = switch (element.size) {
else => unreachable,
.double => .quad,
},
.sf = sf,
},
} } },
},
.scalar => |ftype| switch (n.format) {
else => unreachable,
.integer => {
const sf = n.format.integer;
switch (ftype) {
else => unreachable,
.half => {},
.single => assert(sf == .word),
.double => assert(sf == .doubleword),
}
return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{}),
.opcode = .integer_to_float,
.rmode = .@"0",
.ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } };
},
.scalar => {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
},
.element => |element| switch (n.format) {
else => unreachable,
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{}),
.opcode = .integer_to_float,
.rmode = switch (element.index) {
else => unreachable,
1 => .@"1",
},
.ftype = switch (element.size) {
else => unreachable,
.double => .quad,
},
.sf = sf,
},
} } },
},
},
}
}
/// C7.2.133 FMSUB
pub fn fmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
.fmsub = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.136 FMUL (scalar)
pub fn fmul(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fmul = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.139 FNEG (vector)
/// C7.2.140 FNEG (scalar)
pub fn fneg(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fneg = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fneg = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.fneg = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.141 FNMADD
pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
.fnmadd = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.142 FNMSUB
pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
.fnmsub = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.143 FNMUL (scalar)
pub fn fnmul(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fnmul = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C7.2.155 FRINTA (vector)
/// C7.2.156 FRINTA (scalar)
pub fn frinta(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frinta = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frinta = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frinta = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.157 FRINTI (vector)
/// C7.2.158 FRINTI (scalar)
pub fn frinti(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frinti = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frinti = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frinti = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.159 FRINTM (vector)
/// C7.2.160 FRINTM (scalar)
pub fn frintm(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frintm = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frintm = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frintm = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.161 FRINTN (vector)
/// C7.2.162 FRINTN (scalar)
pub fn frintn(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frintn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frintn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frintn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.163 FRINTP (vector)
/// C7.2.164 FRINTP (scalar)
pub fn frintp(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frintp = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frintp = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frintp = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.165 FRINTX (vector)
/// C7.2.166 FRINTX (scalar)
pub fn frintx(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frintx = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frintx = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frintx = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.167 FRINTZ (vector)
/// C7.2.168 FRINTZ (scalar)
pub fn frintz(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.frintz = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.frintz = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.frintz = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.171 FSQRT (vector)
/// C7.2.172 FSQRT (scalar)
pub fn fsqrt(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.vector => |arrangement| {
assert(n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.fsqrt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.fsqrt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
.scalar => |ftype| {
assert(n.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
.fsqrt = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
},
}
}
/// C7.2.174 FSUB (scalar)
pub fn fsub(d: Register, n: Register, m: Register) Instruction {
const ftype = d.format.scalar;
assert(n.format.scalar == ftype and m.format.scalar == ftype);
return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
.fsub = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.ftype = .fromVectorSize(ftype),
},
} } };
}
/// C6.2.126 HINT
pub fn hint(imm: u7) Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.group = .{
.op2 = @truncate(imm >> 0),
.CRm = @intCast(imm >> 3),
},
} } };
}
/// C6.2.127 HLT
pub fn hlt(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.hlt = .{ .imm16 = imm },
} } };
}
/// C6.2.128 HVC
pub fn hvc(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.hvc = .{ .imm16 = imm },
} } };
}
/// C6.2.131 ISB
pub fn isb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
return .{ .branch_exception_generating_system = .{ .barriers = .{
.isb = .{
.CRm = option,
},
} } };
}
/// C6.2.164 LDP
/// C7.2.190 LDP (SIMD&FP)
pub fn ldp(t1: Register, t2: Register, form: union(enum) {
post_index: struct { base: Register, index: i10 },
pre_index: struct { base: Register, index: i10 },
signed_offset: struct { base: Register, offset: i10 = 0 },
base: Register,
}) Instruction {
switch (t1.format) {
else => unreachable,
.integer => |sf| {
assert(t2.format.integer == sf);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
.ldp = .{
.Rt = t1.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
.ldp = .{
.Rt = t1.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.signed_offset => |signed_offset| {
assert(signed_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
.ldp = .{
.Rt = t1.alias.encode(.{}),
.Rn = signed_offset.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
.scalar => |vs| {
assert(t2.format.scalar == vs);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
.ldp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.signed_offset => |signed_offset| {
assert(signed_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
.ldp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = signed_offset.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
.ldp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
}
}
/// C6.2.166 LDR (immediate)
/// C6.2.167 LDR (literal)
/// C6.2.168 LDR (register)
/// C7.2.191 LDR (immediate, SIMD&FP)
/// C7.2.192 LDR (literal, SIMD&FP)
/// C7.2.193 LDR (register, SIMD&FP)
pub fn ldr(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u16 = 0 },
base: Register,
literal: i21,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
switch (t.format) {
else => unreachable,
.integer => |sf| form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.ldr = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.sf = sf,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldr = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.sf = sf,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.ldr = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
.ldr = .{
.Rt = t.alias.encode(.{}),
.imm19 = @intCast(@shrExact(offset, 2)),
.sf = sf,
},
} } } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldr = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (sf) {
.word => switch (extended_register_explicit.amount) {
0 => false,
2 => true,
else => unreachable,
},
.doubleword => switch (extended_register_explicit.amount) {
0 => false,
3 => true,
else => unreachable,
},
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
.sf = sf,
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
},
.scalar => |vs| form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
.ldr = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
.ldr = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
.ldr = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.literal => |offset| return .{ .load_store = .{ .register_literal = .{ .vector = .{
.ldr = .{
.Rt = t.alias.encode(.{ .V = true }),
.imm19 = @intCast(@shrExact(offset, 2)),
.opc = .encode(vs),
},
} } } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .vector = .{
.ldr = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (vs) {
else => unreachable,
.byte => switch (extended_register_explicit.amount) {
0 => false,
else => unreachable,
},
.half => switch (extended_register_explicit.amount) {
0 => false,
1 => true,
else => unreachable,
},
.single => switch (extended_register_explicit.amount) {
0 => false,
2 => true,
else => unreachable,
},
.double => switch (extended_register_explicit.amount) {
0 => false,
3 => true,
else => unreachable,
},
.quad => switch (extended_register_explicit.amount) {
0 => false,
4 => true,
else => unreachable,
},
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
},
}
}
/// C6.2.170 LDRB (immediate)
/// C6.2.171 LDRB (register)
pub fn ldrb(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u12 = 0 },
base: Register,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
assert(t.format.integer == .word);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.ldrb = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldrb = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.ldrb = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = unsigned_offset.offset,
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldrb = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => false,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.172 LDRH (immediate)
/// C6.2.173 LDRH (register)
pub fn ldrh(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u13 = 0 },
base: Register,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
assert(t.format.integer == .word);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.ldrh = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldrh = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.ldrh = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldrh = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => false,
1 => true,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.174 LDRSB (immediate)
/// C6.2.175 LDRSB (register)
pub fn ldrsb(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u12 = 0 },
base: Register,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
const sf = t.format.integer;
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.ldrsb = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldrsb = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.ldrsb = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = unsigned_offset.offset,
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldrsb = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => false,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.176 LDRSH (immediate)
/// C6.2.177 LDRSH (register)
pub fn ldrsh(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u13 = 0 },
base: Register,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
const sf = t.format.integer;
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.ldrsh = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldrsh = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.ldrsh = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldrsh = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => false,
1 => true,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
.opc0 = ~@intFromEnum(sf),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.178 LDRSW (immediate)
/// C6.2.179 LDRSW (literal)
/// C6.2.180 LDRSW (register)
pub fn ldrsw(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u14 = 0 },
base: Register,
literal: i21,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Integer.Option,
amount: LoadStore.RegisterRegisterOffset.Integer.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Integer.Extend,
},
}) Instruction {
assert(t.format.integer == .doubleword);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{
.ldrsw = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
},
} } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.ldrsw = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{
.ldrsw = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, 2)),
},
} } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.literal => |offset| return .{ .load_store = .{ .register_literal = .{
.ldrsw = .{
.Rt = t.alias.encode(.{}),
.imm19 = @intCast(@shrExact(offset, 2)),
},
} } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.ldrsw = .{
.Rt = t.alias.encode(.{}),
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => 0b0,
2 => 0b1,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.202 LDUR
/// C7.2.194 LDUR (SIMD&FP)
pub fn ldur(t: Register, n: Register, simm: i9) Instruction {
assert(n.format.integer == .doubleword);
switch (t.format) {
else => unreachable,
.integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldur = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.sf = sf,
},
} } } },
.scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
.ldur = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } },
}
}
/// C6.2.203 LDURB
pub fn ldurb(t: Register, n: Register, simm: i9) Instruction {
assert(t.format.integer == .word and n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldurb = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
},
} } } };
}
/// C6.2.204 LDURH
pub fn ldurh(t: Register, n: Register, simm: i9) Instruction {
assert(t.format.integer == .word and n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldurh = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
},
} } } };
}
/// C6.2.205 LDURSB
pub fn ldursb(t: Register, n: Register, simm: i9) Instruction {
assert(n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldursb = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.opc0 = ~@intFromEnum(t.format.integer),
},
} } } };
}
/// C6.2.206 LDURSH
pub fn ldursh(t: Register, n: Register, simm: i9) Instruction {
assert(n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldursh = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.opc0 = ~@intFromEnum(t.format.integer),
},
} } } };
}
/// C6.2.207 LDURSW
pub fn ldursw(t: Register, n: Register, simm: i9) Instruction {
assert(t.format.integer == .doubleword and n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.ldursw = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
},
} } } };
}
/// C6.2.214 LSLV
pub fn lslv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.lslv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.217 LSRV
pub fn lsrv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.lsrv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.218 MADD
pub fn madd(d: Register, n: Register, m: Register, a: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.madd = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C7.2.204 MOVI
pub fn movi(d: Register, imm8: u8, shift: union(enum) { lsl: u5, msl: u5, replicate }) Instruction {
const arrangement = switch (d.format) {
else => unreachable,
.scalar => |vs| switch (vs) {
else => unreachable,
.double => .@"1d",
},
.vector => |arrangement| switch (arrangement) {
.@"1d" => unreachable,
else => arrangement,
},
};
return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
.movi = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm5 = @truncate(imm8 >> 0),
.cmode = switch (shift) {
.lsl => |amount| switch (arrangement) {
else => unreachable,
.@"8b", .@"16b" => @as(u4, 0b1110) |
@as(u4, @as(u0, @intCast(@shrExact(amount, 3)))) << 1,
.@"4h", .@"8h" => @as(u4, 0b1000) |
@as(u4, @as(u1, @intCast(@shrExact(amount, 3)))) << 1,
.@"2s", .@"4s" => @as(u4, 0b0000) |
@as(u4, @as(u2, @intCast(@shrExact(amount, 3)))) << 1,
},
.msl => |amount| switch (arrangement) {
else => unreachable,
.@"2s", .@"4s" => @as(u4, 0b1100) |
@as(u4, @as(u1, @intCast(@shrExact(amount, 3) - 1))) << 0,
},
.replicate => switch (arrangement) {
else => unreachable,
.@"1d", .@"2d" => 0b1110,
},
},
.imm3 = @intCast(imm8 >> 5),
.op = switch (shift) {
.lsl, .msl => 0b0,
.replicate => 0b1,
},
.Q = arrangement.size(),
},
} } };
}
/// C6.2.225 MOVK
pub fn movk(
d: Register,
imm: u16,
shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
) Instruction {
const sf = d.format.integer;
assert(sf == .doubleword or shift.lsl.sf() == .word);
return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
.movk = .{
.Rd = d.alias.encode(.{}),
.imm16 = imm,
.hw = shift.lsl,
.sf = sf,
},
} } };
}
/// C6.2.226 MOVN
pub fn movn(
d: Register,
imm: u16,
shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
) Instruction {
const sf = d.format.integer;
assert(sf == .doubleword or shift.lsl.sf() == .word);
return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
.movn = .{
.Rd = d.alias.encode(.{}),
.imm16 = imm,
.hw = shift.lsl,
.sf = sf,
},
} } };
}
/// C6.2.227 MOVZ
pub fn movz(
d: Register,
imm: u16,
shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
) Instruction {
const sf = d.format.integer;
assert(sf == .doubleword or shift.lsl.sf() == .word);
return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
.movz = .{
.Rd = d.alias.encode(.{}),
.imm16 = imm,
.hw = shift.lsl,
.sf = sf,
},
} } };
}
/// C6.2.228 MRS
pub fn mrs(t: Register, systemreg: Register.System) Instruction {
assert(t.format.integer == .doubleword and systemreg.op0 >= 0b10);
return .{ .branch_exception_generating_system = .{ .system_register_move = .{
.mrs = .{
.Rt = t.alias.encode(.{}),
.systemreg = systemreg,
},
} } };
}
/// C6.2.230 MSR (register)
pub fn msr(systemreg: Register.System, t: Register) Instruction {
assert(systemreg.op0 >= 0b10 and t.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .system_register_move = .{
.msr = .{
.Rt = t.alias.encode(.{}),
.systemreg = systemreg,
},
} } };
}
/// C6.2.231 MSUB
pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.msub = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C7.2.209 NEG (vector)
pub fn neg(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == .double and elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.neg = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.neg = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.238 NOP
pub fn nop() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.nop = .{},
} } };
}
/// C7.2.210 NOT
pub fn not(d: Register, n: Register) Instruction {
const arrangement = d.format.vector;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.not = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
}
/// C6.2.239 ORN (shifted register)
/// C7.2.211 ORN (vector)
pub fn orn(d: Register, n: Register, form: union(enum) {
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| {
assert(n.format.integer == sf);
form: switch (form) {
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.orn = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
},
.vector => |arrangement| {
const m = form.register;
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.orn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.240 ORR (immediate)
/// C6.2.241 ORR (shifted register)
/// C7.2.212 ORR (vector, immediate)
/// C7.2.213 ORR (vector, register)
pub fn orr(d: Register, n: Register, form: union(enum) {
immediate: DataProcessingImmediate.Bitmask,
shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
switch (d.format) {
else => unreachable,
.integer => |sf| {
assert(n.format.integer == sf);
form: switch (form) {
.immediate => |bitmask| {
assert(bitmask.validImmediate(sf));
return .{ .data_processing_immediate = .{ .logical_immediate = .{
.orr = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
},
.shifted_immediate => unreachable,
.register => |register| continue :form .{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .logical_shifted_register = .{
.orr = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = shifted_register_explicit.shift,
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr, .ror => |amount| amount,
},
} },
}
},
.vector => |arrangement| switch (form) {
else => unreachable,
.shifted_immediate => |shifted_immediate| {
assert(n.alias == d.alias and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
.orr = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm5 = @truncate(shifted_immediate.immediate >> 0),
.cmode = switch (arrangement) {
else => unreachable,
.@"4h", .@"8h" => @as(u3, 0b100) |
@as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
.@"2s", .@"4s" => @as(u3, 0b000) |
@as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
},
.imm3 = @intCast(shifted_immediate.immediate >> 5),
.Q = arrangement.size(),
},
} } };
},
.register => |m| {
assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_three_same = .{
.orr = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } };
},
},
}
}
/// C6.2.247 PRFM (immediate)
/// C6.2.248 PRFM (literal)
/// C6.2.249 PRFM (register)
pub fn prfm(prfop: LoadStore.PrfOp, form: union(enum) {
unsigned_offset: struct { base: Register, offset: u15 = 0 },
base: Register,
literal: i21,
extended_register_explicit: struct {
base: Register,
index: Register,
option: LoadStore.RegisterRegisterOffset.Option,
amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
},
extended_register: struct {
base: Register,
index: Register,
extend: LoadStore.RegisterRegisterOffset.Extend,
},
}) Instruction {
form: switch (form) {
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.prfm = .{
.prfop = prfop,
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, 3)),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
.literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
.prfm = .{
.prfop = prfop,
.imm19 = @intCast(@shrExact(offset, 2)),
},
} } } },
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.base.format.integer == .doubleword and
extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
.prfm = .{
.prfop = prfop,
.Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
.S = switch (extended_register_explicit.amount) {
0 => false,
3 => true,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.index.alias.encode(.{}),
},
} } } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.base = extended_register.base,
.index = extended_register.index,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
},
} },
}
}
/// C6.2.253 RBIT
pub fn rbit(d: Register, n: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_one_source = .{
.rbit = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.254 RET
pub fn ret(n: Register) Instruction {
assert(n.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
.ret = .{ .Rn = n.alias.encode(.{}) },
} } };
}
/// C6.2.256 REV
pub fn rev(d: Register, n: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_one_source = .{
.rev = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.opc0 = sf,
.sf = sf,
},
} } };
}
/// C6.2.257 REV16
pub fn rev16(d: Register, n: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_one_source = .{
.rev16 = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.258 REV32
pub fn rev32(d: Register, n: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_one_source = .{
.rev32 = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
},
} } };
}
/// C6.2.263 RORV
pub fn rorv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.rorv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.264 SB
pub fn sb() Instruction {
return .{ .branch_exception_generating_system = .{ .barriers = .{
.sb = .{},
} } };
}
/// C6.2.265 SBC
pub fn sbc(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
.sbc = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.266 SBCS
pub fn sbcs(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
.sbcs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.268 SBFM
pub fn sbfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and bitmask.validBitfield(sf));
return .{ .data_processing_immediate = .{ .bitfield = .{
.sbfm = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
}
/// C7.2.234 SCVTF (vector, integer)
/// C7.2.236 SCVTF (scalar, integer)
pub fn scvtf(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |elem_size| {
assert(ftype == elem_size);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.scvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.scvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.scvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{}),
.ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } },
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.scvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.scvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C6.2.270 SDIV
pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.sdiv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.280 SEV
pub fn sev() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.sev = .{},
} } };
}
/// C6.2.281 SEVL
pub fn sevl() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.sevl = .{},
} } };
}
/// C6.2.282 SMADDL
pub fn smaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.smaddl = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C6.2.283 SMC
pub fn smc(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.smc = .{ .imm16 = imm },
} } };
}
/// C7.2.279 SMOV
pub fn smov(d: Register, n: Register) Instruction {
const sf = d.format.integer;
const vs = n.format.element.size;
switch (vs) {
else => unreachable,
.byte, .half => {},
.single => assert(sf == .doubleword),
}
return .{ .data_processing_vector = .{ .simd_copy = .{
.smov = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.imm5 = switch (vs) {
else => unreachable,
.byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
.half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
.single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
},
.Q = sf,
},
} } };
}
/// C6.2.287 SMSUBL
pub fn smsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.smsubl = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C6.2.288 SMULH
pub fn smulh(d: Register, n: Register, m: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.smulh = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C7.2.282 SQABS
pub fn sqabs(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.sqabs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.sqabs = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C7.2.308 SQXTN
pub fn sqxtn(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.sqxtn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.sqxtn = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.321 STP
/// C7.2.330 STP (SIMD&FP)
pub fn stp(t1: Register, t2: Register, form: union(enum) {
post_index: struct { base: Register, index: i10 },
pre_index: struct { base: Register, index: i10 },
signed_offset: struct { base: Register, offset: i10 = 0 },
base: Register,
}) Instruction {
switch (t1.format) {
else => unreachable,
.integer => |sf| {
assert(t2.format.integer == sf);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
.stp = .{
.Rt = t1.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
.stp = .{
.Rt = t1.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.signed_offset => |signed_offset| {
assert(signed_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
.stp = .{
.Rt = t1.alias.encode(.{}),
.Rn = signed_offset.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{}),
.imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
.scalar => |vs| {
assert(t2.format.scalar == vs);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
.stp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.signed_offset => |signed_offset| {
assert(signed_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
.stp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = signed_offset.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
.stp = .{
.Rt = t1.alias.encode(.{ .V = true }),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.Rt2 = t2.alias.encode(.{ .V = true }),
.imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
.opc = .encode(vs),
},
} } } };
},
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
}
}
/// C6.2.322 STR (immediate)
/// C7.2.331 STR (immediate, SIMD&FP)
pub fn str(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u16 = 0 },
base: Register,
}) Instruction {
switch (t.format) {
else => unreachable,
.integer => |sf| form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.str = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.sf = sf,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.str = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.sf = sf,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.str = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
.sf = sf,
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
},
.scalar => |vs| form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
.str = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
.str = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
.str = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
},
}
}
/// C6.2.324 STRB (immediate)
pub fn strb(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u12 = 0 },
base: Register,
}) Instruction {
assert(t.format.integer == .word);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.strb = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.strb = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.strb = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = unsigned_offset.offset,
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
}
}
/// C6.2.326 STRH (immediate)
pub fn strh(t: Register, form: union(enum) {
post_index: struct { base: Register, index: i9 },
pre_index: struct { base: Register, index: i9 },
unsigned_offset: struct { base: Register, offset: u13 = 0 },
base: Register,
}) Instruction {
assert(t.format.integer == .word);
form: switch (form) {
.post_index => |post_index| {
assert(post_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
.strh = .{
.Rt = t.alias.encode(.{}),
.Rn = post_index.base.alias.encode(.{ .sp = true }),
.imm9 = post_index.index,
},
} } } };
},
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
.strh = .{
.Rt = t.alias.encode(.{}),
.Rn = pre_index.base.alias.encode(.{ .sp = true }),
.imm9 = pre_index.index,
},
} } } };
},
.unsigned_offset => |unsigned_offset| {
assert(unsigned_offset.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
.strh = .{
.Rt = t.alias.encode(.{}),
.Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
.imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
},
} } } };
},
.base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
}
}
/// C6.2.346 STUR
/// C7.2.333 STUR (SIMD&FP)
pub fn stur(t: Register, n: Register, simm: i9) Instruction {
assert(n.format.integer == .doubleword);
switch (t.format) {
else => unreachable,
.integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.stur = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.sf = sf,
},
} } } },
.scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
.stur = .{
.Rt = t.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
.opc1 = .encode(vs),
.size = .encode(vs),
},
} } } },
}
}
/// C6.2.347 STURB
pub fn sturb(t: Register, n: Register, simm: i9) Instruction {
assert(t.format.integer == .word and n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.sturb = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
},
} } } };
}
/// C6.2.348 STURH
pub fn sturh(t: Register, n: Register, simm: i9) Instruction {
assert(t.format.integer == .word and n.format.integer == .doubleword);
return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
.sturh = .{
.Rt = t.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm9 = simm,
},
} } } };
}
/// C6.2.356 SUB (extended register)
/// C6.2.357 SUB (immediate)
/// C6.2.358 SUB (shifted register)
pub fn sub(d: Register, n: Register, form: union(enum) {
extended_register_explicit: struct {
register: Register,
option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
},
extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
immediate: u12,
shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.sub = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm3 = switch (extended_register_explicit.amount) {
0...4 => |amount| amount,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.register.alias.encode(.{}),
.sf = sf,
},
} } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.register = extended_register.register,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
},
} },
.immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
.shifted_immediate => |shifted_immediate| {
return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
.sub = .{
.Rd = d.alias.encode(.{ .sp = true }),
.Rn = n.alias.encode(.{ .sp = true }),
.imm12 = shifted_immediate.immediate,
.sh = shifted_immediate.lsl,
.sf = sf,
},
} } };
},
.register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
.{ .extended_register = .{ .register = register, .extend = switch (sf) {
.word => .{ .uxtw = 0 },
.doubleword => .{ .uxtx = 0 },
} } }
else
.{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
.sub = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = switch (shifted_register_explicit.shift) {
.lsl, .lsr, .asr => |shift| shift,
.ror => unreachable,
},
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr => |amount| amount,
.ror => unreachable,
},
} },
}
}
/// C6.2.362 SUBS (extended register)
/// C6.2.363 SUBS (immediate)
/// C6.2.364 SUBS (shifted register)
pub fn subs(d: Register, n: Register, form: union(enum) {
extended_register_explicit: struct {
register: Register,
option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
},
extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
immediate: u12,
shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
register: Register,
shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
}) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.subs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm3 = switch (extended_register_explicit.amount) {
0...4 => |amount| amount,
else => unreachable,
},
.option = extended_register_explicit.option,
.Rm = extended_register_explicit.register.alias.encode(.{}),
.sf = sf,
},
} } };
},
.extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
.register = extended_register.register,
.option = extended_register.extend,
.amount = switch (extended_register.extend) {
.uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
},
} },
.immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
.shifted_immediate => |shifted_immediate| {
return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
.subs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .sp = true }),
.imm12 = shifted_immediate.immediate,
.sh = shifted_immediate.lsl,
.sf = sf,
},
} } };
},
.register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
.{ .extended_register = .{ .register = register, .extend = switch (sf) {
.word => .{ .uxtw = 0 },
.doubleword => .{ .uxtx = 0 },
} } }
else
.{ .shifted_register = .{ .register = register } },
.shifted_register_explicit => |shifted_register_explicit| {
assert(shifted_register_explicit.register.format.integer == sf);
return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
.subs = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm6 = switch (sf) {
.word => @as(u5, @intCast(shifted_register_explicit.amount)),
.doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
},
.Rm = shifted_register_explicit.register.alias.encode(.{}),
.shift = switch (shifted_register_explicit.shift) {
.lsl, .lsr, .asr => |shift| shift,
.ror => unreachable,
},
.sf = sf,
},
} } };
},
.shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
.register = shifted_register.register,
.shift = shifted_register.shift,
.amount = switch (shifted_register.shift) {
.lsl, .lsr, .asr => |amount| amount,
.ror => unreachable,
},
} },
}
}
/// C7.2.337 SUQADD
pub fn suqadd(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |elem_size| {
assert(elem_size == n.format.scalar);
return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.suqadd = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = .fromVectorSize(elem_size),
},
} } };
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.suqadd = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.size = arrangement.elemSize(),
.Q = arrangement.size(),
},
} } };
},
}
}
/// C6.2.365 SVC
pub fn svc(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.svc = .{ .imm16 = imm },
} } };
}
/// C6.2.372 SYS
pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {
assert(t.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .system = .{
.sys = .{
.Rt = t.alias.encode(.{}),
.op2 = op2,
.CRm = m,
.CRn = n,
.op1 = op1,
},
} } };
}
/// C6.2.373 SYSL
pub fn sysl(t: Register, op1: u3, n: u4, m: u4, op2: u3) Instruction {
assert(t.format.integer == .doubleword);
return .{ .branch_exception_generating_system = .{ .system = .{
.sysl = .{
.Rt = t.alias.encode(.{}),
.op2 = op2,
.CRm = m,
.CRn = n,
.op1 = op1,
},
} } };
}
/// C6.2.374 TBNZ
pub fn tbnz(t: Register, imm: u6, label: i16) Instruction {
return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
.tbnz = .{
.Rt = t.alias.encode(.{}),
.imm14 = @intCast(@shrExact(label, 2)),
.b40 = @truncate(switch (t.format.integer) {
.word => @as(u5, @intCast(imm)),
.doubleword => imm,
}),
.b5 = @intCast(imm >> 5),
},
} } };
}
/// C6.2.375 TBZ
pub fn tbz(t: Register, imm: u6, label: i16) Instruction {
return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
.tbz = .{
.Rt = t.alias.encode(.{}),
.imm14 = @intCast(@shrExact(label, 2)),
.b40 = @truncate(switch (t.format.integer) {
.word => @as(u5, @intCast(imm)),
.doubleword => imm,
}),
.b5 = @intCast(imm >> 5),
},
} } };
}
/// C6.2.376 TCANCEL
pub fn tcancel(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
.tcancel = .{ .imm16 = imm },
} } };
}
/// C6.2.385 UBFM
pub fn ubfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and bitmask.validBitfield(sf));
return .{ .data_processing_immediate = .{ .bitfield = .{
.ubfm = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.imm = bitmask,
.sf = sf,
},
} } };
}
/// C7.2.353 UCVTF (vector, integer)
/// C7.2.355 UCVTF (scalar, integer)
pub fn ucvtf(d: Register, n: Register) Instruction {
switch (d.format) {
else => unreachable,
.scalar => |ftype| switch (n.format) {
else => unreachable,
.scalar => |elem_size| {
assert(ftype == elem_size);
switch (ftype) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
.ucvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
.ucvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = .fromVectorSize(ftype),
},
} } },
}
},
.integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
.ucvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{}),
.ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } },
},
.vector => |arrangement| {
assert(arrangement != .@"1d" and n.format.vector == arrangement);
switch (arrangement.elemSize()) {
else => unreachable,
.half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
.ucvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Q = arrangement.size(),
},
} } },
.single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
.ucvtf = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.sz = arrangement.elemSz(),
.Q = arrangement.size(),
},
} } },
}
},
}
}
/// C6.2.387 UDF
pub fn udf(imm: u16) Instruction {
return .{ .reserved = .{
.udf = .{ .imm16 = imm },
} };
}
/// C6.2.388 UDIV
pub fn udiv(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
assert(n.format.integer == sf and m.format.integer == sf);
return .{ .data_processing_register = .{ .data_processing_two_source = .{
.udiv = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
.sf = sf,
},
} } };
}
/// C6.2.389 UMADDL
pub fn umaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.umaddl = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C6.2.391 UMSUBL
pub fn umsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.umsubl = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Ra = a.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C7.2.371 UMOV
pub fn umov(d: Register, n: Register) Instruction {
const sf = d.format.integer;
const vs = n.format.element.size;
switch (vs) {
else => unreachable,
.byte, .half, .single => assert(sf == .word),
.double => assert(sf == .doubleword),
}
return .{ .data_processing_vector = .{ .simd_copy = .{
.umov = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{ .V = true }),
.imm5 = switch (vs) {
else => unreachable,
.byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
.half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
.single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
.double => @as(u5, @as(u1, @intCast(n.format.element.index))) << 4 | @as(u5, 0b1000) << 0,
},
.Q = sf,
},
} } };
}
/// C6.2.392 UMULH
pub fn umulh(d: Register, n: Register, m: Register) Instruction {
assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
return .{ .data_processing_register = .{ .data_processing_three_source = .{
.umulh = .{
.Rd = d.alias.encode(.{}),
.Rn = n.alias.encode(.{}),
.Rm = m.alias.encode(.{}),
},
} } };
}
/// C6.2.396 WFE
pub fn wfe() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.wfe = .{},
} } };
}
/// C6.2.398 WFI
pub fn wfi() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.wfi = .{},
} } };
}
/// C6.2.402 YIELD
pub fn yield() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.yield = .{},
} } };
}
pub const size = @divExact(@bitSizeOf(Backing), 8);
pub const Backing = u32;
pub fn read(mem: *const [size]u8) Instruction {
return @bitCast(std.mem.readInt(Backing, mem, .little));
}
pub fn write(inst: Instruction, mem: *[size]u8) void {
std.mem.writeInt(Backing, mem, @bitCast(inst), .little);
}
pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
const dis: aarch64.Disassemble = .{};
try dis.printInstruction(inst, writer);
}
comptime {
@setEvalBranchQuota(110_000);
verify(@typeName(Instruction), Instruction);
}
fn verify(name: []const u8, Type: type) void {
switch (@typeInfo(Type)) {
.@"union" => |info| {
if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) {
@compileLog(name ++ " should have u32 abi");
}
for (info.fields) |field| verify(name ++ "." ++ field.name, field.type);
},
.@"struct" => |info| {
if (info.layout != .@"packed" or info.backing_integer != Backing) {
@compileLog(name ++ " should have u32 abi");
}
var bit_offset = 0;
for (info.fields) |field| {
if (std.mem.startsWith(u8, field.name, "encoded")) {
if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) {
@compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
}
if (field.default_value_ptr != null) {
@compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
}
} else if (std.mem.startsWith(u8, field.name, "decoded")) {
if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) {
@compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
}
if (field.default_value_ptr == null) {
@compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
}
}
bit_offset += @bitSizeOf(field.type);
}
},
else => @compileError(name ++ " has an unexpected field type"),
}
}
};
const aarch64 = @import("../aarch64.zig");
const assert = std.debug.assert;
const std = @import("std");