aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/aarch64/encoding.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/aarch64/encoding.zig')
-rw-r--r--src/codegen/aarch64/encoding.zig11799
1 files changed, 11799 insertions, 0 deletions
diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig
new file mode 100644
index 0000000000..1aef2f40c2
--- /dev/null
+++ b/src/codegen/aarch64/encoding.zig
@@ -0,0 +1,11799 @@
+/// 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 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 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 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 (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 (std.mem.eql(u8, 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 (std.mem.eql(u8, reg, "wzr"))
+ .wzr
+ else if (std.mem.eql(u8, reg, "wsp"))
+ .wsp
+ else
+ null,
+ 'i' => return if (std.mem.eql(u8, reg, "ip") or std.mem.eql(u8, reg, "ip0"))
+ .ip0
+ else if (std.mem.eql(u8, reg, "ip1"))
+ .ip1
+ else
+ null,
+ 'f' => return if (std.mem.eql(u8, reg, "fp")) .fp else null,
+ 'p' => return if (std.mem.eql(u8, 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 (std.mem.eql(u8, 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 };
+ }
+};
+
+/// 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,
+ op2: u3,
+ CRm: u4,
+ CRn: u4,
+ op1: u3,
+ o0: u1,
+ decoded20: u1 = 0b1,
+ L: L,
+ decoded22: u10 = 0b1101010100,
+ };
+
+ /// C6.2.230 MSR (register)
+ pub const Msr = packed struct {
+ Rt: Register.Encoded,
+ op2: u3,
+ CRm: u4,
+ CRn: u4,
+ op1: u3,
+ o0: u1,
+ decoded20: u1 = 0b1,
+ L: L = .msr,
+ decoded22: u10 = 0b1101010100,
+ };
+
+ /// C6.2.228 MRS
+ pub const Mrs = packed struct {
+ Rt: Register.Encoded,
+ op2: u3,
+ CRm: u4,
+ CRn: u4,
+ op1: u3,
+ o0: u1,
+ decoded20: u1 = 0b1,
+ 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: bool = false,
+ 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: bool = false,
+ 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: bool = false,
+ 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: bool = true,
+ 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: bool = true,
+ 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: bool = true,
+ 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_pairwise: SimdScalarPairwise,
+ simd_copy: SimdCopy,
+ 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_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 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: u1,
+ 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: u1 = 0b0,
+ decoded30: u2 = 0b01,
+ };
+ };
+
+ /// Advanced SIMD copy
+ pub const SimdCopy = packed union {
+ group: @This().Group,
+ smov: Smov,
+ umov: Umov,
+
+ 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: Register.IntegerSize,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.279 SMOV
+ pub const Smov = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ decoded11: u1 = 0b1,
+ decoded12: u1 = 0b0,
+ decoded13: u2 = 0b01,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b01110000,
+ decoded29: 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,
+ decoded11: u1 = 0b1,
+ decoded12: u1 = 0b1,
+ decoded13: u2 = 0b01,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b01110000,
+ decoded29: u1 = 0b0,
+ Q: Register.IntegerSize,
+ decoded31: u1 = 0b0,
+ };
+ };
+
+ /// Advanced SIMD two-register miscellaneous
+ pub const SimdTwoRegisterMiscellaneous = packed union {
+ group: @This().Group,
+ cnt: Cnt,
+
+ 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: u1,
+ 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: u1 = 0b0,
+ 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: u1,
+ 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: u1 = 0b0,
+ 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,
+
+ 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: u1,
+ 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: u1 = 0b0,
+ 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: u1 = 0b0,
+ 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: u1 = 0b0,
+ 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: u1 = 0b0,
+ 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: u1 = 0b0,
+ 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: u1 = 0b1,
+ 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 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 Q = enum(u1) {
+ double = 0b0,
+ quad = 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) {
+ .byte => .byte,
+ .half => .half,
+ .single => .single,
+ .double => .double,
+ };
+ }
+ };
+
+ pub const Ftype = enum(u2) {
+ single = 0b00,
+ double = 0b01,
+ quad = 0b10,
+ half = 0b11,
+ };
+ };
+
+ 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 },
+ };
+ }
+
+ /// 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,
+ },
+ } },
+ }
+ }
+ /// 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.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,
+ },
+ } } };
+ }
+ /// 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.46 FABS (scalar)
+ pub fn fabs(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ },
+ .zero => return .{ .data_processing_vector = .{ .float_compare = .{
+ .fcmp = .{
+ .opc0 = .register,
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Rm = @enumFromInt(0b00000),
+ .ftype = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } },
+ }
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ },
+ .zero => return .{ .data_processing_vector = .{ .float_compare = .{
+ .fcmpe = .{
+ .opc0 = .zero,
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Rm = @enumFromInt(0b00000),
+ .ftype = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } },
+ }
+ }
+ /// 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 = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.71 FCVTAS (scalar)
+ pub fn fcvtas(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.73 FCVTAU (scalar)
+ pub fn fcvtau(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.76 FCVTMS (scalar)
+ pub fn fcvtms(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.78 FCVTMU (scalar)
+ pub fn fcvtmu(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.81 FCVTNS (scalar)
+ pub fn fcvtns(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.83 FCVTNU (scalar)
+ pub fn fcvtnu(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.85 FCVTPS (scalar)
+ pub fn fcvtps(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.87 FCVTPU (scalar)
+ pub fn fcvtpu(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.92 FCVTZS (scalar, integer)
+ pub fn fcvtzs(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// C7.2.96 FCVTZU (scalar, integer)
+ pub fn fcvtzu(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = switch (n.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = d.format.integer,
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } },
+ .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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ },
+ },
+ .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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.140 FNEG (scalar)
+ pub fn fneg(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.156 FRINTA (scalar)
+ pub fn frinta(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.158 FRINTI (scalar)
+ pub fn frinti(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.160 FRINTM (scalar)
+ pub fn frintm(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.162 FRINTN (scalar)
+ pub fn frintn(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.164 FRINTP (scalar)
+ pub fn frintp(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.166 FRINTX (scalar)
+ pub fn frintx(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.168 FRINTZ (scalar)
+ pub fn frintz(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// C7.2.172 FSQRT (scalar)
+ pub fn fsqrt(d: Register, n: Register) Instruction {
+ const ftype = d.format.scalar;
+ 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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 = switch (ftype) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ },
+ } } };
+ }
+ /// 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,
+ },
+ } } } };
+ },
+ .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,
+ },
+ } } } };
+ },
+ .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,
+ },
+ } } } };
+ },
+ .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, op0: u2, op1: u3, n: u4, m: u4, op2: u3) Instruction {
+ assert(t.format.integer == .doubleword);
+ return .{ .branch_exception_generating_system = .{ .system_register_move = .{
+ .mrs = .{
+ .Rt = t.alias.encode(.{}),
+ .op2 = op2,
+ .CRm = m,
+ .CRn = n,
+ .op1 = op1,
+ .o0 = @intCast(op0 - 0b10),
+ },
+ } } };
+ }
+ /// C6.2.230 MSR (register)
+ pub fn msr(op0: u2, op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {
+ assert(t.format.integer == .doubleword);
+ return .{ .branch_exception_generating_system = .{ .system_register_move = .{
+ .msr = .{
+ .Rt = t.alias.encode(.{}),
+ .op2 = op2,
+ .CRm = m,
+ .CRn = n,
+ .op1 = op1,
+ .o0 = @intCast(op0 - 0b10),
+ },
+ } } };
+ }
+ /// 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,
+ },
+ } } };
+ }
+ /// C6.2.238 NOP
+ pub fn nop() Instruction {
+ return .{ .branch_exception_generating_system = .{ .hints = .{
+ .nop = .{},
+ } } };
+ }
+ /// 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.236 SCVTF (scalar, integer)
+ pub fn scvtf(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{}),
+ .ftype = switch (d.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = n.format.integer,
+ },
+ } } };
+ }
+ /// 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(.{}),
+ },
+ } } };
+ }
+ /// 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,
+ },
+ } } } };
+ },
+ .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,
+ },
+ } } } };
+ },
+ .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,
+ },
+ } } } };
+ },
+ .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,
+ },
+ } },
+ }
+ }
+ /// 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.355 UCVTF (scalar, integer)
+ pub fn ucvtf(d: Register, n: Register) Instruction {
+ return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{}),
+ .ftype = switch (d.format.scalar) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ },
+ .sf = n.format.integer,
+ },
+ } } };
+ }
+ /// 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(68_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");