/// B1.2 Registers in AArch64 Execution state pub const Register = struct { alias: Alias, format: Format, pub const Format = union(enum) { alias: Format.Alias, general: GeneralSize, scalar: ScalarSize, vector: Arrangement, element: struct { size: ScalarSize, index: u4 }, scalable, pub const Alias = enum { general, other, vector, predicate }; }; pub const GeneralSize = enum(u1) { word = 0b0, doubleword = 0b1, pub fn prefix(gs: GeneralSize) u8 { return (comptime std.enums.EnumArray(GeneralSize, u8).init(.{ .word = 'w', .doubleword = 'x', })).get(gs); } }; pub const ScalarSize = enum(u3) { byte = 0, half = 1, single = 2, double = 3, quad = 4, pub fn n(ss: ScalarSize) ScalarSize { return @enumFromInt(@intFromEnum(ss) - 1); } pub fn w(ss: ScalarSize) ScalarSize { return @enumFromInt(@intFromEnum(ss) + 1); } pub fn prefix(ss: ScalarSize) u8 { return (comptime std.enums.EnumArray(ScalarSize, u8).init(.{ .byte = 'b', .half = 'h', .single = 's', .double = 'd', .quad = 'q', })).get(ss); } }; pub const Arrangement = enum(u3) { @"2d" = @bitCast(Unwrapped{ .size = .quad, .elem_size = .double }), @"4s" = @bitCast(Unwrapped{ .size = .quad, .elem_size = .single }), @"8h" = @bitCast(Unwrapped{ .size = .quad, .elem_size = .half }), @"16b" = @bitCast(Unwrapped{ .size = .quad, .elem_size = .byte }), @"1d" = @bitCast(Unwrapped{ .size = .double, .elem_size = .double }), @"2s" = @bitCast(Unwrapped{ .size = .double, .elem_size = .single }), @"4h" = @bitCast(Unwrapped{ .size = .double, .elem_size = .half }), @"8b" = @bitCast(Unwrapped{ .size = .double, .elem_size = .byte }), pub const Unwrapped = packed struct { size: Instruction.DataProcessingVector.Q, elem_size: Instruction.DataProcessingVector.Size, }; pub fn wrap(unwrapped: Unwrapped) Arrangement { return @enumFromInt(@as(@typeInfo(Arrangement).@"enum".tag_type, @bitCast(unwrapped))); } pub fn unwrap(arrangement: Arrangement) Unwrapped { return @bitCast(@intFromEnum(arrangement)); } 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 arrangement.unwrap().size; } pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size { return arrangement.unwrap().elem_size; } pub fn elemSz(arrangement: Arrangement) Instruction.DataProcessingVector.Sz { return arrangement.elemSize().toSz(); } }; pub const x0 = Alias.r0.x(); pub const x1 = Alias.r1.x(); pub const x2 = Alias.r2.x(); pub const x3 = Alias.r3.x(); pub const x4 = Alias.r4.x(); pub const x5 = Alias.r5.x(); pub const x6 = Alias.r6.x(); pub const x7 = Alias.r7.x(); pub const x8 = Alias.r8.x(); pub const x9 = Alias.r9.x(); pub const x10 = Alias.r10.x(); pub const x11 = Alias.r11.x(); pub const x12 = Alias.r12.x(); pub const x13 = Alias.r13.x(); pub const x14 = Alias.r14.x(); pub const x15 = Alias.r15.x(); pub const x16 = Alias.r16.x(); pub const x17 = Alias.r17.x(); pub const x18 = Alias.r18.x(); pub const x19 = Alias.r19.x(); pub const x20 = Alias.r20.x(); pub const x21 = Alias.r21.x(); pub const x22 = Alias.r22.x(); pub const x23 = Alias.r23.x(); pub const x24 = Alias.r24.x(); pub const x25 = Alias.r25.x(); pub const x26 = Alias.r26.x(); pub const x27 = Alias.r27.x(); pub const x28 = Alias.r28.x(); pub const x29 = Alias.r29.x(); pub const x30 = Alias.r30.x(); pub const xzr = Alias.zr.x(); pub const sp = Alias.sp.x(); pub const w0 = Alias.r0.w(); pub const w1 = Alias.r1.w(); pub const w2 = Alias.r2.w(); pub const w3 = Alias.r3.w(); pub const w4 = Alias.r4.w(); pub const w5 = Alias.r5.w(); pub const w6 = Alias.r6.w(); pub const w7 = Alias.r7.w(); pub const w8 = Alias.r8.w(); pub const w9 = Alias.r9.w(); pub const w10 = Alias.r10.w(); pub const w11 = Alias.r11.w(); pub const w12 = Alias.r12.w(); pub const w13 = Alias.r13.w(); pub const w14 = Alias.r14.w(); pub const w15 = Alias.r15.w(); pub const w16 = Alias.r16.w(); pub const w17 = Alias.r17.w(); pub const w18 = Alias.r18.w(); pub const w19 = Alias.r19.w(); pub const w20 = Alias.r20.w(); pub const w21 = Alias.r21.w(); pub const w22 = Alias.r22.w(); pub const w23 = Alias.r23.w(); pub const w24 = Alias.r24.w(); pub const w25 = Alias.r25.w(); pub const w26 = Alias.r26.w(); pub const w27 = Alias.r27.w(); pub const w28 = Alias.r28.w(); pub const w29 = Alias.r29.w(); pub const w30 = Alias.r30.w(); pub const wzr = Alias.zr.w(); pub const wsp = Alias.sp.w(); pub const ip = x16; pub const ip0 = x16; pub const ip1 = x17; pub const fp = x29; pub const lr = x30; pub const pc = Alias.pc.alias(.other); pub const q0 = Alias.v0.q(); pub const q1 = Alias.v1.q(); pub const q2 = Alias.v2.q(); pub const q3 = Alias.v3.q(); pub const q4 = Alias.v4.q(); pub const q5 = Alias.v5.q(); pub const q6 = Alias.v6.q(); pub const q7 = Alias.v7.q(); pub const q8 = Alias.v8.q(); pub const q9 = Alias.v9.q(); pub const q10 = Alias.v10.q(); pub const q11 = Alias.v11.q(); pub const q12 = Alias.v12.q(); pub const q13 = Alias.v13.q(); pub const q14 = Alias.v14.q(); pub const q15 = Alias.v15.q(); pub const q16 = Alias.v16.q(); pub const q17 = Alias.v17.q(); pub const q18 = Alias.v18.q(); pub const q19 = Alias.v19.q(); pub const q20 = Alias.v20.q(); pub const q21 = Alias.v21.q(); pub const q22 = Alias.v22.q(); pub const q23 = Alias.v23.q(); pub const q24 = Alias.v24.q(); pub const q25 = Alias.v25.q(); pub const q26 = Alias.v26.q(); pub const q27 = Alias.v27.q(); pub const q28 = Alias.v28.q(); pub const q29 = Alias.v29.q(); pub const q30 = Alias.v30.q(); pub const q31 = Alias.v31.q(); pub const d0 = Alias.v0.d(); pub const d1 = Alias.v1.d(); pub const d2 = Alias.v2.d(); pub const d3 = Alias.v3.d(); pub const d4 = Alias.v4.d(); pub const d5 = Alias.v5.d(); pub const d6 = Alias.v6.d(); pub const d7 = Alias.v7.d(); pub const d8 = Alias.v8.d(); pub const d9 = Alias.v9.d(); pub const d10 = Alias.v10.d(); pub const d11 = Alias.v11.d(); pub const d12 = Alias.v12.d(); pub const d13 = Alias.v13.d(); pub const d14 = Alias.v14.d(); pub const d15 = Alias.v15.d(); pub const d16 = Alias.v16.d(); pub const d17 = Alias.v17.d(); pub const d18 = Alias.v18.d(); pub const d19 = Alias.v19.d(); pub const d20 = Alias.v20.d(); pub const d21 = Alias.v21.d(); pub const d22 = Alias.v22.d(); pub const d23 = Alias.v23.d(); pub const d24 = Alias.v24.d(); pub const d25 = Alias.v25.d(); pub const d26 = Alias.v26.d(); pub const d27 = Alias.v27.d(); pub const d28 = Alias.v28.d(); pub const d29 = Alias.v29.d(); pub const d30 = Alias.v30.d(); pub const d31 = Alias.v31.d(); pub const s0 = Alias.v0.s(); pub const s1 = Alias.v1.s(); pub const s2 = Alias.v2.s(); pub const s3 = Alias.v3.s(); pub const s4 = Alias.v4.s(); pub const s5 = Alias.v5.s(); pub const s6 = Alias.v6.s(); pub const s7 = Alias.v7.s(); pub const s8 = Alias.v8.s(); pub const s9 = Alias.v9.s(); pub const s10 = Alias.v10.s(); pub const s11 = Alias.v11.s(); pub const s12 = Alias.v12.s(); pub const s13 = Alias.v13.s(); pub const s14 = Alias.v14.s(); pub const s15 = Alias.v15.s(); pub const s16 = Alias.v16.s(); pub const s17 = Alias.v17.s(); pub const s18 = Alias.v18.s(); pub const s19 = Alias.v19.s(); pub const s20 = Alias.v20.s(); pub const s21 = Alias.v21.s(); pub const s22 = Alias.v22.s(); pub const s23 = Alias.v23.s(); pub const s24 = Alias.v24.s(); pub const s25 = Alias.v25.s(); pub const s26 = Alias.v26.s(); pub const s27 = Alias.v27.s(); pub const s28 = Alias.v28.s(); pub const s29 = Alias.v29.s(); pub const s30 = Alias.v30.s(); pub const s31 = Alias.v31.s(); pub const h0 = Alias.v0.h(); pub const h1 = Alias.v1.h(); pub const h2 = Alias.v2.h(); pub const h3 = Alias.v3.h(); pub const h4 = Alias.v4.h(); pub const h5 = Alias.v5.h(); pub const h6 = Alias.v6.h(); pub const h7 = Alias.v7.h(); pub const h8 = Alias.v8.h(); pub const h9 = Alias.v9.h(); pub const h10 = Alias.v10.h(); pub const h11 = Alias.v11.h(); pub const h12 = Alias.v12.h(); pub const h13 = Alias.v13.h(); pub const h14 = Alias.v14.h(); pub const h15 = Alias.v15.h(); pub const h16 = Alias.v16.h(); pub const h17 = Alias.v17.h(); pub const h18 = Alias.v18.h(); pub const h19 = Alias.v19.h(); pub const h20 = Alias.v20.h(); pub const h21 = Alias.v21.h(); pub const h22 = Alias.v22.h(); pub const h23 = Alias.v23.h(); pub const h24 = Alias.v24.h(); pub const h25 = Alias.v25.h(); pub const h26 = Alias.v26.h(); pub const h27 = Alias.v27.h(); pub const h28 = Alias.v28.h(); pub const h29 = Alias.v29.h(); pub const h30 = Alias.v30.h(); pub const h31 = Alias.v31.h(); pub const b0 = Alias.v0.b(); pub const b1 = Alias.v1.b(); pub const b2 = Alias.v2.b(); pub const b3 = Alias.v3.b(); pub const b4 = Alias.v4.b(); pub const b5 = Alias.v5.b(); pub const b6 = Alias.v6.b(); pub const b7 = Alias.v7.b(); pub const b8 = Alias.v8.b(); pub const b9 = Alias.v9.b(); pub const b10 = Alias.v10.b(); pub const b11 = Alias.v11.b(); pub const b12 = Alias.v12.b(); pub const b13 = Alias.v13.b(); pub const b14 = Alias.v14.b(); pub const b15 = Alias.v15.b(); pub const b16 = Alias.v16.b(); pub const b17 = Alias.v17.b(); pub const b18 = Alias.v18.b(); pub const b19 = Alias.v19.b(); pub const b20 = Alias.v20.b(); pub const b21 = Alias.v21.b(); pub const b22 = Alias.v22.b(); pub const b23 = Alias.v23.b(); pub const b24 = Alias.v24.b(); pub const b25 = Alias.v25.b(); pub const b26 = Alias.v26.b(); pub const b27 = Alias.v27.b(); pub const b28 = Alias.v28.b(); pub const b29 = Alias.v29.b(); pub const b30 = Alias.v30.b(); pub const b31 = Alias.v31.b(); pub const fpcr = Alias.fpcr.alias(.other); pub const fpsr = Alias.fpsr.alias(.other); pub const z0 = Alias.v0.z(); pub const z1 = Alias.v1.z(); pub const z2 = Alias.v2.z(); pub const z3 = Alias.v3.z(); pub const z4 = Alias.v4.z(); pub const z5 = Alias.v5.z(); pub const z6 = Alias.v6.z(); pub const z7 = Alias.v7.z(); pub const z8 = Alias.v8.z(); pub const z9 = Alias.v9.z(); pub const z10 = Alias.v10.z(); pub const z11 = Alias.v11.z(); pub const z12 = Alias.v12.z(); pub const z13 = Alias.v13.z(); pub const z14 = Alias.v14.z(); pub const z15 = Alias.v15.z(); pub const z16 = Alias.v16.z(); pub const z17 = Alias.v17.z(); pub const z18 = Alias.v18.z(); pub const z19 = Alias.v19.z(); pub const z20 = Alias.v20.z(); pub const z21 = Alias.v21.z(); pub const z22 = Alias.v22.z(); pub const z23 = Alias.v23.z(); pub const z24 = Alias.v24.z(); pub const z25 = Alias.v25.z(); pub const z26 = Alias.v26.z(); pub const z27 = Alias.v27.z(); pub const z28 = Alias.v28.z(); pub const z29 = Alias.v29.z(); pub const z30 = Alias.v30.z(); pub const z31 = Alias.v31.z(); pub const p0 = Alias.p0.p(); pub const p1 = Alias.p1.p(); pub const p2 = Alias.p2.p(); pub const p3 = Alias.p3.p(); pub const p4 = Alias.p4.p(); pub const p5 = Alias.p5.p(); pub const p6 = Alias.p6.p(); pub const p7 = Alias.p7.p(); pub const p8 = Alias.p8.p(); pub const p9 = Alias.p9.p(); pub const p10 = Alias.p10.p(); pub const p11 = Alias.p11.p(); pub const p12 = Alias.p12.p(); pub const p13 = Alias.p13.p(); pub const p14 = Alias.p14.p(); pub const p15 = Alias.p15.p(); pub const ffr = Alias.ffr.alias(.other); pub const Encoded = enum(u5) { _, pub fn decode(enc: Encoded, opts: struct { sp: bool = false, V: bool = false }) Alias { return switch (opts.V) { false => @enumFromInt(@intFromEnum(Alias.r0) + @intFromEnum(enc) + @intFromBool(opts.sp and enc == comptime Alias.sp.encode(.{ .sp = true }))), true => @enumFromInt(@intFromEnum(Alias.v0) + @intFromEnum(enc)), }; } }; /// One tag per set of aliasing registers. pub const Alias = enum(u7) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, zr, sp, pc, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, fpcr, fpsr, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, ffr, pub const ip: Alias = .r16; pub const ip0: Alias = .r16; pub const ip1: Alias = .r17; pub const fp: Alias = .r29; pub const lr: Alias = .r30; pub fn alias(ra: Alias, fa: Format.Alias) Register { switch (fa) { .general => assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)), .other => switch (ra) { else => unreachable, .pc, .fpcr, .fpsr, .ffr => {}, }, .vector => assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)), .predicate => assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15)), } return .{ .alias = ra, .format = .{ .alias = fa } }; } pub fn general(ra: Alias, gs: GeneralSize) Register { assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)); return .{ .alias = ra, .format = .{ .general = gs } }; } pub fn scalar(ra: Alias, ss: ScalarSize) Register { assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); return .{ .alias = ra, .format = .{ .scalar = ss } }; } pub fn vector(ra: Alias, arrangement: Arrangement) Register { assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); return .{ .alias = ra, .format = .{ .vector = arrangement } }; } pub fn element(ra: Alias, ss: ScalarSize, index: u4) Register { assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); return .{ .alias = ra, .format = .{ .element = .{ .size = ss, .index = index } } }; } pub fn z(ra: Alias) Register { assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); return .{ .alias = ra, .format = .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 r(ra: Alias) Register { return ra.alias(.general); } pub fn x(ra: Alias) Register { return ra.general(.doubleword); } pub fn w(ra: Alias) Register { return ra.general(.word); } pub fn v(ra: Alias) Register { return ra.alias(.vector); } pub fn q(ra: Alias) Register { return ra.scalar(.quad); } pub fn d(ra: Alias) Register { return ra.scalar(.double); } pub fn s(ra: Alias) Register { return ra.scalar(.single); } pub fn h(ra: Alias) Register { return ra.scalar(.half); } pub fn b(ra: Alias) Register { return ra.scalar(.byte); } pub fn @"2d"(ra: Alias) Register { return ra.vector(.@"2d"); } pub fn @"4s"(ra: Alias) Register { return ra.vector(.@"4s"); } pub fn @"8h"(ra: Alias) Register { return ra.vector(.@"8h"); } pub fn @"16b"(ra: Alias) Register { return ra.vector(.@"16b"); } pub fn @"1d"(ra: Alias) Register { return ra.vector(.@"1d"); } pub fn @"2s"(ra: Alias) Register { return ra.vector(.@"2s"); } pub fn @"4h"(ra: Alias) Register { return ra.vector(.@"4h"); } pub fn @"8b"(ra: Alias) Register { return ra.vector(.@"8b"); } pub fn @"d[]"(ra: Alias, index: u1) Register { return ra.element(.double, index); } pub fn @"s[]"(ra: Alias, index: u2) Register { return ra.element(.single, index); } pub fn @"h[]"(ra: Alias, index: u3) Register { return ra.element(.half, index); } pub fn @"b[]"(ra: Alias, index: u4) Register { return ra.element(.byte, 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, .general => |sf| switch (sf) { .word => 4, .doubleword => 8, }, .scalar => |elem_size| switch (elem_size) { .byte => 1, .half => 2, .single => 4, .double => 8, .quad => 16, }, .vector => |arrangement| switch (arrangement) { .@"2d", .@"4s", .@"8h", .@"16b" => 16, .@"1d", .@"2s", .@"4h", .@"8b" => 8, }, .element => |element| continue :format .{ .scalar = element.size }, .scalable => null, }; } pub fn parse(reg: []const u8) ?Register { return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) { else => null, 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { 0...30 => .{ .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), .format = .{ .alias = .general }, }, 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 = .{ .general = .doubleword }, }, 31 => null, } else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null, 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { 0...30 => .{ .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), .format = .{ .general = .word }, }, 31 => null, } else |_| if (toLowerEqlAssertLower(reg, "wzr")) .wzr else if (toLowerEqlAssertLower(reg, "wsp")) .wsp else null, 'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0")) .ip0 else if (toLowerEqlAssertLower(reg, "ip1")) .ip1 else null, 'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null, 'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null, 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .alias = .vector }, } else |_| null, 'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .quad }, } else |_| null, 'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .double }, } else |_| null, 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .single }, } else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null, 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .half }, } else |_| null, 'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .byte }, } else |_| null, }; } pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter { return reg.fmtCase(.lower); } pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter { return .{ .reg = reg, .case = case }; } pub const System = packed struct(u16) { op2: u3, CRm: u4, CRn: u4, op1: u3, op0: u2, // D19.2 General system control registers /// D19.2.1 ACCDATA_EL1, Accelerator Data pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; /// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1) pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2) pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3) pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1) pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12) pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2) pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3) pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1) pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12) pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2) pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3) pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.11 AIDR_EL1, Auxiliary ID Register pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1) pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12) pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2) pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3) pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64]) pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 }; /// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0]) pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64]) pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 }; /// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0]) pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 }; /// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64]) pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 }; /// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0]) pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64]) pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0]) pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64]) pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 }; /// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0]) pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; /// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2 pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.27 CLIDR_EL1, Cache Level ID Register pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1) pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12) pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2) pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2) pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; /// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3) pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; /// D19.2.33 CSSELR_EL1, Cache Size Selection Register pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.34 CTR_EL0, Cache Type Register pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.35 DACR32_EL2, Domain Access Control Register pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.36 DCZID_EL0, Data Cache Zero ID Register pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1) pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12) pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2) pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3) pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.40 FAR_EL1, Fault Address Register (EL1) pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.40 FAR_EL12, Fault Address Register (EL12) pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.41 FAR_EL2, Fault Address Register (EL2) pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.42 FAR_EL3, Fault Address Register (EL3) pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.44 GCR_EL1, Tag Control Register pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 }; /// D19.2.45 GMID_EL1, Tag Control Register pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 }; /// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 }; /// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 }; /// D19.2.48 HCR_EL2, Hypervisor Configuration Register pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 }; /// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 }; /// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 }; /// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 }; /// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 }; /// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 }; /// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 }; /// D19.2.56 HSTR_EL2, Hypervisor System Trap Register pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 }; /// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0 pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 }; /// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1 pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 }; /// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0 pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 }; /// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1 pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 }; /// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0 pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1 pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 }; /// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2 pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 }; /// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0 pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 }; /// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1 pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 }; /// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2 pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 }; /// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3 pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 }; /// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4 pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 }; /// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0 pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 }; /// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1 pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 }; /// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2 pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 }; /// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0 pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 }; /// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0 pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 }; /// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0 pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 }; /// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0 pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 }; /// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1 pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 }; /// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0 pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1 pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 }; /// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2 pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 }; /// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3 pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 }; /// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4 pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 }; /// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5 pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 }; /// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6 pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 }; /// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0 pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 }; /// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1 pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 }; /// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2 pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 }; /// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3 pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 }; /// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4 pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 }; /// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5 pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 }; /// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0 pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1 pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 }; /// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2 pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 }; /// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2) pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.94 ISR_EL1, Interrupt Status Register pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.95 LORC_EL1, LORegion Control (EL1) pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 }; /// D19.2.96 LOREA_EL1, LORegion End Address (EL1) pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 }; /// D19.2.97 SORID_EL1, LORegionID (EL1) pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 }; /// D19.2.98 LORN_EL1, LORegion Number (EL1) pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 }; /// D19.2.99 LORSA_EL1, LORegion Start Address (EL1) pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 }; /// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1) pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12) pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2) pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3) pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.103 MIDR_EL1, Main ID Register pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; /// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0 pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 }; /// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1 pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 }; /// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2 pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 }; /// D19.2.108 PAR_EL1, Physical Address Register pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 }; /// D19.2.109 REVIDR_EL1, Revision ID Register pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; /// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 }; /// D19.2.111 RMR_EL1, Reset Management Register (EL1) pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.112 RMR_EL2, Reset Management Register (EL2) pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.113 RMR_EL3, Reset Management Register (EL3) pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.114 RNDR, Random Number pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 }; /// D19.2.115 RNDRRS, Reseeded Random Number pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 }; /// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented) pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented) pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented) pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.120 SCR_EL3, Secure Configuration Register pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.121 SCTLR2_EL1, System Control Register (EL1) pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.121 SCTLR2_EL12, System Control Register (EL12) pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.122 SCTLR2_EL2, System Control Register (EL2) pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.123 SCTLR2_EL3, System Control Register (EL3) pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.124 SCTLR_EL1, System Control Register (EL1) pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.124 SCTLR_EL12, System Control Register (EL12) pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.125 SCTLR_EL2, System Control Register (EL2) pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.126 SCTLR_EL3, System Control Register (EL3) pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; /// D19.2.131 SMCR_EL1, SME Control Register (EL1) pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; /// D19.2.131 SMCR_EL12, SME Control Register (EL12) pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; /// D19.2.132 SMCR_EL2, SME Control Register (EL2) pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; /// D19.2.133 SMCR_EL3, SME Control Register (EL3) pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; /// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; /// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 }; /// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 }; /// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1) pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12) pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2) pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.139 TCR_EL1, Translation Control Register (EL1) pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.139 TCR_EL12, Translation Control Register (EL12) pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.140 TCR_EL2, Translation Control Register (EL2) pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.141 TCR_EL3, Translation Control Register (EL3) pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0) pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 }; /// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1) pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12) pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2) pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3) pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2 pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; /// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 }; /// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; /// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 }; /// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1) pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12) pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2) pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3) pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1) pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12) pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2) pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; /// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1) pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12) pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2) pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3) pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; /// D19.2.161 VNCR_EL2, Virtual Nested Control Register pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; /// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 }; /// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 }; /// D19.2.165 VTCR_EL2, Virtualization Translation Control Register pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; /// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; /// D19.2.167 ZCR_EL1, SVE Control Register (EL1) pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.167 ZCR_EL12, SVE Control Register (EL12) pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.168 ZCR_EL2, SVE Control Register (EL2) pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; /// D19.2.169 ZCR_EL3, SVE Control Register (EL3) pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; pub fn parse(reg: []const u8) ?System { if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: { var symbol_it = std.mem.splitScalar(u8, reg[1..], '_'); const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded; if (op0 < 0b10) break :encoded; const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; const n = symbol_it.next() orelse break :encoded; if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded; const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded; const m = symbol_it.next() orelse break :encoded; if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded; const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded; const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; if (symbol_it.next() != null) break :encoded; return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 }; } inline for (@typeInfo(System).@"struct".decls) |decl| { if (@TypeOf(@field(System, decl.name)) != System) continue; if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name); } return null; } }; fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool { if (lhs.len != rhs.len) return false; for (lhs, rhs) |l, r| { assert(!std.ascii.isUpper(r)); if (std.ascii.toLower(l) != r) return false; } return true; } }; /// C1.2.4 Condition code pub const ConditionCode = enum(u4) { /// integer: Equal /// floating-point: Equal /// Z == 1 eq = 0b0000, /// integer: Not equal /// floating-point: Not equal or unordered /// Z == 0 ne = 0b0001, /// integer: Unsigned higher or same /// floating-point: Greater than, equal, or unordered /// C == 1 hs = 0b0010, /// integer: Unsigned lower /// floating-point: Less than /// C == 0 lo = 0b0011, /// integer: Minus, negative /// floating-point: Less than /// N == 1 mi = 0b0100, /// integer: Plus, positive or zero /// floating-point: Greater than, equal, or unordered /// N == 0 pl = 0b0101, /// integer: Overflow /// floating-point: Unordered /// V == 1 vs = 0b0110, /// integer: No overflow /// floating-point: Ordered /// V == 0 vc = 0b0111, /// integer: Unsigned higher /// floating-point: Greater than, or unordered /// C == 1 and Z == 0 hi = 0b1000, /// integer: Unsigned lower or same /// floating-point: Less than or equal /// C == 0 or Z == 1 ls = 0b1001, /// integer: Signed greater than or equal /// floating-point: Greater than or equal /// N == V ge = 0b1010, /// integer: Signed less than /// floating-point: Less than, or unordered /// N != V lt = 0b1011, /// integer: Signed greater than /// floating-point: Greater than /// Z == 0 and N == V gt = 0b1100, /// integer: Signed less than or equal /// floating-point: Less than, equal, or unordered /// Z == 1 or N != V le = 0b1101, /// integer: Always /// floating-point: Always /// true al = 0b1110, /// integer: Always /// floating-point: Always /// true nv = 0b1111, /// Carry set /// C == 1 pub const cs: ConditionCode = .hs; /// Carry clear /// C == 0 pub const cc: ConditionCode = .lo; pub fn invert(cond: ConditionCode) ConditionCode { return @enumFromInt(@intFromEnum(cond) ^ 0b0001); } }; /// C4.1 A64 instruction set encoding pub const Instruction = packed union { group: Group, reserved: Reserved, sme: Sme, sve: Sve, data_processing_immediate: DataProcessingImmediate, branch_exception_generating_system: BranchExceptionGeneratingSystem, load_store: LoadStore, data_processing_register: DataProcessingRegister, data_processing_vector: DataProcessingVector, /// Table C4-1 Main encoding table for the A64 instruction set pub const Group = packed struct { encoded0: u25, op1: u4, encoded29: u2, op0: u1, }; /// C4.1.1 Reserved pub const Reserved = packed union { group: @This().Group, udf: Udf, /// Table C4-2 Encoding table for the Reserved group pub const Group = packed struct { encoded0: u16, op1: u9, decoded25: u4 = 0b0000, op0: u2, decoded31: u1 = 0b0, }; /// C6.2.387 UDF pub const Udf = packed struct { imm16: u16, decoded16: u16 = 0b0000000000000000, }; pub const Decoded = union(enum) { unallocated, udf: Udf, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op0) { 0b00 => switch (inst.group.op1) { 0b000000000 => .{ .udf = inst.udf }, else => .unallocated, }, else => .unallocated, }; } }; /// C4.1.2 SME encodings pub const Sme = packed union { group: @This().Group, /// Table C4-3 Encodings table for the SME encodings group pub const Group = packed struct { encoded0: u2, op2: u3, encoded5: u5, op1: u15, decoded25: u4 = 0b0000, op0: u2, decoded31: u1 = 0b1, }; }; /// C4.1.30 SVE encodings pub const Sve = packed union { group: @This().Group, /// Table C4-31 Encoding table for the SVE encodings group pub const Group = packed struct { encoded0: u4, op2: u1, encoded5: u5, op1: u15, decoded25: u4 = 0b0010, op0: u3, }; }; /// C4.1.86 Data Processing -- Immediate pub const DataProcessingImmediate = packed union { group: @This().Group, pc_relative_addressing: PcRelativeAddressing, add_subtract_immediate: AddSubtractImmediate, add_subtract_immediate_with_tags: AddSubtractImmediateWithTags, logical_immediate: LogicalImmediate, move_wide_immediate: MoveWideImmediate, bitfield: Bitfield, extract: Extract, /// Table C4-87 Encoding table for the Data Processing -- Immediate group pub const Group = packed struct { encoded0: u23, op0: u3, decoded26: u3 = 0b100, encoded29: u3, }; /// PC-rel. addressing pub const PcRelativeAddressing = packed union { group: @This().Group, adr: Adr, adrp: Adrp, pub const Group = packed struct { Rd: Register.Encoded, immhi: i19, decoded24: u5 = 0b10000, immlo: u2, op: Op, }; /// C6.2.10 ADR pub const Adr = packed struct { Rd: Register.Encoded, immhi: i19, decoded24: u5 = 0b10000, immlo: u2, op: Op = .adr, }; /// C6.2.11 ADRP pub const Adrp = packed struct { Rd: Register.Encoded, immhi: i19, decoded24: u5 = 0b10000, immlo: u2, op: Op = .adrp, }; pub const Op = enum(u1) { adr = 0b0, adrp = 0b1, }; pub const Decoded = union(enum) { adr: Adr, adrp: Adrp, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { .adr => .{ .adr = inst.adr }, .adrp => .{ .adrp = inst.adrp }, }; } }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; pub const Shift = enum(u1) { @"0" = 0b0, @"12" = 0b1, }; pub const Decoded = union(enum) { add: Add, adds: Adds, sub: Sub, subs: Subs, }; pub fn decode(inst: @This()) @This().Decaded { return switch (inst.group.op) { .add => switch (inst.group.S) { false => .{ .add = inst.add }, true => .{ .addc = inst.addc }, }, .sub => switch (inst.group.S) { false => .{ .sub = inst.sub }, true => .{ .subc = inst.subc }, }, }; } }; /// Add/subtract (immediate, with tags) pub const AddSubtractImmediateWithTags = packed union { group: @This().Group, addg: Addg, subg: Subg, 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.GeneralSize, }; /// C6.2.6 ADDG pub const Addg = packed struct { Xd: Register.Encoded, Xn: Register.Encoded, uimm4: u4, op3: u2 = 0b00, uimm6: u6, o2: u1 = 0b0, decoded23: u6 = 0b100011, S: bool = false, op: AddSubtractOp = .add, sf: Register.GeneralSize = .doubleword, }; /// C6.2.359 SUBG pub const Subg = packed struct { Xd: Register.Encoded, Xn: Register.Encoded, uimm4: u4, op3: u2 = 0b00, uimm6: u6, o2: u1 = 0b0, decoded23: u6 = 0b100011, S: bool = false, op: AddSubtractOp = .sub, sf: Register.GeneralSize = .doubleword, }; pub const Decoded = union(enum) { unallocated, addg: Addg, subg: Subg, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.o2) { 0b1 => .unallocated, 0b0 => switch (inst.group.sf) { .word => .unallocated, .doubleword => switch (inst.group.S) { true => .unallocated, false => switch (inst.group.op) { .add => .{ .addg = inst.addg }, .sub => .{ .subg = inst.subg }, }, }, }, }; } }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// C6.2.226 MOVN pub const Movn = packed struct { Rd: Register.Encoded, imm16: u16, hw: Hw, decoded23: u6 = 0b100101, opc: Opc = .movn, sf: Register.GeneralSize, }; /// C6.2.227 MOVZ pub const Movz = packed struct { Rd: Register.Encoded, imm16: u16, hw: Hw, decoded23: u6 = 0b100101, opc: Opc = .movz, sf: Register.GeneralSize, }; /// C6.2.225 MOVK pub const Movk = packed struct { Rd: Register.Encoded, imm16: u16, hw: Hw, decoded23: u6 = 0b100101, opc: Opc = .movk, sf: Register.GeneralSize, }; 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.GeneralSize { 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.GeneralSize, }; pub const Sbfm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, imm: Bitmask, decoded23: u6 = 0b100110, opc: Opc = .sbfm, sf: Register.GeneralSize, }; pub const Bfm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, imm: Bitmask, decoded23: u6 = 0b100110, opc: Opc = .bfm, sf: Register.GeneralSize, }; pub const Ubfm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, imm: Bitmask, decoded23: u6 = 0b100110, opc: Opc = .ubfm, sf: Register.GeneralSize, }; 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.GeneralSize, decoded23: u6 = 0b100111, op21: u2, sf: Register.GeneralSize, }; pub const Extr = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, imms: u6, Rm: Register.Encoded, o0: u1 = 0b0, N: Register.GeneralSize, decoded23: u6 = 0b100111, op21: u2 = 0b00, sf: Register.GeneralSize, }; 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.GeneralSize, fn lenHsb(bitmask: Bitmask) u7 { return @bitCast(packed struct { not_imms: u6, N: Register.GeneralSize, }{ .not_imms = ~bitmask.imms, .N = bitmask.N }); } fn validImmediate(bitmask: Bitmask, sf: Register.GeneralSize) 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.GeneralSize) 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.GeneralSize) 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.GeneralSize) u64 { assert(bitmask.validImmediate(sf)); const imm, _ = bitmask.decode(sf); return imm; } pub fn decodeBitfield(bitmask: Bitmask, sf: Register.GeneralSize) struct { u64, u64 } { assert(bitmask.validBitfield(sf)); return bitmask.decode(sf); } pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.GeneralSize) 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 = no_reg, 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 = no_reg, 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 = no_reg, 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 = no_reg, 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 = no_reg, 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, _, }; pub const Decoded = union(enum) { unallocated, clrex: Clrex, dsb: Dsb, dmb: Dmb, isb: Isb, sb: Sb, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op2) { 0b000, 0b001 => .unallocated, 0b010 => switch (inst.group.Rt) { no_reg => .{ .clrex = inst.clrex }, else => .unallocated, }, 0b100 => switch (inst.group.Rt) { no_reg => .{ .dsb = inst.dsb }, else => .unallocated, }, 0b101 => switch (inst.group.Rt) { no_reg => .{ .dmb = inst.dmb }, else => .unallocated, }, 0b110 => switch (inst.group.Rt) { no_reg => .{ .isb = inst.isb }, else => .unallocated, }, 0b111 => switch (inst.group.Rt) { no_reg => .{ .sb = inst.sb }, else => .unallocated, }, }; } }; /// PSTATE pub const Pstate = packed union { group: @This().Group, msr: Msr, cfinv: Cfinv, xaflag: Xaflag, axflag: Axflag, pub const Group = packed struct { Rt: Register.Encoded, op2: u3, CRm: u4, decoded12: u4 = 0b0100, op1: u3, decoded19: u13 = 0b1101010100000, }; /// C6.2.229 MSR (immediate) pub const Msr = packed struct { Rt: Register.Encoded = no_reg, op2: u3, CRm: u4, decoded12: u4 = 0b0100, op1: u3, decoded19: u13 = 0b1101010100000, }; /// C6.2.52 CFINV pub const Cfinv = packed struct { Rt: Register.Encoded = no_reg, op2: u3 = 0b000, CRm: u4 = 0b0000, decoded12: u4 = 0b0100, op1: u3 = 0b000, decoded19: u13 = 0b1101010100000, }; /// C6.2.400 XAFLAG pub const Xaflag = packed struct { Rt: Register.Encoded = no_reg, op2: u3 = 0b001, CRm: u4 = 0b0000, decoded12: u4 = 0b0100, op1: u3 = 0b000, decoded19: u13 = 0b1101010100000, }; /// C6.2.24 AXFLAG pub const Axflag = packed struct { Rt: Register.Encoded = no_reg, op2: u3 = 0b010, CRm: u4 = 0b0000, decoded12: u4 = 0b0100, op1: u3 = 0b000, decoded19: u13 = 0b1101010100000, }; pub const Decoded = union(enum) { unallocated, msr: Msr, cfinv: Cfinv, xaflag: Xaflag, axflag: Axflag, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.Rt) { else => .unallocated, no_reg => switch (inst.group.op1) { else => .{ .msr = inst.msr }, 0b000 => switch (inst.group.op2) { else => .{ .msr = inst.msr }, 0b000 => .{ .cfinv = inst.cfinv }, 0b001 => .{ .xaflag = inst.xaflag }, 0b010 => .{ .axflag = inst.axflag }, }, }, }; } }; /// System with result pub const SystemResult = packed struct { Rt: Register.Encoded, op2: u3, CRm: u4, CRn: u4, op1: u3, decoded19: u13 = 0b1101010100100, }; /// System instructions pub const System = packed union { group: @This().Group, sys: Sys, sysl: Sysl, pub const Group = packed struct { Rt: Register.Encoded, op2: u3, CRm: u4, CRn: u4, op1: u3, decoded19: u2 = 0b01, L: L, decoded22: u10 = 0b1101010100, }; /// C6.2.372 SYS pub const Sys = packed struct { Rt: Register.Encoded, op2: u3, CRm: u4, CRn: u4, op1: u3, decoded19: u2 = 0b01, L: L = .sys, decoded22: u10 = 0b1101010100, }; /// C6.2.373 SYSL pub const Sysl = packed struct { Rt: Register.Encoded, op2: u3, CRm: u4, CRn: u4, op1: u3, decoded19: u2 = 0b01, L: L = .sysl, decoded22: u10 = 0b1101010100, }; const L = enum(u1) { sys = 0b0, sysl = 0b1, }; pub const Decoded = union(enum) { sys: Sys, sysl: Sysl, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.L) { .sys => .{ .sys = inst.sys }, .sysl => .{ .sysl = inst.sysl }, }; } }; /// System register move pub const SystemRegisterMove = packed union { group: @This().Group, msr: Msr, mrs: Mrs, pub const Group = packed struct { Rt: Register.Encoded, systemreg: Register.System, L: L, decoded22: u10 = 0b1101010100, }; /// C6.2.230 MSR (register) pub const Msr = packed struct { Rt: Register.Encoded, systemreg: Register.System, L: L = .msr, decoded22: u10 = 0b1101010100, }; /// C6.2.228 MRS pub const Mrs = packed struct { Rt: Register.Encoded, systemreg: Register.System, L: L = .mrs, decoded22: u10 = 0b1101010100, }; pub const L = enum(u1) { msr = 0b0, mrs = 0b1, }; pub const Decoded = union(enum) { msr: Msr, mrs: Mrs, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.L) { .msr => .{ .msr = inst.msr }, .mrs => .{ .mrs = inst.mrs }, }; } }; /// Unconditional branch (register) pub const UnconditionalBranchRegister = packed union { group: @This().Group, br: Br, blr: Blr, ret: Ret, pub const Group = packed struct { op4: u5, Rn: Register.Encoded, op3: u6, op2: u5, opc: u4, decoded25: u7 = 0b1101011, }; /// C6.2.37 BR pub const Br = packed struct { Rm: Register.Encoded = @enumFromInt(0), Rn: Register.Encoded, M: bool = false, A: bool = false, decoded12: u4 = 0b0000, decoded16: u5 = 0b11111, op: u2 = 0b00, decoded23: u1 = 0b0, Z: bool = false, decoded25: u7 = 0b1101011, }; /// C6.2.35 BLR pub const Blr = packed struct { Rm: Register.Encoded = @enumFromInt(0), Rn: Register.Encoded, M: bool = false, A: bool = false, decoded12: u4 = 0b0000, decoded16: u5 = 0b11111, op: u2 = 0b01, decoded23: u1 = 0b0, Z: bool = false, decoded25: u7 = 0b1101011, }; /// C6.2.254 RET pub const Ret = packed struct { Rm: Register.Encoded = @enumFromInt(0), Rn: Register.Encoded, M: bool = false, A: bool = false, decoded12: u4 = 0b0000, decoded16: u5 = 0b11111, op: u2 = 0b10, decoded23: u1 = 0b0, Z: bool = false, decoded25: u7 = 0b1101011, }; pub const Decoded = union(enum) { unallocated, br: Br, blr: Blr, ret: Ret, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op2) { else => .unallocated, 0b11111 => switch (inst.group.opc) { 0b0000 => switch (inst.group.op4) { else => .unallocated, 0b00000 => .{ .br = inst.br }, }, 0b0001 => switch (inst.group.op4) { else => .unallocated, 0b00000 => .{ .blr = inst.blr }, }, 0b0010 => switch (inst.group.op4) { else => .unallocated, 0b00000 => .{ .ret = inst.ret }, }, else => .unallocated, }, }; } }; /// Unconditional branch (immediate) pub const UnconditionalBranchImmediate = packed union { group: @This().Group, b: B, bl: Bl, pub const Group = packed struct { imm26: i26, decoded26: u5 = 0b00101, op: Op, }; /// C6.2.25 B pub const B = packed struct { imm26: i26, decoded26: u5 = 0b00101, op: Op = .b, }; /// C6.2.34 BL pub const Bl = packed struct { imm26: i26, decoded26: u5 = 0b00101, op: Op = .bl, }; pub const Op = enum(u1) { b = 0b0, bl = 0b1, }; pub const Decoded = union(enum) { b: B, bl: Bl, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { .b => .{ .b = inst.b }, .bl => .{ .bl = inst.bl }, }; } }; /// 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.GeneralSize, }; /// C6.2.47 CBZ pub const Cbz = packed struct { Rt: Register.Encoded, imm19: i19, op: Op = .cbz, decoded25: u6 = 0b011010, sf: Register.GeneralSize, }; /// C6.2.46 CBNZ pub const Cbnz = packed struct { Rt: Register.Encoded, imm19: i19, op: Op = .cbnz, decoded25: u6 = 0b011010, sf: Register.GeneralSize, }; pub const Op = enum(u1) { cbz = 0b0, cbnz = 0b1, }; pub const Decoded = union(enum) { cbz: Cbz, cbnz: Cbnz, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { .cbz => .{ .cbz = inst.cbz }, .cbnz => .{ .cbnz = inst.cbnz }, }; } }; /// 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) { tbz: Tbz, tbnz: Tbnz, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { .tbz => .{ .tbz = inst.tbz }, .tbnz => .{ .tbnz = inst.tbnz }, }; } }; pub const no_reg: Register.Encoded = Register.Alias.zr.encode(.{}); 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.GeneralSize, 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: Size, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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: Size, }; /// 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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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.GeneralSize, 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.GeneralSize, 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: Size = .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: Size = .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: Vector.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: Vector.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: Vector.Size, }; pub const Opc1 = packed struct { encoded: u1, pub fn encode(ss: Register.ScalarSize) Opc1 { return .{ .encoded = switch (ss) { .byte, .half, .single, .double => 0b0, .quad => 0b1, } }; } pub fn decode(enc_opc1: Opc1, enc_size: Vector.Size) Register.ScalarSize { 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(ss: Register.ScalarSize) Vector.Size { return .{ .encoded = switch (ss) { .byte, .quad => 0b00, .half => 0b01, .single => 0b10, .double => 0b11, } }; } }; 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: Size, }; /// 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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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.GeneralSize, 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.GeneralSize, 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: Size = .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: Vector.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: Vector.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: Vector.Size, }; pub const Opc1 = packed struct { encoded: u1, pub fn encode(ss: Register.ScalarSize) Opc1 { return .{ .encoded = switch (ss) { .byte, .half, .single, .double => 0b0, .quad => 0b1, } }; } pub fn decode(enc_opc1: Opc1, enc_size: Vector.Size) Register.ScalarSize { 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(ss: Register.ScalarSize) Vector.Size { return .{ .encoded = switch (ss) { .byte, .quad => 0b00, .half => 0b01, .single => 0b10, .double => 0b11, } }; } }; 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: Size, }; /// 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: Size, }; /// 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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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.GeneralSize, 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.GeneralSize, 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: Size = .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: Vector.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: Vector.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: Vector.Size, }; pub const Opc1 = packed struct { encoded: u1, pub fn encode(ss: Register.ScalarSize) Opc1 { return .{ .encoded = switch (ss) { .byte, .half, .single, .double => 0b0, .quad => 0b1, } }; } pub fn decode(enc_opc1: Opc1, enc_size: Vector.Size) Register.ScalarSize { 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(ss: Register.ScalarSize) Vector.Size { return .{ .encoded = switch (ss) { .byte, .quad => 0b00, .half => 0b01, .single => 0b10, .double => 0b11, } }; } }; 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: Size, }; /// 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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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.GeneralSize, 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.GeneralSize, 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: Size = .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: Size = .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: Vector.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: Vector.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: Vector.Size, }; pub const Opc1 = packed struct { encoded: u1, pub fn encode(ss: Register.ScalarSize) Opc1 { return .{ .encoded = switch (ss) { .byte, .half, .single, .double => 0b0, .quad => 0b1, } }; } pub fn decode(enc_opc1: Opc1, enc_size: Vector.Size) Register.ScalarSize { 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(ss: Register.ScalarSize) Vector.Size { return .{ .encoded = switch (ss) { .byte, .quad => 0b00, .half => 0b01, .single => 0b10, .double => 0b11, } }; } }; }; pub const Option = enum(u3) { uxtw = 0b010, lsl = 0b011, sxtw = 0b110, sxtx = 0b111, _, pub fn sf(option: Option) Register.GeneralSize { 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: Size, }; /// 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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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: Size = .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.GeneralSize, 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.GeneralSize, 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: Size = .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: Size = .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: Vector.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: Vector.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: Vector.Size, }; pub const Opc1 = packed struct { encoded: u1, pub fn encode(ss: Register.ScalarSize) Opc1 { return .{ .encoded = switch (ss) { .byte, .half, .single, .double => 0b0, .quad => 0b1, } }; } pub fn decode(enc_opc1: Opc1, enc_size: Vector.Size) Register.ScalarSize { 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(ss: Register.ScalarSize) Vector.Size { return .{ .encoded = switch (ss) { .byte, .quad => 0b00, .half => 0b01, .single => 0b10, .double => 0b11, } }; } }; 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 Size = 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.ScalarSize { return switch (vs) { .single => .single, .double => .double, .quad => .quad, _ => unreachable, }; } pub fn encode(ss: Register.ScalarSize) VectorSize { return switch (ss) { 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize = .doubleword, }; /// C6.2.256 REV pub const Rev = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, opc0: Register.GeneralSize, opc1: u1 = 0b1, decoded12: u4 = 0b0000, decoded16: u5 = 0b00000, decoded21: u8 = 0b11010110, S: bool = false, decoded30: u1 = 0b1, sf: Register.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize { 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; }; /// 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.GeneralSize, }; }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// C6.2.282 SMADDL pub const Smaddl = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .add, Rm: Register.Encoded, op21: u2 = 0b01, U: std.builtin.Signedness = .signed, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .doubleword, }; /// C6.2.287 SMSUBL pub const Smsubl = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .sub, Rm: Register.Encoded, op21: u2 = 0b01, U: std.builtin.Signedness = .signed, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .doubleword, }; /// C6.2.288 SMULH pub const Smulh = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded = Register.Alias.zr.encode(.{}), o0: AddSubtractOp = .add, Rm: Register.Encoded, op21: u2 = 0b10, U: std.builtin.Signedness = .signed, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .doubleword, }; /// C6.2.389 UMADDL pub const Umaddl = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .add, Rm: Register.Encoded, op21: u2 = 0b01, U: std.builtin.Signedness = .unsigned, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .doubleword, }; /// C6.2.391 UMSUBL pub const Umsubl = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .sub, Rm: Register.Encoded, op21: u2 = 0b01, U: std.builtin.Signedness = .unsigned, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .doubleword, }; /// C6.2.392 UMULH pub const Umulh = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded = Register.Alias.zr.encode(.{}), o0: AddSubtractOp = .add, Rm: Register.Encoded, op21: u2 = 0b10, U: std.builtin.Signedness = .unsigned, decoded24: u5 = 0b11011, op54: u2 = 0b00, sf: Register.GeneralSize = .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 Decoded = union(enum) { unallocated, data_processing_two_source: DataProcessingTwoSource, data_processing_one_source: DataProcessingOneSource, logical_shifted_register: LogicalShiftedRegister, add_subtract_shifted_register: AddSubtractShiftedRegister, add_subtract_extended_register: AddSubtractExtendedRegister, add_subtract_with_carry: AddSubtractWithCarry, rotate_right_into_flags: RotateRightIntoFlags, evaluate_into_flags: EvaluateIntoFlags, conditional_compare_register: ConditionalCompareRegister, conditional_compare_immediate: ConditionalCompareImmediate, conditional_select: ConditionalSelect, data_processing_three_source: DataProcessingThreeSource, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op1) { 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) { 0b0 => .{ .logical_shifted_register = inst.logical_shifted_register }, 0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) { 0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register }, 0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register }, }, }, 0b1 => switch (inst.group.op2) { 0b0000 => switch (inst.group.op3) { 0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry }, 0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags }, 0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags }, else => .unallocated, }, 0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) { 0b0 => .{ .conditional_compare_register = inst.conditional_compare_register }, 0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate }, }, 0b0100 => .{ .conditional_select = inst.conditional_select }, 0b0110 => switch (inst.group.op0) { 0b0 => .{ .data_processing_two_source = inst.data_processing_two_source }, 0b1 => .{ .data_processing_one_source = inst.data_processing_one_source }, }, 0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source }, else => .unallocated, }, }; } }; /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD pub const DataProcessingVector = packed union { group: @This().Group, simd_scalar_copy: SimdScalarCopy, simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16, simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous, simd_scalar_pairwise: SimdScalarPairwise, simd_copy: SimdCopy, simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16, simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous, simd_across_lanes: SimdAcrossLanes, simd_three_same: SimdThreeSame, simd_modified_immediate: SimdModifiedImmediate, convert_float_fixed: ConvertFloatFixed, convert_float_integer: ConvertFloatInteger, float_data_processing_one_source: FloatDataProcessingOneSource, float_compare: FloatCompare, float_immediate: FloatImmediate, float_conditional_compare: FloatConditionalCompare, float_data_processing_two_source: FloatDataProcessingTwoSource, float_conditional_select: FloatConditionalSelect, float_data_processing_three_source: FloatDataProcessingThreeSource, /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group pub const Group = packed struct { encoded0: u10, op3: u9, op2: u4, op1: u2, decoded25: u3 = 0b111, op0: u4, }; /// Advanced SIMD scalar copy pub const SimdScalarCopy = packed union { group: @This().Group, dup: Dup, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: u4, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b11110000, op: u1, decoded30: u2 = 0b01, }; /// C7.2.39 DUP (element) pub const Dup = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: u4 = 0b0000, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b11110000, op: u1 = 0b0, decoded30: u2 = 0b01, }; pub const Decoded = union(enum) { unallocated, dup: Dup, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { 0b0 => switch (inst.group.imm4) { else => .unallocated, 0b0000 => .{ .dup = inst.dup }, }, 0b1 => .unallocated, }; } }; /// Advanced SIMD scalar two-register miscellaneous FP16 pub const SimdScalarTwoRegisterMiscellaneousFp16 = packed union { group: @This().Group, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frecpx: Frecpx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u6 = 0b111100, a: u1, decoded24: u5 = 0b11110, U: std.builtin.Signedness, decoded30: u2 = 0b01, }; /// C7.2.80 FCVTNS (vector) pub const Fcvtns = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.75 FCVTMS (vector) pub const Fcvtms = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.70 FCVTAS (vector) pub const Fcvtas = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.234 SCVTF (vector, integer) pub const Scvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.61 FCMGT (zero) pub const Fcmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.57 FCMEQ (zero) pub const Fcmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.65 FCMLT (zero) pub const Fcmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01110, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.84 FCVTPS (vector) pub const Fcvtps = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.90 FCVTZS (vector, integer) pub const Fcvtzs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.144 FRECPE pub const Frecpe = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.146 FRECPX pub const Frecpx = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11111, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.82 FCVTNU (vector) pub const Fcvtnu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.77 FCVTMU (vector) pub const Fcvtmu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.72 FCVTAU (vector) pub const Fcvtau = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.353 UCVTF (vector, integer) pub const Ucvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.59 FCMGE (zero) pub const Fcmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.64 FCMLE (zero) pub const Fcmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.86 FCVTPU (vector) pub const Fcvtpu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.94 FCVTZU (vector, integer) pub const Fcvtzu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.169 FRSQRTE pub const Frsqrte = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; pub const Decoded = union(enum) { unallocated, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frecpx: Frecpx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.a) { 0b0 => switch (inst.group.opcode) { else => .unallocated, 0b11010 => .{ .fcvtns = inst.fcvtns }, 0b11011 => .{ .fcvtms = inst.fcvtms }, 0b11100 => .{ .fcvtas = inst.fcvtas }, 0b11101 => .{ .scvtf = inst.scvtf }, }, 0b1 => switch (inst.group.opcode) { else => .unallocated, 0b01100 => .{ .fcmgt = inst.fcmgt }, 0b01101 => .{ .fcmeq = inst.fcmeq }, 0b01110 => .{ .fcmlt = inst.fcmlt }, 0b11010 => .{ .fcvtps = inst.fcvtps }, 0b11011 => .{ .fcvtzs = inst.fcvtzs }, 0b11101 => .{ .frecpe = inst.frecpe }, 0b11111 => .{ .frecpx = inst.frecpx }, }, }, .unsigned => switch (inst.group.a) { 0b0 => switch (inst.group.opcode) { else => .unallocated, 0b11010 => .{ .fcvtnu = inst.fcvtnu }, 0b11011 => .{ .fcvtmu = inst.fcvtmu }, 0b11100 => .{ .fcvtau = inst.fcvtau }, 0b11101 => .{ .ucvtf = inst.ucvtf }, }, 0b1 => switch (inst.group.opcode) { else => .unallocated, 0b01100 => .{ .fcmge = inst.fcmge }, 0b01101 => .{ .fcmle = inst.fcmle }, 0b11010 => .{ .fcvtpu = inst.fcvtpu }, 0b11011 => .{ .fcvtzu = inst.fcvtzu }, 0b11101 => .{ .frsqrte = inst.frsqrte }, }, }, }; } }; /// Advanced SIMD scalar two-register miscellaneous pub const SimdScalarTwoRegisterMiscellaneous = packed union { group: @This().Group, suqadd: Suqadd, sqabs: Sqabs, cmgt: Cmgt, cmeq: Cmeq, cmlt: Cmlt, abs: Abs, sqxtn: Sqxtn, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frecpx: Frecpx, usqadd: Usqadd, sqneg: Sqneg, cmge: Cmge, cmle: Cmle, neg: Neg, sqxtun: Sqxtun, uqxtn: Uqxtn, fcvtxn: Fcvtxn, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness, decoded30: u2 = 0b01, }; /// C7.2.337 SUQADD pub const Suqadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.282 SQABS pub const Sqabs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00111, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.32 CMGT (zero) pub const Cmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01000, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.28 CMEQ (zero) pub const Cmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01001, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.36 CMLT (zero) pub const Cmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01010, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.1 ABS pub const Abs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.308 SQXTN pub const Sqxtn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10100, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.80 FCVTNS (vector) pub const Fcvtns = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.75 FCVTMS (vector) pub const Fcvtms = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.70 FCVTAS (vector) pub const Fcvtas = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.234 SCVTF (vector, integer) pub const Scvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.61 FCMGT (zero) pub const Fcmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.57 FCMEQ (zero) pub const Fcmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.65 FCMLT (zero) pub const Fcmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01110, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.84 FCVTPS (vector) pub const Fcvtps = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.90 FCVTZS (vector, integer) pub const Fcvtzs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.144 FRECPE pub const Frecpe = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.146 FRECPX pub const Frecpx = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11111, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; /// C7.2.394 USQADD pub const Usqadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.292 SQNEG pub const Sqneg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00111, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.30 CMGE (zero) pub const Cmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01000, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.35 CMLE (zero) pub const Cmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01001, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.209 NEG (vector) pub const Neg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.309 SQXTUN pub const Sqxtun = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10010, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.381 UQXTN pub const Uqxtn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10100, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.88 FCVTXN pub const Fcvtxn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10110, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.82 FCVTNU (vector) pub const Fcvtnu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.77 FCVTMU (vector) pub const Fcvtmu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.72 FCVTAU (vector) pub const Fcvtau = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.353 UCVTF (vector, integer) pub const Ucvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.59 FCMGE (zero) pub const Fcmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.64 FCMLE (zero) pub const Fcmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.86 FCVTPU (vector) pub const Fcvtpu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.94 FCVTZU (vector, integer) pub const Fcvtzu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; /// C7.2.169 FRSQRTE pub const Frsqrte = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .unsigned, decoded30: u2 = 0b01, }; pub const Decoded = union(enum) { unallocated, suqadd: Suqadd, sqabs: Sqabs, cmgt: Cmgt, cmeq: Cmeq, cmlt: Cmlt, abs: Abs, sqxtn: Sqxtn, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frecpx: Frecpx, usqadd: Usqadd, sqneg: Sqneg, cmge: Cmge, cmle: Cmle, neg: Neg, sqxtun: Sqxtun, uqxtn: Uqxtn, fcvtxn: Fcvtxn, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.opcode) { else => .unallocated, 0b00011 => .{ .suqadd = inst.suqadd }, 0b00111 => .{ .sqabs = inst.sqabs }, 0b01000 => .{ .cmgt = inst.cmgt }, 0b01001 => .{ .cmeq = inst.cmeq }, 0b01010 => .{ .cmlt = inst.cmlt }, 0b01011 => .{ .abs = inst.abs }, 0b10100 => .{ .sqxtn = inst.sqxtn }, 0b11010 => switch (inst.group.size) { .byte, .half => .{ .fcvtns = inst.fcvtns }, .single, .double => .{ .fcvtps = inst.fcvtps }, }, 0b11011 => switch (inst.group.size) { .byte, .half => .{ .fcvtms = inst.fcvtms }, .single, .double => .{ .fcvtzs = inst.fcvtzs }, }, 0b11100 => switch (inst.group.size) { .byte, .half => .{ .fcvtas = inst.fcvtas }, .single, .double => .unallocated, }, 0b11101 => switch (inst.group.size) { .byte, .half => .{ .scvtf = inst.scvtf }, .single, .double => .{ .frecpe = inst.frecpe }, }, 0b01100 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmgt = inst.fcmgt }, }, 0b01101 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmeq = inst.fcmeq }, }, 0b01110 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmlt = inst.fcmlt }, }, 0b11111 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .frecpx = inst.frecpx }, }, }, .unsigned => switch (inst.group.opcode) { else => .unallocated, 0b00011 => .{ .usqadd = inst.usqadd }, 0b00111 => .{ .sqneg = inst.sqneg }, 0b01000 => .{ .cmge = inst.cmge }, 0b01001 => .{ .cmle = inst.cmle }, 0b01011 => .{ .neg = inst.neg }, 0b10010 => .{ .sqxtun = inst.sqxtun }, 0b10100 => .{ .uqxtn = inst.uqxtn }, 0b10110 => switch (inst.group.size) { .byte, .half => .{ .fcvtxn = inst.fcvtxn }, .single, .double => .unallocated, }, 0b11010 => switch (inst.group.size) { .byte, .half => .{ .fcvtnu = inst.fcvtnu }, .single, .double => .{ .fcvtpu = inst.fcvtpu }, }, 0b11011 => switch (inst.group.size) { .byte, .half => .{ .fcvtmu = inst.fcvtmu }, .single, .double => .{ .fcvtzu = inst.fcvtzu }, }, 0b11100 => switch (inst.group.size) { .byte, .half => .{ .fcvtau = inst.fcvtau }, .single, .double => .unallocated, }, 0b11101 => switch (inst.group.size) { .byte, .half => .{ .ucvtf = inst.ucvtf }, .single, .double => .{ .frsqrte = inst.frsqrte }, }, 0b01100 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmge = inst.fcmge }, }, 0b01101 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmle = inst.fcmle }, }, }, }; } }; /// Advanced SIMD scalar pairwise pub const SimdScalarPairwise = packed union { group: @This().Group, addp: Addp, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u5 = 0b11000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness, decoded30: u2 = 0b01, }; /// C7.2.4 ADDP (scalar) pub const Addp = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b11000, size: Size, decoded24: u5 = 0b11110, U: std.builtin.Signedness = .signed, decoded30: u2 = 0b01, }; pub const Decoded = union(enum) { unallocated, addp: Addp, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.opcode) { else => .unallocated, 0b11011 => .{ .addp = inst.addp }, }, .unsigned => .unallocated, }; } }; /// Advanced SIMD copy pub const SimdCopy = packed union { group: @This().Group, dup: Dup, smov: Smov, umov: Umov, ins: Ins, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: u4, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b01110000, op: u1, Q: u1, decoded31: u1 = 0b0, }; /// C7.2.39 DUP (element) /// C7.2.40 DUP (general) pub const Dup = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: Imm4, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b01110000, op: u1 = 0b0, Q: Q, decoded31: u1 = 0b0, pub const Imm4 = enum(u4) { element = 0b0000, general = 0b0001, _, }; }; /// C7.2.279 SMOV pub const Smov = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: u4 = 0b0101, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b01110000, op: u1 = 0b0, Q: Register.GeneralSize, decoded31: u1 = 0b0, }; /// C7.2.371 UMOV pub const Umov = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: u4 = 0b0111, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b01110000, op: u1 = 0b0, Q: Register.GeneralSize, decoded31: u1 = 0b0, }; /// C7.2.175 INS (element) /// C7.2.176 INS (general) pub const Ins = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, imm4: Imm4, decoded15: u1 = 0b0, imm5: u5, decoded21: u8 = 0b01110000, op: Op, Q: u1 = 0b1, decoded31: u1 = 0b0, pub const Imm4 = packed union { element: u4, general: General, pub const General = enum(u4) { general = 0b0011, _, }; }; pub const Op = enum(u1) { general = 0b0, element = 0b1, }; }; pub const Decoded = union(enum) { unallocated, dup: Dup, smov: Smov, umov: Umov, ins: Ins, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op) { 0b0 => switch (inst.group.imm4) { 0b0000, 0b0001 => .{ .dup = inst.dup }, else => .unallocated, 0b0101 => switch (@ctz(inst.group.imm5)) { 0, 1 => .{ .smov = inst.smov }, 2 => switch (inst.group.Q) { 0b1 => .{ .smov = inst.smov }, 0b0 => .unallocated, }, else => .unallocated, }, 0b0111 => switch (@ctz(inst.group.imm5)) { 0, 1, 2 => switch (inst.group.Q) { 0b0 => .{ .umov = inst.umov }, 0b1 => .unallocated, }, 3 => switch (inst.group.Q) { 0b1 => .{ .umov = inst.umov }, 0b0 => .unallocated, }, else => .unallocated, }, 0b0011 => switch (inst.group.Q) { 0b0 => .unallocated, 0b1 => .{ .ins = inst.ins }, }, }, 0b1 => switch (inst.group.Q) { 0b0 => .unallocated, 0b1 => .{ .ins = inst.ins }, }, }; } }; /// Advanced SIMD two-register miscellaneous (FP16) pub const SimdTwoRegisterMiscellaneousFp16 = packed union { group: @This().Group, frintn: Frintn, frintm: Frintm, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fabs: Fabs, frintp: Frintp, frintz: Frintz, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frinta: Frinta, frintx: Frintx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fneg: Fneg, frinti: Frinti, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, fsqrt: Fsqrt, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u6 = 0b111100, a: u1, decoded24: u5 = 0b01110, U: std.builtin.Signedness, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.161 FRINTN (vector) pub const Frintn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.159 FRINTM (vector) pub const Frintm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.80 FCVTNS (vector) pub const Fcvtns = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.75 FCVTMS (vector) pub const Fcvtms = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.70 FCVTAS (vector) pub const Fcvtas = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.234 SCVTF (vector, integer) pub const Scvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.61 FCMGT (zero) pub const Fcmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.57 FCMEQ (zero) pub const Fcmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.65 FCMLT (zero) pub const Fcmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01110, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.45 FABS (vector) pub const Fabs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01111, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.163 FRINTP (vector) pub const Frintp = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.167 FRINTZ (vector) pub const Frintz = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.84 FCVTPS (vector) pub const Fcvtps = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.90 FCVTZS (vector, integer) pub const Fcvtzs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.144 FRECPE pub const Frecpe = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.155 FRINTA (vector) pub const Frinta = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.159 FRINTX (vector) pub const Frintx = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.82 FCVTNU (vector) pub const Fcvtnu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.77 FCVTMU (vector) pub const Fcvtmu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.72 FCVTAU (vector) pub const Fcvtau = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.353 UCVTF (vector, integer) pub const Ucvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.59 FCMGE (zero) pub const Fcmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.64 FCMLE (zero) pub const Fcmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.139 FNEG (vector) pub const Fneg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01111, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.157 FRINTI (vector) pub const Frinti = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.86 FCVTPU (vector) pub const Fcvtpu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.94 FCVTZU (vector, integer) pub const Fcvtzu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.169 FRSQRTE pub const Frsqrte = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.171 FSQRT pub const Fsqrt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11111, decoded17: u6 = 0b111100, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; pub const Decoded = union(enum) { unallocated, frintn: Frintn, frintm: Frintm, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fabs: Fabs, frintp: Frintp, frintz: Frintz, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, frinta: Frinta, frintx: Frintx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, fcmge: Fcmge, fcmle: Fcmle, fneg: Fneg, frinti: Frinti, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, fsqrt: Fsqrt, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.a) { 0b0 => switch (inst.group.opcode) { else => .unallocated, 0b11000 => .{ .frintn = inst.frintn }, 0b11001 => .{ .frintm = inst.frintm }, 0b11010 => .{ .fcvtns = inst.fcvtns }, 0b11011 => .{ .fcvtms = inst.fcvtms }, 0b11100 => .{ .fcvtas = inst.fcvtas }, 0b11101 => .{ .scvtf = inst.scvtf }, }, 0b1 => switch (inst.group.opcode) { else => .unallocated, 0b01100 => .{ .fcmgt = inst.fcmgt }, 0b01101 => .{ .fcmeq = inst.fcmeq }, 0b01110 => .{ .fcmlt = inst.fcmlt }, 0b01111 => .{ .fabs = inst.fabs }, 0b11000 => .{ .frintp = inst.frintp }, 0b11001 => .{ .frintz = inst.frintz }, 0b11010 => .{ .fcvtps = inst.fcvtps }, 0b11011 => .{ .fcvtzs = inst.fcvtzs }, 0b11101 => .{ .frecpe = inst.frecpe }, }, }, .unsigned => switch (inst.group.a) { 0b0 => switch (inst.group.opcode) { else => .unallocated, 0b11000 => .{ .frinta = inst.frinta }, 0b11001 => .{ .frintx = inst.frintx }, 0b11010 => .{ .fcvtnu = inst.fcvtnu }, 0b11011 => .{ .fcvtmu = inst.fcvtmu }, 0b11100 => .{ .fcvtau = inst.fcvtau }, 0b11101 => .{ .ucvtf = inst.ucvtf }, }, 0b1 => switch (inst.group.opcode) { else => .unallocated, 0b01100 => .{ .fcmge = inst.fcmge }, 0b01101 => .{ .fcmle = inst.fcmle }, 0b01111 => .{ .fneg = inst.fneg }, 0b11001 => .{ .frinti = inst.frinti }, 0b11010 => .{ .fcvtpu = inst.fcvtpu }, 0b11011 => .{ .fcvtzu = inst.fcvtzu }, 0b11101 => .{ .frsqrte = inst.frsqrte }, 0b11111 => .{ .fsqrt = inst.fsqrt }, }, }, }; } }; /// Advanced SIMD two-register miscellaneous pub const SimdTwoRegisterMiscellaneous = packed union { group: @This().Group, suqadd: Suqadd, cnt: Cnt, sqabs: Sqabs, cmgt: Cmgt, cmeq: Cmeq, cmlt: Cmlt, abs: Abs, sqxtn: Sqxtn, frintn: Frintn, frintm: Frintm, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fabs: Fabs, frintp: Frintp, frintz: Frintz, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, usqadd: Usqadd, sqneg: Sqneg, cmge: Cmge, cmle: Cmle, neg: Neg, sqxtun: Sqxtun, uqxtn: Uqxtn, fcvtxn: Fcvtxn, frinta: Frinta, frintx: Frintx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, not: Not, fcmge: Fcmge, fcmle: Fcmle, fneg: Fneg, frinti: Frinti, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, fsqrt: Fsqrt, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.337 SUQADD pub const Suqadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.38 CNT pub const Cnt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00101, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.282 SQABS pub const Sqabs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00111, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.32 CMGT (zero) pub const Cmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01000, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.28 CMEQ (zero) pub const Cmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01001, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.36 CMLT (zero) pub const Cmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01010, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.1 ABS pub const Abs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.308 SQXTN, SQXTN2 pub const Sqxtn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10100, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.161 FRINTN (vector) pub const Frintn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.159 FRINTM (vector) pub const Frintm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.80 FCVTNS (vector) pub const Fcvtns = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.75 FCVTMS (vector) pub const Fcvtms = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.70 FCVTAS (vector) pub const Fcvtas = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.234 SCVTF (vector, integer) pub const Scvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.61 FCMGT (zero) pub const Fcmgt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.57 FCMEQ (zero) pub const Fcmeq = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.65 FCMLT (zero) pub const Fcmlt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01110, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.45 FABS (vector) pub const Fabs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01111, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.163 FRINTP (vector) pub const Frintp = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.167 FRINTZ (vector) pub const Frintz = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.84 FCVTPS (vector) pub const Fcvtps = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.90 FCVTZS (vector, integer) pub const Fcvtzs = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.144 FRECPE pub const Frecpe = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.394 USQADD pub const Usqadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.292 SQNEG pub const Sqneg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00111, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.30 CMGE (zero) pub const Cmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01000, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.35 CMLE (zero) pub const Cmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01001, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.209 NEG (vector) pub const Neg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01011, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.309 SQXTUN pub const Sqxtun = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10010, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.381 UQXTN pub const Uqxtn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10100, decoded17: u5 = 0b10000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.88 FCVTXN pub const Fcvtxn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b10110, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.155 FRINTA (vector) pub const Frinta = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11000, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.165 FRINTX (vector) pub const Frintx = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.82 FCVTNU (vector) pub const Fcvtnu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.77 FCVTMU (vector) pub const Fcvtmu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.72 FCVTAU (vector) pub const Fcvtau = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.353 UCVTF (vector, integer) pub const Ucvtf = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b0, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.210 NOT pub const Not = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b00101, decoded17: u5 = 0b10000, size: Size = .byte, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.59 FCMGE (zero) pub const Fcmge = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01100, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.64 FCMLE (zero) pub const Fcmle = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.139 FNEG (vector) pub const Fneg = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b01111, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.157 FRINTI (vector) pub const Frinti = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11001, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.86 FCVTPU (vector) pub const Fcvtpu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11010, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.94 FCVTZU (vector, integer) pub const Fcvtzu = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.169 FRSQRTE pub const Frsqrte = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11101, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.171 FSQRT (vector) pub const Fsqrt = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11111, decoded17: u5 = 0b10000, sz: Sz, o2: u1 = 0b1, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; pub const Decoded = union(enum) { unallocated, suqadd: Suqadd, cnt: Cnt, sqabs: Sqabs, cmgt: Cmgt, cmeq: Cmeq, cmlt: Cmlt, abs: Abs, sqxtn: Sqxtn, frintn: Frintn, frintm: Frintm, fcvtns: Fcvtns, fcvtms: Fcvtms, fcvtas: Fcvtas, scvtf: Scvtf, fcmgt: Fcmgt, fcmeq: Fcmeq, fcmlt: Fcmlt, fabs: Fabs, frintp: Frintp, frintz: Frintz, fcvtps: Fcvtps, fcvtzs: Fcvtzs, frecpe: Frecpe, usqadd: Usqadd, sqneg: Sqneg, cmge: Cmge, cmle: Cmle, neg: Neg, sqxtun: Sqxtun, uqxtn: Uqxtn, fcvtxn: Fcvtxn, frinta: Frinta, frintx: Frintx, fcvtnu: Fcvtnu, fcvtmu: Fcvtmu, fcvtau: Fcvtau, ucvtf: Ucvtf, not: Not, fcmge: Fcmge, fcmle: Fcmle, fneg: Fneg, frinti: Frinti, fcvtpu: Fcvtpu, fcvtzu: Fcvtzu, frsqrte: Frsqrte, fsqrt: Fsqrt, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.opcode) { else => .unallocated, 0b00011 => .{ .suqadd = inst.suqadd }, 0b00101 => .{ .cnt = inst.cnt }, 0b00111 => .{ .sqabs = inst.sqabs }, 0b01000 => .{ .cmgt = inst.cmgt }, 0b01001 => .{ .cmeq = inst.cmeq }, 0b01010 => .{ .cmlt = inst.cmlt }, 0b01011 => .{ .abs = inst.abs }, 0b10100 => .{ .sqxtn = inst.sqxtn }, 0b11000 => switch (inst.group.size) { .byte, .half => .{ .frintn = inst.frintn }, .single, .double => .{ .frintp = inst.frintp }, }, 0b11001 => switch (inst.group.size) { .byte, .half => .{ .frintm = inst.frintm }, .single, .double => .{ .frintz = inst.frintz }, }, 0b11010 => switch (inst.group.size) { .byte, .half => .{ .fcvtns = inst.fcvtns }, .single, .double => .{ .fcvtps = inst.fcvtps }, }, 0b11011 => switch (inst.group.size) { .byte, .half => .{ .fcvtms = inst.fcvtms }, .single, .double => .{ .fcvtzs = inst.fcvtzs }, }, 0b11100 => switch (inst.group.size) { .byte, .half => .{ .fcvtas = inst.fcvtas }, .single, .double => .unallocated, }, 0b11101 => switch (inst.group.size) { .byte, .half => .{ .scvtf = inst.scvtf }, .single, .double => .{ .frecpe = inst.frecpe }, }, 0b01100 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmgt = inst.fcmgt }, }, 0b01101 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmeq = inst.fcmeq }, }, 0b01110 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmlt = inst.fcmlt }, }, 0b01111 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fabs = inst.fabs }, }, }, .unsigned => switch (inst.group.opcode) { else => .unallocated, 0b00011 => .{ .usqadd = inst.usqadd }, 0b00111 => .{ .sqneg = inst.sqneg }, 0b01000 => .{ .cmge = inst.cmge }, 0b01001 => .{ .cmle = inst.cmle }, 0b01011 => .{ .neg = inst.neg }, 0b10010 => .{ .sqxtun = inst.sqxtun }, 0b10100 => .{ .uqxtn = inst.uqxtn }, 0b10110 => switch (inst.group.size) { .byte, .half => .{ .fcvtxn = inst.fcvtxn }, .single, .double => .unallocated, }, 0b11000 => switch (inst.group.size) { .byte, .half => .{ .frinta = inst.frinta }, .single, .double => .unallocated, }, 0b11001 => switch (inst.group.size) { .byte, .half => .{ .frintx = inst.frintx }, .single, .double => .{ .frinti = inst.frinti }, }, 0b11010 => switch (inst.group.size) { .byte, .half => .{ .fcvtnu = inst.fcvtnu }, .single, .double => .{ .fcvtpu = inst.fcvtpu }, }, 0b11011 => switch (inst.group.size) { .byte, .half => .{ .fcvtmu = inst.fcvtmu }, .single, .double => .{ .fcvtzu = inst.fcvtzu }, }, 0b11100 => switch (inst.group.size) { .byte, .half => .{ .fcvtau = inst.fcvtau }, .single, .double => .unallocated, }, 0b11101 => switch (inst.group.size) { .byte, .half => .{ .ucvtf = inst.ucvtf }, .single, .double => .{ .frsqrte = inst.frsqrte }, }, 0b00101 => switch (inst.group.size) { .byte => .{ .not = inst.not }, .half, .single, .double => .unallocated, }, 0b01100 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmge = inst.fcmge }, }, 0b01101 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fcmle = inst.fcmle }, }, 0b01111 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fneg = inst.fneg }, }, 0b11111 => switch (inst.group.size) { .byte, .half => .unallocated, .single, .double => .{ .fsqrt = inst.fsqrt }, }, }, }; } }; /// Advanced SIMD across lanes pub const SimdAcrossLanes = packed union { group: @This().Group, addv: Addv, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5, decoded17: u5 = 0b11000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.6 ADDV pub const Addv = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: u5 = 0b11011, decoded17: u5 = 0b11000, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; pub const Decoded = union(enum) { unallocated, addv: Addv, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.opcode) { else => .unallocated, 0b11011 => .{ .addv = inst.addv }, }, .unsigned => .unallocated, }; } }; /// Advanced SIMD three same pub const SimdThreeSame = packed union { group: @This().Group, addp: Addp, @"and": And, bic: Bic, orr: Orr, orn: Orn, eor: Eor, bsl: Bsl, bit: Bit, bif: Bif, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.5 ADDP (vector) pub const Addp = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b10111, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.11 AND (vector) pub const And = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .byte, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.21 BIC (vector, register) pub const Bic = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .half, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.213 ORR (vector, register) pub const Orr = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .single, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.211 ORN (vector) pub const Orn = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .double, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .signed, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.41 EOR (vector) pub const Eor = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .byte, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.24 BSL pub const Bsl = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .half, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.23 BIT pub const Bit = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .single, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; /// C7.2.22 BIF pub const Bif = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u1 = 0b1, opcode: u5 = 0b00011, Rm: Register.Encoded, decoded21: u1 = 0b1, size: Size = .double, decoded24: u5 = 0b01110, U: std.builtin.Signedness = .unsigned, Q: Q, decoded31: u1 = 0b0, }; pub const Decoded = union(enum) { unallocated, addp: Addp, @"and": And, bic: Bic, orr: Orr, orn: Orn, eor: Eor, bsl: Bsl, bit: Bit, bif: Bif, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.U) { .signed => switch (inst.group.opcode) { else => .unallocated, 0b10111 => .{ .addp = inst.addp }, 0b00011 => switch (inst.group.size) { .byte => .{ .@"and" = inst.@"and" }, .half => .{ .bic = inst.bic }, .single => .{ .orr = inst.orr }, .double => .{ .orn = inst.orn }, }, }, .unsigned => switch (inst.group.opcode) { else => .unallocated, 0b00011 => switch (inst.group.size) { .byte => .{ .eor = inst.eor }, .half => .{ .bsl = inst.bsl }, .single => .{ .bit = inst.bit }, .double => .{ .bif = inst.bif }, }, }, }; } }; /// 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, cmode: u4 = 0b1111, imm3: u3, decoded19: u10 = 0b0111100000, op: u1, 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, }; pub const Decoded = union(enum) { unallocated, fmov: Fmov, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.cmode) { else => .unallocated, 0b1111 => switch (inst.group.op) { 0b0 => .{ .fmov = inst.fmov }, 0b1 => switch (inst.group.Q) { .double => .unallocated, .quad => switch (inst.group.o2) { 0b1 => .unallocated, 0b0 => .{ .fmov = inst.fmov }, }, }, }, }; } }; /// Conversion between floating-point and fixed-point pub const ConvertFloatFixed = packed union { group: @This().Group, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, scale: u6, opcode: u3, rmode: u2, decoded21: u1 = 0b0, ptype: Ftype, decoded24: u5 = 0b11110, S: bool, decoded30: u1 = 0b0, sf: Register.GeneralSize, }; }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize, }; /// 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.GeneralSize = .word, }; pub const Rmode = enum(u2) { /// to nearest n = 0b00, /// toward plus infinity p = 0b01, /// toward minus infinity m = 0b10, /// toward zero z = 0b11, }; pub const Decoded = union(enum) { unallocated, 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 fn decode(inst: @This()) @This().Decoded { return switch (inst.group.S) { true => .unallocated, false => switch (inst.group.ptype) { .single, .double, .half => switch (inst.group.opcode) { 0b000 => switch (inst.group.rmode) { 0b00 => .{ .fcvtns = inst.fcvtns }, 0b01 => .{ .fcvtps = inst.fcvtps }, 0b10 => .{ .fcvtms = inst.fcvtms }, 0b11 => .{ .fcvtzs = inst.fcvtzs }, }, 0b001 => switch (inst.group.rmode) { 0b00 => .{ .fcvtnu = inst.fcvtnu }, 0b01 => .{ .fcvtpu = inst.fcvtpu }, 0b10 => .{ .fcvtmu = inst.fcvtmu }, 0b11 => .{ .fcvtzu = inst.fcvtzu }, }, 0b010 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .scvtf = inst.scvtf }, }, 0b011 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .ucvtf = inst.ucvtf }, }, 0b100 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .fcvtas = inst.fcvtas }, }, 0b101 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .fcvtau = inst.fcvtau }, }, 0b110 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .fmov = inst.fmov }, 0b11 => switch (inst.group.ptype) { .single, .double => .unallocated, .quad => unreachable, .half => .{ .fjcvtzs = inst.fjcvtzs }, }, }, 0b111 => switch (inst.group.rmode) { else => .unallocated, 0b00 => .{ .fmov = inst.fmov }, }, }, .quad => switch (inst.group.opcode) { else => .unallocated, 0b110, 0b111 => switch (inst.group.rmode) { else => .unallocated, 0b01 => switch (inst.group.sf) { .word => .unallocated, .doubleword => .{ .fmov = inst.fmov }, }, }, }, }, }; } }; /// 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, _, }; pub const Decoded = union(enum) { unallocated, 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 fn decode(inst: @This()) @This().Decoded { return switch (inst.group.M) { 0b0 => switch (inst.group.S) { true => .unallocated, false => switch (inst.group.ptype) { .single, .double, .half => switch (inst.group.opcode) { else => .unallocated, 0b000000 => .{ .fmov = inst.fmov }, 0b000001 => .{ .fabs = inst.fabs }, 0b000010 => .{ .fneg = inst.fneg }, 0b000011 => .{ .fsqrt = inst.fsqrt }, 0b000101, 0b000111 => .{ .fcvt = inst.fcvt }, 0b001000 => .{ .frintn = inst.frintn }, 0b001001 => .{ .frintp = inst.frintp }, 0b001010 => .{ .frintm = inst.frintm }, 0b001011 => .{ .frintz = inst.frintz }, 0b001100 => .{ .frinta = inst.frinta }, 0b001110 => .{ .frintx = inst.frintx }, 0b001111 => .{ .frinti = inst.frinti }, }, .quad => .unallocated, }, }, 0b1 => .unallocated, }; } }; /// 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: Imm8, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, pub const Imm8 = packed struct(u8) { mantissa: u4, exponent: i3, sign: std.math.Sign, pub const Modified = packed struct(u8) { imm5: u5, imm3: u3 }; pub fn fromModified(mod: Modified) Imm8 { return @bitCast(mod); } pub fn toModified(imm8: Imm8) Modified { return @bitCast(imm8); } pub fn decode(imm8: Imm8) f16 { const Normalized = std.math.FloatRepr(f16).Normalized; return Normalized.reconstruct(.{ .fraction = @as(Normalized.Fraction, imm8.mantissa) << 6, .exponent = @as(Normalized.Exponent, imm8.exponent) + 1, }, imm8.sign); } }; }; pub const Decoded = union(enum) { unallocated, fmov: Fmov, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.M) { 0b0 => switch (inst.group.S) { true => .unallocated, false => switch (inst.group.imm5) { else => .unallocated, 0b00000 => switch (inst.group.ptype) { .quad => .unallocated, .single, .double, .half => .{ .fmov = inst.fmov }, }, }, }, 0b1 => .unallocated, }; } }; /// Floating-point conditional compare pub const FloatConditionalCompare = packed union { group: @This().Group, pub const Group = packed struct { nzcv: Nzcv, op: u1, Rn: Register.Encoded, decoded10: u2 = 0b01, cond: ConditionCode, Rm: Register.Encoded, decoded21: u1 = 0b1, ptype: Ftype, decoded24: u5 = 0b11110, S: bool, decoded30: u1 = 0b0, M: u1, }; }; /// Floating-point data-processing (2 source) pub const FloatDataProcessingTwoSource = packed union { group: @This().Group, fmul: Fmul, fdiv: Fdiv, fadd: Fadd, fsub: Fsub, fmax: Fmax, fmin: Fmin, fmaxnm: Fmaxnm, fminnm: Fminnm, fnmul: Fnmul, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode, Rm: Register.Encoded, decoded21: u1 = 0b1, ptype: Ftype, decoded24: u5 = 0b11110, S: bool, decoded30: u1 = 0b0, M: u1, }; /// C7.2.136 FMUL (scalar) pub const Fmul = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fmul, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.98 FDIV (scalar) pub const Fdiv = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fdiv, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.50 FADD (scalar) pub const Fadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fadd, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.174 FSUB (scalar) pub const Fsub = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fsub, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.102 FMAX (scalar) pub const Fmax = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fmax, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.112 FMIN (scalar) pub const Fmin = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fmin, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.104 FMAXNM (scalar) pub const Fmaxnm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fmaxnm, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.114 FMINNM (scalar) pub const Fminnm = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fminnm, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.143 FNMUL (scalar) pub const Fnmul = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b10, opcode: Opcode = .fnmul, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; pub const Opcode = enum(u4) { fmul = 0b0000, fdiv = 0b0001, fadd = 0b0010, fsub = 0b0011, fmax = 0b0100, fmin = 0b0101, fmaxnm = 0b0110, fminnm = 0b0111, fnmul = 0b1000, _, }; }; /// Floating-point conditional select pub const FloatConditionalSelect = packed union { group: @This().Group, fcsel: Fcsel, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b11, cond: ConditionCode, Rm: Register.Encoded, decoded21: u1 = 0b1, ptype: Ftype, decoded24: u5 = 0b11110, S: bool, decoded30: u1 = 0b0, M: u1, }; /// C7.2.68 FCSEL pub const Fcsel = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, decoded10: u2 = 0b11, cond: ConditionCode, Rm: Register.Encoded, decoded21: u1 = 0b1, ftype: Ftype, decoded24: u5 = 0b11110, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; pub const Decoded = union(enum) { unallocated, fcsel: Fcsel, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.ptype) { .quad => .unallocated, .single, .double, .half => switch (inst.group.S) { true => .unallocated, false => switch (inst.group.M) { 0b0 => .{ .fcsel = inst.fcsel }, 0b1 => .unallocated, }, }, }; } }; /// Floating-point data-processing (3 source) pub const FloatDataProcessingThreeSource = packed union { group: @This().Group, fmadd: Fmadd, fmsub: Fmsub, fnmadd: Fnmadd, fnmsub: Fnmsub, pub const Group = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp, Rm: Register.Encoded, o1: u1, ptype: Ftype, decoded24: u5 = 0b11111, S: bool, decoded30: u1 = 0b0, M: u1, }; /// C7.2.100 FMADD pub const Fmadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .add, Rm: Register.Encoded, o1: O1 = .fm, ftype: Ftype, decoded24: u5 = 0b11111, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.133 FMSUB pub const Fmsub = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .sub, Rm: Register.Encoded, o1: O1 = .fm, ftype: Ftype, decoded24: u5 = 0b11111, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.141 FNMADD pub const Fnmadd = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .add, Rm: Register.Encoded, o1: O1 = .fnm, ftype: Ftype, decoded24: u5 = 0b11111, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; /// C7.2.142 FNMSUB pub const Fnmsub = packed struct { Rd: Register.Encoded, Rn: Register.Encoded, Ra: Register.Encoded, o0: AddSubtractOp = .sub, Rm: Register.Encoded, o1: O1 = .fnm, ftype: Ftype, decoded24: u5 = 0b11111, S: bool = false, decoded30: u1 = 0b0, M: u1 = 0b0, }; pub const O1 = enum(u1) { fm = 0b0, fnm = 0b1, }; }; pub const Size = enum(u2) { byte = 0b00, half = 0b01, single = 0b10, double = 0b11, pub fn n(s: Size) Size { return @enumFromInt(@intFromEnum(s) - 1); } pub fn w(s: Size) Size { return @enumFromInt(@intFromEnum(s) + 1); } pub fn toScalarSize(s: Size) Register.ScalarSize { return switch (s) { .byte => .byte, .half => .half, .single => .single, .double => .double, }; } pub fn fromScalarSize(ss: Register.ScalarSize) Size { return switch (ss) { else => unreachable, .byte => .byte, .half => .half, .single => .single, .double => .double, }; } pub fn toSz(s: Size) Sz { return switch (s) { else => unreachable, .single => .single, .double => .double, }; } }; pub const Sz = enum(u1) { single = 0b0, double = 0b1, pub fn toScalarSize(sz: Sz) Register.ScalarSize { return switch (sz) { .single => .single, .double => .double, }; } pub fn fromScalarSize(ss: Register.ScalarSize) Sz { return switch (ss) { else => unreachable, .single => .single, .double => .double, }; } pub fn toSize(sz: Sz) Size { return switch (sz) { .single => .single, .double => .double, }; } }; pub const Q = enum(u1) { double = 0b0, quad = 0b1, }; pub const Ftype = enum(u2) { single = 0b00, double = 0b01, quad = 0b10, half = 0b11, pub fn toScalarSize(ftype: Ftype) Register.ScalarSize { return switch (ftype) { .single => .single, .double => .double, .quad => .quad, .half => .half, }; } pub fn fromScalarSize(ss: Register.ScalarSize) Ftype { return switch (ss) { else => unreachable, .single => .single, .double => .double, .quad => .quad, .half => .half, }; } }; pub const Decoded = union(enum) { unallocated, simd_scalar_copy: SimdScalarCopy, simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16, simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous, simd_scalar_pairwise: SimdScalarPairwise, simd_copy: SimdCopy, simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16, simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous, simd_across_lanes: SimdAcrossLanes, simd_three_same: SimdThreeSame, simd_modified_immediate: SimdModifiedImmediate, convert_float_fixed: ConvertFloatFixed, convert_float_integer: ConvertFloatInteger, float_data_processing_one_source: FloatDataProcessingOneSource, float_compare: FloatCompare, float_immediate: FloatImmediate, float_conditional_compare: FloatConditionalCompare, float_data_processing_two_source: FloatDataProcessingTwoSource, float_conditional_select: FloatConditionalSelect, float_data_processing_three_source: FloatDataProcessingThreeSource, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op0) { else => .unallocated, 0b0101, 0b0111 => switch (inst.group.op1) { 0b00...0b01 => if (inst.group.op3 & 0b000100001 == 0b000000001) if (inst.group.op1 == 0b00 and inst.group.op2 & 0b1100 == 0b0000) .{ .simd_scalar_copy = inst.simd_scalar_copy } else .unallocated else if (inst.group.op3 & 0b110000011 == 0b000000010) switch (inst.group.op2) { else => .unallocated, 0b1111 => .{ .simd_scalar_two_register_miscellaneous_fp16 = inst.simd_scalar_two_register_miscellaneous_fp16 }, 0b0100, 0b1100 => .{ .simd_scalar_two_register_miscellaneous = inst.simd_scalar_two_register_miscellaneous }, 0b0110, 0b1110 => .{ .simd_scalar_pairwise = inst.simd_scalar_pairwise }, } else .unallocated, 0b10, 0b11 => switch (@as(u1, @truncate(inst.group.op3 >> 0))) { 0b1 => switch (inst.group.op1) { 0b10 => .unallocated, else => .unallocated, }, 0b0 => .unallocated, }, }, 0b0000, 0b0010, 0b0100, 0b0110 => if (inst.group.op1 == 0b00 and inst.group.op2 & 0b1100 == 0b0000 and inst.group.op3 & 0b000100001 == 0b0000000001) .{ .simd_copy = inst.simd_copy } else if (inst.group.op1 & 0b10 == 0b00 and inst.group.op2 == 0b1111 and inst.group.op3 & 0b110000011 == 0b000000010) .{ .simd_two_register_miscellaneous_fp16 = inst.simd_two_register_miscellaneous_fp16 } else if (inst.group.op1 & 0b10 == 0b00 and inst.group.op2 & 0b0111 == 0b0100 and inst.group.op3 & 0b110000011 == 0b000000010) .{ .simd_two_register_miscellaneous = inst.simd_two_register_miscellaneous } else if (inst.group.op1 & 0b10 == 0b00 and inst.group.op2 & 0b0111 == 0b0110 and inst.group.op3 & 0b110000011 == 0b000000010) .{ .simd_across_lanes = inst.simd_across_lanes } else if (inst.group.op1 & 0b10 == 0b00 and inst.group.op2 & 0b0100 == 0b0100 and inst.group.op3 & 0b000000001 == 0b000000001) .{ .simd_three_same = inst.simd_three_same } else if (inst.group.op1 == 0b10 and inst.group.op2 == 0b0000 and inst.group.op3 & 0b000000001 == 0b000000001) .{ .simd_modified_immediate = inst.simd_modified_immediate } else .unallocated, 0b0001, 0b0011, 0b1001, 0b1011 => switch (@as(u1, @truncate(inst.group.op1 >> 1))) { 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 2))) { 0b0 => .{ .convert_float_fixed = inst.convert_float_fixed }, 0b1 => switch (@ctz(inst.group.op3)) { else => .{ .convert_float_integer = inst.convert_float_integer }, 4 => .{ .float_data_processing_one_source = inst.float_data_processing_one_source }, 3 => .{ .float_compare = inst.float_compare }, 2 => .{ .float_immediate = inst.float_immediate }, 1 => .{ .float_data_processing_two_source = inst.float_data_processing_two_source }, 0 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) { 0b0 => .unallocated, 0b1 => .{ .float_conditional_select = inst.float_conditional_select }, }, }, }, 0b1 => .unallocated, }, }; } }; pub const AddSubtractOp = enum(u1) { add = 0b0, sub = 0b1, }; pub const LogicalOpc = enum(u2) { @"and" = 0b00, orr = 0b01, eor = 0b10, ands = 0b11, }; pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool }; pub const Decoded = union(enum) { unallocated, reserved: Reserved, sme: Sme, sve: Sve, data_processing_immediate: DataProcessingImmediate, branch_exception_generating_system: BranchExceptionGeneratingSystem, load_store: LoadStore, data_processing_register: DataProcessingRegister, data_processing_vector: DataProcessingVector, }; pub fn decode(inst: @This()) @This().Decoded { return switch (inst.group.op1) { 0b0000 => switch (inst.group.op0) { 0b0 => .{ .reserved = inst.reserved }, 0b1 => .{ .sme = inst.sme }, }, 0b0001 => .unallocated, 0b0010 => .{ .sve = inst.sve }, 0b0011 => .unallocated, 0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate }, 0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system }, 0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store }, 0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register }, 0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector }, }; } /// C7.2.1 ABS pub fn abs(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .abs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .abs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, } } /// C6.2.1 ADC pub fn adc(d: Register, n: Register, m: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf); form: switch (form) { .extended_register_explicit => |extended_register_explicit| { assert(extended_register_explicit.register.format.general == switch (sf) { .word => .word, .doubleword => 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.general == 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.6 ADDG pub fn addg(d: Register, n: Register, uimm6: u10, uimm4: u4) Instruction { assert(d.format.general == .doubleword and n.format.general == .doubleword); return .{ .data_processing_immediate = .{ .add_subtract_immediate_with_tags = .{ .addg = .{ .Xd = d.alias.encode(.{ .sp = true }), .Xn = n.alias.encode(.{ .sp = true }), .uimm4 = uimm4, .uimm6 = @intCast(@shrExact(uimm6, 4)), }, } } }; } /// 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.general; assert(n.format.general == sf); form: switch (form) { .extended_register_explicit => |extended_register_explicit| { assert(extended_register_explicit.register.format.general == switch (sf) { .word => .word, .doubleword => 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.general == 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().toScalarSize()); 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.general == .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.general == .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, .general => |sf| { assert(n.format.general == 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.general == 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.general; assert(n.format.general == 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.general == 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.general; assert(n.format.general == sf and m.format.general == 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.24 AXFLAG pub fn axflag() Instruction { return .{ .branch_exception_generating_system = .{ .pstate = .{ .axflag = .{}, } } }; } /// 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.general; assert(n.format.general == 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, .general => |sf| { assert(n.format.general == 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.general == 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.general; assert(n.format.general == sf); form: switch (form) { .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, .shifted_register_explicit => |shifted_register_explicit| { assert(shifted_register_explicit.register.format.general == sf); return .{ .data_processing_register = .{ .logical_shifted_register = .{ .bics = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .imm6 = switch (sf) { .word => @as(u5, @intCast(shifted_register_explicit.amount)), .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), }, .Rm = shifted_register_explicit.register.alias.encode(.{}), .shift = shifted_register_explicit.shift, .sf = sf, }, } } }; }, .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ .register = shifted_register.register, .shift = shifted_register.shift, .amount = switch (shifted_register.shift) { .lsl, .lsr, .asr, .ror => |amount| amount, }, } }, } } /// C7.2.22 BIF pub fn bif(d: Register, n: Register, m: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_three_same = .{ .bif = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }; } /// C7.2.23 BIT pub fn bit(d: Register, n: Register, m: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_three_same = .{ .bit = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }; } /// C7.2.24 BSL pub fn bsl(d: Register, n: Register, m: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_three_same = .{ .bsl = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }; } /// C6.2.34 BL pub fn bl(label: i28) Instruction { return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{ .bl = .{ .imm26 = @intCast(@shrExact(label, 2)) }, } } }; } /// C6.2.35 BLR pub fn blr(n: Register) Instruction { assert(n.format.general == .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.general == .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.general, }, } } }; } /// 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.general, }, } } }; } /// C6.2.48 CCMN (immediate) /// C6.2.49 CCMN (register) pub fn ccmn( n: Register, form: union(enum) { register: Register, immediate: u5 }, nzcv: Nzcv, cond: ConditionCode, ) Instruction { const sf = n.format.general; switch (form) { .register => |m| { assert(m.format.general == 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: Nzcv, cond: ConditionCode, ) Instruction { const sf = n.format.general; switch (form) { .register => |m| { assert(m.format.general == 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.52 CFINV pub fn cfinv() Instruction { return .{ .branch_exception_generating_system = .{ .pstate = .{ .cfinv = .{}, } } }; } /// C6.2.56 CLREX pub fn clrex(imm: u4) Instruction { return .{ .branch_exception_generating_system = .{ .barriers = .{ .clrex = .{ .CRm = imm, }, } } }; } /// C6.2.57 CLS pub fn cls(d: Register, n: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf); return .{ .data_processing_register = .{ .data_processing_one_source = .{ .cls = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .sf = sf, }, } } }; } /// C6.2.58 CLZ pub fn clz(d: Register, n: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf); return .{ .data_processing_register = .{ .data_processing_one_source = .{ .clz = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .sf = sf, }, } } }; } /// C7.2.28 CMEQ (zero) pub fn cmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .cmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, }, } } /// C7.2.30 CMGE (zero) pub fn cmge(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .cmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, }, } } /// C7.2.32 CMGT (zero) pub fn cmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .cmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, }, } } /// C7.2.35 CMLE (zero) pub fn cmle(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .cmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, }, } } /// C7.2.36 CMLT (zero) pub fn cmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .cmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, }, } } /// C7.2.38 CNT pub fn cnt(d: Register, n: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.elemSize() == .byte and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .cnt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; } /// C6.2.103 CSEL pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { const sf = d.format.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == sf); return .{ .data_processing_register = .{ .conditional_select = .{ .csneg = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .cond = cond, .Rm = m.alias.encode(.{}), .sf = sf, }, } } }; } /// C6.2.110 DCPS1 pub fn dcps1(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .dcps1 = .{ .imm16 = imm }, } } }; } /// C6.2.111 DCPS2 pub fn dcps2(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .dcps2 = .{ .imm16 = imm }, } } }; } /// C6.2.112 DCPS3 pub fn dcps3(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .dcps3 = .{ .imm16 = imm }, } } }; } /// C6.2.116 DSB pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction { return .{ .branch_exception_generating_system = .{ .barriers = .{ .dsb = .{ .CRm = option, }, } } }; } /// C7.2.39 DUP (element) /// C7.2.40 DUP (general) pub fn dup(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(@intFromEnum(elem_size) <= @intFromEnum(Register.ScalarSize.double) and elem_size == n.format.element.size); return .{ .data_processing_vector = .{ .simd_scalar_copy = .{ .dup = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .imm5 = @shlExact(@as(u5, n.format.element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d"); const elem_size = arrangement.elemSize(); switch (n.format) { else => unreachable, .element => |element| { assert(elem_size.toScalarSize() == element.size); return .{ .data_processing_vector = .{ .simd_copy = .{ .dup = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .imm4 = .element, .imm5 = @shlExact(@as(u5, element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)), .Q = arrangement.size(), }, } } }; }, .general => |sf| { assert(sf == @as(Register.GeneralSize, switch (elem_size) { .byte, .half, .single => .word, .double => .doubleword, })); return .{ .data_processing_vector = .{ .simd_copy = .{ .dup = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{}), .imm4 = .general, .imm5 = @shlExact(@as(u5, 0b1), @intFromEnum(elem_size)), .Q = arrangement.size(), }, } } }; }, } }, } } /// C6.2.118 EON (shifted register) pub fn eon(d: Register, n: Register, form: union(enum) { register: Register, shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, }) Instruction { const sf = d.format.general; assert(n.format.general == sf); form: switch (form) { .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, .shifted_register_explicit => |shifted_register_explicit| { assert(shifted_register_explicit.register.format.general == 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, .general => |sf| { assert(n.format.general == 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.general == 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.general; assert(n.format.general == sf and m.format.general == sf); return .{ .data_processing_immediate = .{ .extract = .{ .extr = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .imms = switch (sf) { .word => @as(u5, @intCast(lsb)), .doubleword => @as(u6, @intCast(lsb)), }, .Rm = m.alias.encode(.{}), .N = sf, .sf = sf, }, } } }; } /// C7.2.45 FABS (vector) /// C7.2.46 FABS (scalar) pub fn fabs(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fabs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fabs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .fabs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.50 FADD (scalar) pub fn fadd(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fadd = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.57 FCMEQ (zero) pub fn fcmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |n_scalar| { assert(n_scalar == ftype); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcmeq = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, }, } } /// C7.2.59 FCMGE (zero) pub fn fcmge(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |n_scalar| { assert(n_scalar == ftype); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcmge = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, }, } } /// C7.2.61 FCMGT (zero) pub fn fcmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |n_scalar| { assert(n_scalar == ftype); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcmgt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, }, } } /// C7.2.64 FCMLE (zero) pub fn fcmle(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |n_scalar| { assert(n_scalar == ftype); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcmle = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, }, } } /// C7.2.65 FCMLT (zero) pub fn fcmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction { switch (form) { .zero => switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |n_scalar| { assert(n_scalar == ftype); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcmlt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, }, } } /// C7.2.66 FCMP pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction { const ftype = n.format.scalar; switch (form) { .register => |m| { assert(m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_compare = .{ .fcmp = .{ .opc0 = .register, .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, .zero => return .{ .data_processing_vector = .{ .float_compare = .{ .fcmp = .{ .opc0 = .register, .Rn = n.alias.encode(.{ .V = true }), .Rm = @enumFromInt(0b00000), .ftype = .fromScalarSize(ftype), }, } } }, } } /// C7.2.67 FCMPE pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction { const ftype = n.format.scalar; switch (form) { .register => |m| { assert(m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_compare = .{ .fcmpe = .{ .opc0 = .zero, .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, .zero => return .{ .data_processing_vector = .{ .float_compare = .{ .fcmpe = .{ .opc0 = .zero, .Rn = n.alias.encode(.{ .V = true }), .Rm = @enumFromInt(0b00000), .ftype = .fromScalarSize(ftype), }, } } }, } } /// C7.2.68 FCSEL pub fn fcsel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_conditional_select = .{ .fcsel = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .cond = cond, .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.69 FCVT pub fn fcvt(d: Register, n: Register) Instruction { assert(d.format.scalar != n.format.scalar); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .fcvt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .opc = switch (d.format.scalar) { else => unreachable, .single => .single, .double => .double, .half => .half, }, .ftype = .fromScalarSize(n.format.scalar), }, } } }; } /// C7.2.70 FCVTAS (vector) /// C7.2.71 FCVTAS (scalar) pub fn fcvtas(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtas = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtas = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtas = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtas = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtas = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.72 FCVTAU (vector) /// C7.2.73 FCVTAU (scalar) pub fn fcvtau(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtau = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtau = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtau = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtau = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtau = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.75 FCVTMS (vector) /// C7.2.76 FCVTMS (scalar) pub fn fcvtms(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtms = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtms = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtms = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtms = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtms = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.77 FCVTMU (vector) /// C7.2.78 FCVTMU (scalar) pub fn fcvtmu(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtmu = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtmu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtmu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtmu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtmu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.80 FCVTNS (vector) /// C7.2.81 FCVTNS (scalar) pub fn fcvtns(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtns = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtns = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtns = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtns = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtns = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.82 FCVTNU (vector) /// C7.2.83 FCVTNU (scalar) pub fn fcvtnu(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtnu = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtnu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtnu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtnu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtnu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.84 FCVTPS (vector) /// C7.2.85 FCVTPS (scalar) pub fn fcvtps(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtps = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtps = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtps = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtps = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtps = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.86 FCVTPU (vector) /// C7.2.87 FCVTPU (scalar) pub fn fcvtpu(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtpu = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtpu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtpu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtpu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtpu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.90 FCVTZS (vector, integer) /// C7.2.92 FCVTZS (scalar, integer) pub fn fcvtzs(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtzs = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtzs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtzs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtzs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtzs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.94 FCVTZU (vector, integer) /// C7.2.96 FCVTZU (scalar, integer) pub fn fcvtzu(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fcvtzu = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(n.format.scalar), .sf = sf, }, } } }, .scalar => |elem_size| switch (n.format) { else => unreachable, .scalar => |ftype| { assert(ftype == elem_size); switch (elem_size) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .fcvtzu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .fcvtzu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(elem_size), }, } } }, } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fcvtzu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fcvtzu = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C7.2.98 FDIV (scalar) pub fn fdiv(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fdiv = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.99 FJCVTZS pub fn fjcvtzs(d: Register, n: Register) Instruction { assert(d.format.general == .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 = .fromScalarSize(ftype), }, } } }; } /// C7.2.102 FMAX (scalar) pub fn fmax(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fmax = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.104 FMAXNM (scalar) pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fmaxnm = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.112 FMIN (scalar) pub fn fmin(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fmin = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.114 FMINNM (scalar) pub fn fminnm(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fminnm = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.129 FMOV (vector, immediate) /// C7.2.130 FMOV (register) /// C7.2.131 FMOV (general) /// C7.2.132 FMOV (scalar, immediate) pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction { switch (form) { .immediate => |immediate| { const repr: std.math.FloatRepr(f16) = @bitCast(immediate); const imm: DataProcessingVector.FloatImmediate.Fmov.Imm8 = .{ .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 = .fromScalarSize(ftype), }, } } }, .vector => |arrangement| { const elem_size = arrangement.elemSize(); assert(arrangement.len() > 1); const mod_imm = imm.toModified(); return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ .fmov = .{ .Rd = d.alias.encode(.{ .V = true }), .imm5 = mod_imm.imm5, .o2 = switch (elem_size) { .byte => unreachable, .half => 0b1, .single, .double => 0b0, }, .imm3 = mod_imm.imm3, .op = switch (elem_size) { .byte => unreachable, .half, .single => 0b0, .double => 0b1, }, .Q = arrangement.size(), }, } } }; }, } }, .register => |n| switch (d.format) { else => unreachable, .general => |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 = .fromScalarSize(ftype), .sf = sf, }, } } }; }, .element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .fmov = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{ .V = true }), .opcode = .float_to_integer, .rmode = switch (element.index) { else => unreachable, 1 => .@"1", }, .ftype = switch (element.size) { else => unreachable, .double => .quad, }, .sf = sf, }, } } }, }, .scalar => |ftype| switch (n.format) { else => unreachable, .general => |sf| { 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 = .fromScalarSize(ftype), .sf = sf, }, } } }; }, .scalar => { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .fmov = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, }, .element => |element| switch (n.format) { else => unreachable, .general => |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 = .fromScalarSize(ftype), }, } } }; } /// C7.2.136 FMUL (scalar) pub fn fmul(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fmul = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.139 FNEG (vector) /// C7.2.140 FNEG (scalar) pub fn fneg(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fneg = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fneg = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .fneg = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.141 FNMADD pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ .fnmadd = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .Ra = a.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.142 FNMSUB pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ .fnmsub = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .Ra = a.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.143 FNMUL (scalar) pub fn fnmul(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fnmul = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C7.2.155 FRINTA (vector) /// C7.2.156 FRINTA (scalar) pub fn frinta(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frinta = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frinta = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frinta = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.157 FRINTI (vector) /// C7.2.158 FRINTI (scalar) pub fn frinti(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frinti = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frinti = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frinti = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.159 FRINTM (vector) /// C7.2.160 FRINTM (scalar) pub fn frintm(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frintm = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frintm = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frintm = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.161 FRINTN (vector) /// C7.2.162 FRINTN (scalar) pub fn frintn(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frintn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frintn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frintn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.163 FRINTP (vector) /// C7.2.164 FRINTP (scalar) pub fn frintp(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frintp = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frintp = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frintp = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.165 FRINTX (vector) /// C7.2.166 FRINTX (scalar) pub fn frintx(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frintx = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frintx = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frintx = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.167 FRINTZ (vector) /// C7.2.168 FRINTZ (scalar) pub fn frintz(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .frintz = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .frintz = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .frintz = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.171 FSQRT (vector) /// C7.2.172 FSQRT (scalar) pub fn fsqrt(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .vector => |arrangement| { assert(n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .fsqrt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .fsqrt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, .scalar => |ftype| { assert(n.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ .fsqrt = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; }, } } /// C7.2.174 FSUB (scalar) pub fn fsub(d: Register, n: Register, m: Register) Instruction { const ftype = d.format.scalar; assert(n.format.scalar == ftype and m.format.scalar == ftype); return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ .fsub = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Rm = m.alias.encode(.{ .V = true }), .ftype = .fromScalarSize(ftype), }, } } }; } /// C6.2.126 HINT pub fn hint(imm: u7) Instruction { return .{ .branch_exception_generating_system = .{ .hints = .{ .group = .{ .op2 = @truncate(imm >> 0), .CRm = @intCast(imm >> 3), }, } } }; } /// C6.2.127 HLT pub fn hlt(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .hlt = .{ .imm16 = imm }, } } }; } /// C6.2.128 HVC pub fn hvc(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .hvc = .{ .imm16 = imm }, } } }; } /// C7.2.175 INS (element) /// C7.2.176 INS (general) pub fn ins(d: Register, n: Register) Instruction { const elem_size = d.format.element.size; switch (n.format) { else => unreachable, .element => |element| { assert(elem_size == element.size); return .{ .data_processing_vector = .{ .simd_copy = .{ .ins = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .imm4 = .{ .element = element.index << @intCast(@intFromEnum(elem_size)) }, .imm5 = (@as(u5, d.format.element.index) << 1 | @as(u5, 0b1) << 0) << @intFromEnum(elem_size), .op = .element, }, } } }; }, .general => |general| { assert(general == @as(Register.GeneralSize, switch (elem_size) { else => unreachable, .byte, .half, .single => .word, .double => .doubleword, })); return .{ .data_processing_vector = .{ .simd_copy = .{ .ins = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{}), .imm4 = .{ .general = .general }, .imm5 = (@as(u5, d.format.element.index) << 1 | @as(u5, 0b1) << 0) << @intFromEnum(elem_size), .op = .general, }, } } }; }, } } /// 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, .general => |sf| { assert(t2.format.general == sf); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ .ldp = .{ .Rt = t1.alias.encode(.{}), .Rn = post_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .pre_index => |pre_index| { assert(pre_index.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ .ldp = .{ .Rt = t1.alias.encode(.{}), .Rn = pre_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .signed_offset => |signed_offset| { assert(signed_offset.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ .ldp = .{ .Rt = t1.alias.encode(.{}), .Rn = signed_offset.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, } }, .scalar => |vs| { assert(t2.format.scalar == vs); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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, .general => |sf| form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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) { .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.general == .word); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.general == .word); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.general; form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.general; form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.Option, amount: LoadStore.RegisterRegisterOffset.Extend.Amount, }, extended_register: struct { base: Register, index: Register, extend: LoadStore.RegisterRegisterOffset.Extend, }, }) Instruction { assert(t.format.general == .doubleword); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .doubleword); return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ .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.general == .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.general == .doubleword); return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ .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 = .{ .integer = .{ .ldrsw = .{ .Rt = t.alias.encode(.{}), .imm19 = @intCast(@shrExact(offset, 2)), }, } } } }, .extended_register_explicit => |extended_register_explicit| { assert(extended_register_explicit.base.format.general == .doubleword and extended_register_explicit.index.format.general == 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 => false, 2 => 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.202 LDUR /// C7.2.194 LDUR (SIMD&FP) pub fn ldur(t: Register, n: Register, simm: i9) Instruction { assert(n.format.general == .doubleword); switch (t.format) { else => unreachable, .general => |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.general == .word and n.format.general == .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.general == .word and n.format.general == .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.general == .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.general), }, } } } }; } /// C6.2.206 LDURSH pub fn ldursh(t: Register, n: Register, simm: i9) Instruction { assert(n.format.general == .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.general), }, } } } }; } /// C6.2.207 LDURSW pub fn ldursw(t: Register, n: Register, simm: i9) Instruction { assert(t.format.general == .doubleword and n.format.general == .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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == sf and a.format.general == 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.general; 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.general; 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.general; assert(sf == .doubleword or shift.lsl.sf() == .word); return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ .movz = .{ .Rd = d.alias.encode(.{}), .imm16 = imm, .hw = shift.lsl, .sf = sf, }, } } }; } /// C6.2.228 MRS pub fn mrs(t: Register, systemreg: Register.System) Instruction { assert(t.format.general == .doubleword and systemreg.op0 >= 0b10); return .{ .branch_exception_generating_system = .{ .system_register_move = .{ .mrs = .{ .Rt = t.alias.encode(.{}), .systemreg = systemreg, }, } } }; } /// C6.2.230 MSR (register) pub fn msr(systemreg: Register.System, t: Register) Instruction { assert(systemreg.op0 >= 0b10 and t.format.general == .doubleword); return .{ .branch_exception_generating_system = .{ .system_register_move = .{ .msr = .{ .Rt = t.alias.encode(.{}), .systemreg = systemreg, }, } } }; } /// C6.2.231 MSUB pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf and m.format.general == sf and a.format.general == sf); return .{ .data_processing_register = .{ .data_processing_three_source = .{ .msub = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .Ra = a.alias.encode(.{}), .Rm = m.alias.encode(.{}), .sf = sf, }, } } }; } /// C7.2.209 NEG (vector) pub fn neg(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == .double and elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .neg = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .neg = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, } } /// C6.2.238 NOP pub fn nop() Instruction { return .{ .branch_exception_generating_system = .{ .hints = .{ .nop = .{}, } } }; } /// C7.2.210 NOT pub fn not(d: Register, n: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.elemSize() == .byte and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .not = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; } /// C6.2.239 ORN (shifted register) /// C7.2.211 ORN (vector) pub fn orn(d: Register, n: Register, form: union(enum) { register: Register, shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, }) Instruction { switch (d.format) { else => unreachable, .general => |sf| { assert(n.format.general == sf); form: switch (form) { .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, .shifted_register_explicit => |shifted_register_explicit| { assert(shifted_register_explicit.register.format.general == 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, .general => |sf| { assert(n.format.general == 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.general == 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.general == .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.general == .doubleword and extended_register_explicit.index.format.general == 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.general; assert(n.format.general == 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.general == .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.general; assert(n.format.general == 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.general; assert(n.format.general == 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.general == .doubleword and n.format.general == .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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and m.format.general == 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.general; assert(n.format.general == sf and bitmask.validBitfield(sf)); return .{ .data_processing_immediate = .{ .bitfield = .{ .sbfm = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .imm = bitmask, .sf = sf, }, } } }; } /// C7.2.234 SCVTF (vector, integer) /// C7.2.236 SCVTF (scalar, integer) pub fn scvtf(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |elem_size| { assert(ftype == elem_size); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .scvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .scvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .scvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{}), .ftype = .fromScalarSize(ftype), .sf = sf, }, } } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .scvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .scvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C6.2.270 SDIV pub fn sdiv(d: Register, n: Register, m: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf and m.format.general == 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.general == .doubleword and n.format.general == .word and m.format.general == .word and a.format.general == .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.general; 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.general == .doubleword and n.format.general == .word and m.format.general == .word and a.format.general == .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.general == .doubleword and n.format.general == .doubleword and m.format.general == .doubleword); return .{ .data_processing_register = .{ .data_processing_three_source = .{ .smulh = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .Rm = m.alias.encode(.{}), }, } } }; } /// C7.2.282 SQABS pub fn sqabs(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .sqabs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .sqabs = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, } } /// C7.2.308 SQXTN pub fn sqxtn(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == n.format.scalar.n()); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .sqxtn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement.len() == n.format.vector.len() and arrangement.elemSize() == n.format.vector.elemSize().n()); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .sqxtn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, } } /// C7.2.308 SQXTN2 pub fn sqxtn2(d: Register, n: Register) Instruction { const arrangement = d.format.vector; assert(arrangement.len() == n.format.vector.len() * 2 and arrangement.elemSize() == n.format.vector.elemSize().n()); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .sqxtn = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; } /// C6.2.321 STP /// C7.2.330 STP (SIMD&FP) pub fn stp(t1: Register, t2: Register, form: union(enum) { post_index: struct { base: Register, index: i10 }, pre_index: struct { base: Register, index: i10 }, signed_offset: struct { base: Register, offset: i10 = 0 }, base: Register, }) Instruction { switch (t1.format) { else => unreachable, .general => |sf| { assert(t2.format.general == sf); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ .stp = .{ .Rt = t1.alias.encode(.{}), .Rn = post_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .pre_index => |pre_index| { assert(pre_index.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ .stp = .{ .Rt = t1.alias.encode(.{}), .Rn = pre_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .signed_offset => |signed_offset| { assert(signed_offset.base.format.general == .doubleword); return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ .stp = .{ .Rt = t1.alias.encode(.{}), .Rn = signed_offset.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, } }, .scalar => |vs| { assert(t2.format.scalar == vs); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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, .general => |sf| form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .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.general == .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.general == .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.general == .word); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .word); form: switch (form) { .post_index => |post_index| { assert(post_index.base.format.general == .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.general == .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.general == .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.general == .doubleword); switch (t.format) { else => unreachable, .general => |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.general == .word and n.format.general == .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.general == .word and n.format.general == .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.general; assert(n.format.general == sf); form: switch (form) { .extended_register_explicit => |extended_register_explicit| { assert(extended_register_explicit.register.format.general == switch (sf) { .word => .word, .doubleword => 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.general == 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, }, } }, } } /// C7.2.359 SUBG pub fn subg(d: Register, n: Register, uimm6: u10, uimm4: u4) Instruction { assert(d.format.general == .doubleword and n.format.general == .doubleword); return .{ .data_processing_immediate = .{ .add_subtract_immediate_with_tags = .{ .subg = .{ .Xd = d.alias.encode(.{ .sp = true }), .Xn = n.alias.encode(.{ .sp = true }), .uimm4 = uimm4, .uimm6 = @intCast(@shrExact(uimm6, 4)), }, } } }; } /// 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.general; assert(n.format.general == sf); form: switch (form) { .extended_register_explicit => |extended_register_explicit| { assert(extended_register_explicit.register.format.general == switch (sf) { .word => .word, .doubleword => 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.general == sf); return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ .subs = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .imm6 = switch (sf) { .word => @as(u5, @intCast(shifted_register_explicit.amount)), .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), }, .Rm = shifted_register_explicit.register.alias.encode(.{}), .shift = switch (shifted_register_explicit.shift) { .lsl, .lsr, .asr => |shift| shift, .ror => unreachable, }, .sf = sf, }, } } }; }, .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ .register = shifted_register.register, .shift = shifted_register.shift, .amount = switch (shifted_register.shift) { .lsl, .lsr, .asr => |amount| amount, .ror => unreachable, }, } }, } } /// C7.2.337 SUQADD pub fn suqadd(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |elem_size| { assert(elem_size == n.format.scalar); return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .suqadd = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = .fromScalarSize(elem_size), }, } } }; }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .suqadd = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .size = arrangement.elemSize(), .Q = arrangement.size(), }, } } }; }, } } /// C6.2.365 SVC pub fn svc(imm: u16) Instruction { return .{ .branch_exception_generating_system = .{ .exception_generating = .{ .svc = .{ .imm16 = imm }, } } }; } /// C6.2.372 SYS pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction { assert(t.format.general == .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.general == .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.general) { .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.general) { .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.general; assert(n.format.general == sf and bitmask.validBitfield(sf)); return .{ .data_processing_immediate = .{ .bitfield = .{ .ubfm = .{ .Rd = d.alias.encode(.{}), .Rn = n.alias.encode(.{}), .imm = bitmask, .sf = sf, }, } } }; } /// C7.2.353 UCVTF (vector, integer) /// C7.2.355 UCVTF (scalar, integer) pub fn ucvtf(d: Register, n: Register) Instruction { switch (d.format) { else => unreachable, .scalar => |ftype| switch (n.format) { else => unreachable, .scalar => |elem_size| { assert(ftype == elem_size); switch (ftype) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{ .ucvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{ .ucvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = .fromScalarSize(ftype), }, } } }, } }, .general => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ .ucvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{}), .ftype = .fromScalarSize(ftype), .sf = sf, }, } } }, }, .vector => |arrangement| { assert(arrangement != .@"1d" and n.format.vector == arrangement); switch (arrangement.elemSize()) { else => unreachable, .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{ .ucvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .Q = arrangement.size(), }, } } }, .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ .ucvtf = .{ .Rd = d.alias.encode(.{ .V = true }), .Rn = n.alias.encode(.{ .V = true }), .sz = arrangement.elemSz(), .Q = arrangement.size(), }, } } }, } }, } } /// C6.2.387 UDF pub fn udf(imm: u16) Instruction { return .{ .reserved = .{ .udf = .{ .imm16 = imm }, } }; } /// C6.2.388 UDIV pub fn udiv(d: Register, n: Register, m: Register) Instruction { const sf = d.format.general; assert(n.format.general == sf and m.format.general == 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.general == .doubleword and n.format.general == .word and m.format.general == .word and a.format.general == .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.general == .doubleword and n.format.general == .word and m.format.general == .word and a.format.general == .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.general; 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.general == .doubleword and n.format.general == .doubleword and m.format.general == .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.400 XAFLAG pub fn xaflag() Instruction { return .{ .branch_exception_generating_system = .{ .pstate = .{ .xaflag = .{}, } } }; } /// C6.2.402 YIELD pub fn yield() Instruction { return .{ .branch_exception_generating_system = .{ .hints = .{ .yield = .{}, } } }; } pub const size = @divExact(@bitSizeOf(Backing), 8); pub const Backing = u32; pub fn read(mem: *const [size]u8) Instruction { return @bitCast(std.mem.readInt(Backing, mem, .little)); } pub fn write(inst: Instruction, mem: *[size]u8) void { std.mem.writeInt(Backing, mem, @bitCast(inst), .little); } pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void { const dis: aarch64.Disassemble = .{}; try dis.printInstruction(inst, writer); } comptime { @setEvalBranchQuota(110_000); verify(@typeName(Instruction), Instruction); } fn verify(name: []const u8, Type: type) void { switch (@typeInfo(Type)) { .@"union" => |info| { if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) { @compileLog(name ++ " should have u32 abi"); } for (info.fields) |field| verify(name ++ "." ++ field.name, field.type); }, .@"struct" => |info| { if (info.layout != .@"packed" or info.backing_integer != Backing) { @compileLog(name ++ " should have u32 abi"); } var bit_offset = 0; for (info.fields) |field| { if (std.mem.startsWith(u8, field.name, "encoded")) { if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) { @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); } if (field.default_value_ptr != null) { @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); } } else if (std.mem.startsWith(u8, field.name, "decoded")) { if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) { @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); } if (field.default_value_ptr == null) { @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); } } bit_offset += @bitSizeOf(field.type); } }, else => @compileError(name ++ " has an unexpected field type"), } } }; const aarch64 = @import("../aarch64.zig"); const assert = std.debug.assert; const std = @import("std");