master
   1const std = @import("std");
   2const assert = std.debug.assert;
   3const testing = std.testing;
   4
   5/// General purpose registers in the SPARCv9 instruction set
   6pub const Register = enum(u6) {
   7    // zig fmt: off
   8    g0,    g1,    g2,    g3,    g4,    g5,    g6,    g7,
   9    o0,    o1,    o2,    o3,    o4,    o5,    o6,    o7,
  10    l0,    l1,    l2,    l3,    l4,    l5,    l6,    l7,
  11  @"i0", @"i1", @"i2", @"i3", @"i4", @"i5", @"i6", @"i7",
  12
  13    sp = 46, // stack pointer (o6)
  14    fp = 62, // frame pointer (i6)
  15    // zig fmt: on
  16
  17    pub fn id(reg: Register) u5 {
  18        return @truncate(@intFromEnum(reg));
  19    }
  20
  21    pub fn enc(reg: Register) u5 {
  22        // For integer registers, enc() == id().
  23        return reg.id();
  24    }
  25
  26    pub fn dwarfNum(reg: Register) u5 {
  27        return reg.id();
  28    }
  29};
  30
  31test "Register.id" {
  32    // SP
  33    try testing.expectEqual(@as(u5, 14), Register.o6.id());
  34    try testing.expectEqual(Register.o6.id(), Register.sp.id());
  35
  36    // FP
  37    try testing.expectEqual(@as(u5, 30), Register.i6.id());
  38    try testing.expectEqual(Register.i6.id(), Register.fp.id());
  39
  40    // x0
  41    try testing.expectEqual(@as(u5, 0), Register.g0.id());
  42    try testing.expectEqual(@as(u5, 8), Register.o0.id());
  43    try testing.expectEqual(@as(u5, 16), Register.l0.id());
  44    try testing.expectEqual(@as(u5, 24), Register.i0.id());
  45}
  46
  47test "Register.enc" {
  48    // x0
  49    try testing.expectEqual(@as(u5, 0), Register.g0.enc());
  50    try testing.expectEqual(@as(u5, 8), Register.o0.enc());
  51    try testing.expectEqual(@as(u5, 16), Register.l0.enc());
  52    try testing.expectEqual(@as(u5, 24), Register.i0.enc());
  53
  54    // For integer registers, enc() == id().
  55    try testing.expectEqual(Register.g0.enc(), Register.g0.id());
  56    try testing.expectEqual(Register.o0.enc(), Register.o0.id());
  57    try testing.expectEqual(Register.l0.enc(), Register.l0.id());
  58    try testing.expectEqual(Register.i0.enc(), Register.i0.id());
  59}
  60
  61/// Scalar floating point registers in the SPARCv9 instruction set
  62pub const FloatingPointRegister = enum(u7) {
  63    // SPARCv9 has 64 f32 registers, 32 f64 registers, and 16 f128 registers,
  64    // which are aliased in this way:
  65    //
  66    //      |    %d0    |    %d2    |
  67    // %q0  | %f0 | %f1 | %f2 | %f3 |
  68    //      |    %d4    |    %d6    |
  69    // %q4  | %f4 | %f5 | %f6 | %f7 |
  70    // ...
  71    //      |    %d60     |    %d62     |
  72    // %q60 | %f60 | %f61 | %f62 | %f63 |
  73    //
  74    // Though, since the instructions uses five-bit addressing, only %f0-%f31
  75    // is usable with f32 instructions.
  76
  77    // zig fmt: off
  78
  79    // 32-bit registers
  80     @"f0",  @"f1",  @"f2",  @"f3",  @"f4",  @"f5",  @"f6",  @"f7",
  81     @"f8",  @"f9", @"f10", @"f11", @"f12", @"f13", @"f14", @"f15",
  82    @"f16", @"f17", @"f18", @"f19", @"f20", @"f21", @"f22", @"f23",
  83    @"f24", @"f25", @"f26", @"f27", @"f28", @"f29", @"f30", @"f31",
  84
  85    // 64-bit registers
  86     d0,  d2,  d4,  d6,  d8, d10, d12, d14,
  87    d16, d18, d20, d22, d24, d26, d28, d30,
  88    d32, d34, d36, d38, d40, d42, d44, d46,
  89    d48, d50, d52, d54, d56, d58, d60, d62,
  90
  91    // 128-bit registers
  92     q0,  q4,  q8, q12, q16, q20, q24, q28,
  93    q32, q36, q40, q44, q48, q52, q56, q60,
  94    // zig fmt: on
  95
  96    pub fn id(self: FloatingPointRegister) u6 {
  97        return switch (self.size()) {
  98            32 => @as(u6, @truncate(@intFromEnum(self))),
  99            64 => @as(u6, @truncate((@intFromEnum(self) - 32) * 2)),
 100            128 => @as(u6, @truncate((@intFromEnum(self) - 64) * 4)),
 101            else => unreachable,
 102        };
 103    }
 104
 105    pub fn enc(self: FloatingPointRegister) u5 {
 106        // Floating point registers use an encoding scheme to map from the 6-bit
 107        // ID to 5-bit encoded value.
 108        // (See section 5.1.4.1 of SPARCv9 ISA specification)
 109
 110        const reg_id = self.id();
 111        return @as(u5, @truncate(reg_id | (reg_id >> 5)));
 112    }
 113
 114    /// Returns the bit-width of the register.
 115    pub fn size(self: FloatingPointRegister) u8 {
 116        return switch (@intFromEnum(self)) {
 117            0...31 => 32,
 118            32...63 => 64,
 119            64...79 => 128,
 120            else => unreachable,
 121        };
 122    }
 123};
 124
 125test "FloatingPointRegister.id" {
 126    // Low region
 127    try testing.expectEqual(@as(u6, 0), FloatingPointRegister.q0.id());
 128    try testing.expectEqual(FloatingPointRegister.q0.id(), FloatingPointRegister.d0.id());
 129    try testing.expectEqual(FloatingPointRegister.d0.id(), FloatingPointRegister.f0.id());
 130
 131    try testing.expectEqual(@as(u6, 28), FloatingPointRegister.q28.id());
 132    try testing.expectEqual(FloatingPointRegister.q28.id(), FloatingPointRegister.d28.id());
 133    try testing.expectEqual(FloatingPointRegister.d28.id(), FloatingPointRegister.f28.id());
 134
 135    // High region
 136    try testing.expectEqual(@as(u6, 32), FloatingPointRegister.q32.id());
 137    try testing.expectEqual(FloatingPointRegister.q32.id(), FloatingPointRegister.d32.id());
 138
 139    try testing.expectEqual(@as(u6, 60), FloatingPointRegister.q60.id());
 140    try testing.expectEqual(FloatingPointRegister.q60.id(), FloatingPointRegister.d60.id());
 141}
 142
 143test "FloatingPointRegister.enc" {
 144    // f registers
 145    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.f0.enc());
 146    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.f1.enc());
 147    try testing.expectEqual(@as(u5, 31), FloatingPointRegister.f31.enc());
 148
 149    // d registers
 150    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.enc());
 151    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.d32.enc());
 152    try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d62.enc());
 153
 154    // q registers
 155    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.enc());
 156    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.q32.enc());
 157    try testing.expectEqual(@as(u5, 29), FloatingPointRegister.q60.enc());
 158}
 159
 160/// Represents an instruction in the SPARCv9 instruction set
 161pub const Instruction = union(enum) {
 162    // Some of the instruction formats have several minor formats, here I
 163    // name them with letters since there's no official naming scheme.
 164    // TODO: need to rename the minor formats to a more descriptive name.
 165
 166    // I am using regular structs instead of packed ones to avoid
 167    // endianness-dependent behavior when constructing the actual
 168    // assembly instructions.
 169    // See also: https://github.com/ziglang/zig/issues/10113
 170    // TODO: change it back to packed structs once the issue is resolved.
 171
 172    // Format 1 (op = 1): CALL
 173    format_1: struct {
 174        op: u2 = 0b01,
 175        disp30: u30,
 176    },
 177
 178    // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
 179    format_2a: struct {
 180        op: u2 = 0b00,
 181        rd: u5,
 182        op2: u3,
 183        imm22: u22,
 184    },
 185    format_2b: struct {
 186        op: u2 = 0b00,
 187        a: u1,
 188        cond: u4,
 189        op2: u3,
 190        disp22: u22,
 191    },
 192    format_2c: struct {
 193        op: u2 = 0b00,
 194        a: u1,
 195        cond: u4,
 196        op2: u3,
 197        cc1: u1,
 198        cc0: u1,
 199        p: u1,
 200        disp19: u19,
 201    },
 202    format_2d: struct {
 203        op: u2 = 0b00,
 204        a: u1,
 205        fixed: u1 = 0b0,
 206        rcond: u3,
 207        op2: u3,
 208        d16hi: u2,
 209        p: u1,
 210        rs1: u5,
 211        d16lo: u14,
 212    },
 213
 214    // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
 215    format_3a: struct {
 216        op: u2,
 217        rd: u5,
 218        op3: u6,
 219        rs1: u5,
 220        i: u1 = 0b0,
 221        reserved: u8 = 0b00000000,
 222        rs2: u5,
 223    },
 224    format_3b: struct {
 225        op: u2,
 226        rd: u5,
 227        op3: u6,
 228        rs1: u5,
 229        i: u1 = 0b1,
 230        simm13: u13,
 231    },
 232    format_3c: struct {
 233        op: u2,
 234        reserved1: u5 = 0b00000,
 235        op3: u6,
 236        rs1: u5,
 237        i: u1 = 0b0,
 238        reserved2: u8 = 0b00000000,
 239        rs2: u5,
 240    },
 241    format_3d: struct {
 242        op: u2,
 243        reserved: u5 = 0b00000,
 244        op3: u6,
 245        rs1: u5,
 246        i: u1 = 0b1,
 247        simm13: u13,
 248    },
 249    format_3e: struct {
 250        op: u2,
 251        rd: u5,
 252        op3: u6,
 253        rs1: u5,
 254        i: u1 = 0b0,
 255        rcond: u3,
 256        reserved: u5 = 0b00000,
 257        rs2: u5,
 258    },
 259    format_3f: struct {
 260        op: u2,
 261        rd: u5,
 262        op3: u6,
 263        rs1: u5,
 264        i: u1 = 0b1,
 265        rcond: u3,
 266        simm10: u10,
 267    },
 268    format_3g: struct {
 269        op: u2,
 270        rd: u5,
 271        op3: u6,
 272        rs1: u5,
 273        // See Errata 58 of SPARCv9 specification
 274        // https://sparc.org/errata-for-v9/#58
 275        i: u1 = 0b1,
 276        reserved: u8 = 0b00000000,
 277        rs2: u5,
 278    },
 279    format_3h: struct {
 280        op: u2 = 0b10,
 281        fixed1: u5 = 0b00000,
 282        op3: u6 = 0b101000,
 283        fixed2: u5 = 0b01111,
 284        i: u1 = 0b1,
 285        reserved: u6 = 0b000000,
 286        cmask: u3,
 287        mmask: u4,
 288    },
 289    format_3i: struct {
 290        op: u2,
 291        rd: u5,
 292        op3: u6,
 293        rs1: u5,
 294        i: u1 = 0b0,
 295        imm_asi: u8,
 296        rs2: u5,
 297    },
 298    format_3j: struct {
 299        op: u2,
 300        impl_dep1: u5,
 301        op3: u6,
 302        impl_dep2: u19,
 303    },
 304    format_3k: struct {
 305        op: u2,
 306        rd: u5,
 307        op3: u6,
 308        rs1: u5,
 309        i: u1 = 0b0,
 310        x: u1,
 311        reserved: u7 = 0b0000000,
 312        rs2: u5,
 313    },
 314    format_3l: struct {
 315        op: u2,
 316        rd: u5,
 317        op3: u6,
 318        rs1: u5,
 319        i: u1 = 0b1,
 320        x: u1 = 0b0,
 321        reserved: u7 = 0b0000000,
 322        shcnt32: u5,
 323    },
 324    format_3m: struct {
 325        op: u2,
 326        rd: u5,
 327        op3: u6,
 328        rs1: u5,
 329        i: u1 = 0b1,
 330        x: u1 = 0b1,
 331        reserved: u6 = 0b000000,
 332        shcnt64: u6,
 333    },
 334    format_3n: struct {
 335        op: u2,
 336        rd: u5,
 337        op3: u6,
 338        reserved: u5 = 0b00000,
 339        opf: u9,
 340        rs2: u5,
 341    },
 342    format_3o: struct {
 343        op: u2,
 344        fixed: u3 = 0b000,
 345        cc1: u1,
 346        cc0: u1,
 347        op3: u6,
 348        rs1: u5,
 349        opf: u9,
 350        rs2: u5,
 351    },
 352    format_3p: struct {
 353        op: u2,
 354        rd: u5,
 355        op3: u6,
 356        rs1: u5,
 357        opf: u9,
 358        rs2: u5,
 359    },
 360    format_3q: struct {
 361        op: u2,
 362        rd: u5,
 363        op3: u6,
 364        rs1: u5,
 365        reserved: u14 = 0b00000000000000,
 366    },
 367    format_3r: struct {
 368        op: u2,
 369        fcn: u5,
 370        op3: u6,
 371        reserved: u19 = 0b0000000000000000000,
 372    },
 373    format_3s: struct {
 374        op: u2,
 375        rd: u5,
 376        op3: u6,
 377        reserved: u19 = 0b0000000000000000000,
 378    },
 379
 380    //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
 381    format_4a: struct {
 382        op: u2 = 0b10,
 383        rd: u5,
 384        op3: u6,
 385        rs1: u5,
 386        i: u1 = 0b0,
 387        cc1: u1,
 388        cc0: u1,
 389        reserved: u6 = 0b000000,
 390        rs2: u5,
 391    },
 392    format_4b: struct {
 393        op: u2 = 0b10,
 394        rd: u5,
 395        op3: u6,
 396        rs1: u5,
 397        i: u1 = 0b1,
 398        cc1: u1,
 399        cc0: u1,
 400        simm11: u11,
 401    },
 402    format_4c: struct {
 403        op: u2 = 0b10,
 404        rd: u5,
 405        op3: u6,
 406        cc2: u1,
 407        cond: u4,
 408        i: u1 = 0b0,
 409        cc1: u1,
 410        cc0: u1,
 411        reserved: u6 = 0b000000,
 412        rs2: u5,
 413    },
 414    format_4d: struct {
 415        op: u2 = 0b10,
 416        rd: u5,
 417        op3: u6,
 418        cc2: u1,
 419        cond: u4,
 420        i: u1 = 0b1,
 421        cc1: u1,
 422        cc0: u1,
 423        simm11: u11,
 424    },
 425    format_4e: struct {
 426        op: u2 = 0b10,
 427        rd: u5,
 428        op3: u6,
 429        rs1: u5,
 430        i: u1 = 0b1,
 431        cc1: u1,
 432        cc0: u1,
 433        reserved: u4 = 0b0000,
 434        sw_trap: u7,
 435    },
 436    format_4f: struct {
 437        op: u2 = 0b10,
 438        rd: u5,
 439        op3: u6,
 440        rs1: u5,
 441        fixed: u1 = 0b0,
 442        rcond: u3,
 443        opf_low: u5,
 444        rs2: u5,
 445    },
 446    format_4g: struct {
 447        op: u2 = 0b10,
 448        rd: u5,
 449        op3: u6,
 450        fixed: u1 = 0b0,
 451        cond: u4,
 452        opf_cc: u3,
 453        opf_low: u6,
 454        rs2: u5,
 455    },
 456
 457    pub const CCR = enum(u3) {
 458        fcc0,
 459        fcc1,
 460        fcc2,
 461        fcc3,
 462        icc,
 463        reserved1,
 464        xcc,
 465        reserved2,
 466    };
 467
 468    pub const RCondition = enum(u3) {
 469        reserved1,
 470        eq_zero,
 471        le_zero,
 472        lt_zero,
 473        reserved2,
 474        ne_zero,
 475        gt_zero,
 476        ge_zero,
 477
 478        /// Returns the condition which is true iff the given condition is
 479        /// false (if such a condition exists).
 480        pub fn negate(cond: RCondition) RCondition {
 481            return switch (cond) {
 482                .eq_zero => .ne_zero,
 483                .ne_zero => .eq_zero,
 484                .lt_zero => .ge_zero,
 485                .ge_zero => .lt_zero,
 486                .le_zero => .gt_zero,
 487                .gt_zero => .le_zero,
 488                .reserved1 => unreachable,
 489                .reserved2 => unreachable,
 490            };
 491        }
 492    };
 493
 494    pub const ASI = enum(u8) {
 495        asi_nucleus = 0x04,
 496        asi_nucleus_little = 0x0c,
 497        asi_as_if_user_primary = 0x10,
 498        asi_as_if_user_secondary = 0x11,
 499        asi_as_if_user_primary_little = 0x18,
 500        asi_as_if_user_secondary_little = 0x19,
 501        asi_primary = 0x80,
 502        asi_secondary = 0x81,
 503        asi_primary_nofault = 0x82,
 504        asi_secondary_nofault = 0x83,
 505        asi_primary_little = 0x88,
 506        asi_secondary_little = 0x89,
 507        asi_primary_nofault_little = 0x8a,
 508        asi_secondary_nofault_little = 0x8b,
 509    };
 510
 511    pub const ShiftWidth = enum(u1) {
 512        shift32,
 513        shift64,
 514    };
 515
 516    pub const MemOrderingConstraint = packed struct {
 517        store_store: bool = false,
 518        load_store: bool = false,
 519        store_load: bool = false,
 520        load_load: bool = false,
 521    };
 522
 523    pub const MemCompletionConstraint = packed struct {
 524        sync: bool = false,
 525        mem_issue: bool = false,
 526        lookaside: bool = false,
 527    };
 528
 529    // In SPARCv9, FP and integer comparison operations
 530    // are encoded differently.
 531
 532    pub const FCondition = enum(u4) {
 533        /// Branch Never
 534        nv,
 535        /// Branch on Not Equal
 536        ne,
 537        /// Branch on Less or Greater
 538        lg,
 539        /// Branch on Unordered or Less
 540        ul,
 541        /// Branch on Less
 542        lt,
 543        /// Branch on Unordered or Greater
 544        ug,
 545        /// Branch on Greater
 546        gt,
 547        /// Branch on Unordered
 548        un,
 549        /// Branch Always
 550        al,
 551        /// Branch on Equal
 552        eq,
 553        /// Branch on Unordered or Equal
 554        ue,
 555        /// Branch on Greater or Equal
 556        ge,
 557        /// Branch on Unordered or Greater or Equal
 558        uge,
 559        /// Branch on Less or Equal
 560        le,
 561        /// Branch on Unordered or Less or Equal
 562        ule,
 563        /// Branch on Ordered
 564        ord,
 565
 566        /// Converts a std.math.CompareOperator into a condition flag,
 567        /// i.e. returns the condition that is true iff the result of the
 568        /// comparison is true.
 569        pub fn fromCompareOperator(op: std.math.CompareOperator) FCondition {
 570            return switch (op) {
 571                .gte => .ge,
 572                .gt => .gt,
 573                .neq => .ne,
 574                .lt => .lt,
 575                .lte => .le,
 576                .eq => .eq,
 577            };
 578        }
 579
 580        /// Returns the condition which is true iff the given condition is
 581        /// false (if such a condition exists).
 582        pub fn negate(cond: FCondition) FCondition {
 583            return switch (cond) {
 584                .eq => .ne,
 585                .ne => .eq,
 586                .ge => .ul,
 587                .ul => .ge,
 588                .le => .ug,
 589                .ug => .le,
 590                .lt => .uge,
 591                .uge => .lt,
 592                .gt => .ule,
 593                .ule => .gt,
 594                .ue => .lg,
 595                .lg => .ue,
 596                .ord => .un,
 597                .un => .ord,
 598                .al => unreachable,
 599                .nv => unreachable,
 600            };
 601        }
 602    };
 603
 604    pub const ICondition = enum(u4) {
 605        /// Branch Never
 606        nv,
 607        /// Branch on Equal
 608        eq,
 609        /// Branch on Less or Equal
 610        le,
 611        /// Branch on Less
 612        lt,
 613        /// Branch on Less or Equal Unsigned
 614        leu,
 615        /// Branch on Carry Set (Less than, Unsigned)
 616        cs,
 617        /// Branch on Negative
 618        neg,
 619        /// Branch on Overflow Set
 620        vs,
 621        /// Branch Always
 622        al,
 623        /// Branch on Not Equal
 624        ne,
 625        /// Branch on Greater
 626        gt,
 627        /// Branch on Greater or Equal
 628        ge,
 629        /// Branch on Greater Unsigned
 630        gu,
 631        /// Branch on Carry Clear (Greater Than or Equal, Unsigned)
 632        cc,
 633        /// Branch on Positive
 634        pos,
 635        /// Branch on Overflow Clear
 636        vc,
 637
 638        /// Converts a std.math.CompareOperator into a condition flag,
 639        /// i.e. returns the condition that is true iff the result of the
 640        /// comparison is true. Assumes signed comparison.
 641        pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) ICondition {
 642            return switch (op) {
 643                .gte => .ge,
 644                .gt => .gt,
 645                .neq => .ne,
 646                .lt => .lt,
 647                .lte => .le,
 648                .eq => .eq,
 649            };
 650        }
 651
 652        /// Converts a std.math.CompareOperator into a condition flag,
 653        /// i.e. returns the condition that is true iff the result of the
 654        /// comparison is true. Assumes unsigned comparison.
 655        pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) ICondition {
 656            return switch (op) {
 657                .gte => .cc,
 658                .gt => .gu,
 659                .neq => .ne,
 660                .lt => .cs,
 661                .lte => .leu,
 662                .eq => .eq,
 663            };
 664        }
 665
 666        /// Returns the condition which is true iff the given condition is
 667        /// false (if such a condition exists).
 668        pub fn negate(cond: ICondition) ICondition {
 669            return switch (cond) {
 670                .eq => .ne,
 671                .ne => .eq,
 672                .cs => .cc,
 673                .cc => .cs,
 674                .neg => .pos,
 675                .pos => .neg,
 676                .vs => .vc,
 677                .vc => .vs,
 678                .gu => .leu,
 679                .leu => .gu,
 680                .ge => .lt,
 681                .lt => .ge,
 682                .gt => .le,
 683                .le => .gt,
 684                .al => unreachable,
 685                .nv => unreachable,
 686            };
 687        }
 688    };
 689
 690    pub const ConditionTag = enum { fcond, icond };
 691    pub const Condition = union(ConditionTag) {
 692        fcond: FCondition,
 693        icond: ICondition,
 694
 695        /// Encodes the condition into the instruction bit pattern.
 696        pub fn enc(cond: Condition) u4 {
 697            return switch (cond) {
 698                .icond => |c| @intFromEnum(c),
 699                .fcond => |c| @intFromEnum(c),
 700            };
 701        }
 702
 703        /// Returns the condition which is true iff the given condition is
 704        /// false (if such a condition exists).
 705        pub fn negate(cond: Condition) Condition {
 706            return switch (cond) {
 707                .icond => |c| .{ .icond = c.negate() },
 708                .fcond => |c| .{ .fcond = c.negate() },
 709            };
 710        }
 711    };
 712
 713    pub fn toU32(self: Instruction) u32 {
 714        // TODO: Remove this once packed structs work.
 715        return switch (self) {
 716            .format_1 => |v| (@as(u32, v.op) << 30) | @as(u32, v.disp30),
 717            .format_2a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.imm22),
 718            .format_2b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.disp22),
 719            .format_2c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.cc1) << 21) | (@as(u32, v.cc0) << 20) | (@as(u32, v.p) << 19) | @as(u32, v.disp19),
 720            .format_2d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.fixed) << 28) | (@as(u32, v.rcond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.d16hi) << 20) | (@as(u32, v.p) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.d16lo),
 721            .format_3a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 722            .format_3b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
 723            .format_3c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved2) << 5) | @as(u32, v.rs2),
 724            .format_3d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
 725            .format_3e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 726            .format_3f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | @as(u32, v.simm10),
 727            .format_3g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 728            .format_3h => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed2) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 7) | (@as(u32, v.cmask) << 4) | @as(u32, v.mmask),
 729            .format_3i => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.imm_asi) << 5) | @as(u32, v.rs2),
 730            .format_3j => |v| (@as(u32, v.op) << 30) | (@as(u32, v.impl_dep1) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.impl_dep2),
 731            .format_3k => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 732            .format_3l => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.shcnt32),
 733            .format_3m => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 6) | @as(u32, v.shcnt64),
 734            .format_3n => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.reserved) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
 735            .format_3o => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed) << 27) | (@as(u32, v.cc1) << 26) | (@as(u32, v.cc0) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
 736            .format_3p => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
 737            .format_3q => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.reserved),
 738            .format_3r => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fcn) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
 739            .format_3s => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
 740            .format_4a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 741            .format_4b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
 742            .format_4c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
 743            .format_4d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
 744            .format_4e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 7) | @as(u32, v.sw_trap),
 745            .format_4f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.fixed) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
 746            .format_4g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.opf_cc) << 11) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
 747        };
 748    }
 749
 750    // SPARCv9 Instruction formats.
 751    // See section 6.2 of the SPARCv9 ISA manual.
 752
 753    fn format1(disp: i32) Instruction {
 754        const udisp = @as(u32, @bitCast(disp));
 755
 756        // In SPARC, branch target needs to be aligned to 4 bytes.
 757        assert(udisp % 4 == 0);
 758
 759        // Discard the last two bits since those are implicitly zero.
 760        const udisp_truncated = @as(u30, @truncate(udisp >> 2));
 761        return Instruction{
 762            .format_1 = .{
 763                .disp30 = udisp_truncated,
 764            },
 765        };
 766    }
 767
 768    fn format2a(op2: u3, imm: u22, rd: Register) Instruction {
 769        return Instruction{
 770            .format_2a = .{
 771                .rd = rd.enc(),
 772                .op2 = op2,
 773                .imm22 = imm,
 774            },
 775        };
 776    }
 777
 778    fn format2b(op2: u3, cond: Condition, annul: bool, disp: i24) Instruction {
 779        const udisp = @as(u24, @bitCast(disp));
 780
 781        // In SPARC, branch target needs to be aligned to 4 bytes.
 782        assert(udisp % 4 == 0);
 783
 784        // Discard the last two bits since those are implicitly zero.
 785        const udisp_truncated = @as(u22, @truncate(udisp >> 2));
 786        return Instruction{
 787            .format_2b = .{
 788                .a = @intFromBool(annul),
 789                .cond = cond.enc(),
 790                .op2 = op2,
 791                .disp22 = udisp_truncated,
 792            },
 793        };
 794    }
 795
 796    fn format2c(op2: u3, cond: Condition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction {
 797        const udisp = @as(u21, @bitCast(disp));
 798
 799        // In SPARC, branch target needs to be aligned to 4 bytes.
 800        assert(udisp % 4 == 0);
 801
 802        // Discard the last two bits since those are implicitly zero.
 803        const udisp_truncated = @as(u19, @truncate(udisp >> 2));
 804
 805        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
 806        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
 807        return Instruction{
 808            .format_2c = .{
 809                .a = @intFromBool(annul),
 810                .cond = cond.enc(),
 811                .op2 = op2,
 812                .cc1 = ccr_cc1,
 813                .cc0 = ccr_cc0,
 814                .p = @intFromBool(pt),
 815                .disp19 = udisp_truncated,
 816            },
 817        };
 818    }
 819
 820    fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
 821        const udisp = @as(u18, @bitCast(disp));
 822
 823        // In SPARC, branch target needs to be aligned to 4 bytes.
 824        assert(udisp % 4 == 0);
 825
 826        // Discard the last two bits since those are implicitly zero,
 827        // and split it into low and high parts.
 828        const udisp_truncated = @as(u16, @truncate(udisp >> 2));
 829        const udisp_hi = @as(u2, @truncate((udisp_truncated & 0b1100_0000_0000_0000) >> 14));
 830        const udisp_lo = @as(u14, @truncate(udisp_truncated & 0b0011_1111_1111_1111));
 831        return Instruction{
 832            .format_2d = .{
 833                .a = @intFromBool(annul),
 834                .rcond = @intFromEnum(rcond),
 835                .op2 = op2,
 836                .p = @intFromBool(pt),
 837                .rs1 = rs1.enc(),
 838                .d16hi = udisp_hi,
 839                .d16lo = udisp_lo,
 840            },
 841        };
 842    }
 843
 844    fn format3a(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction {
 845        return Instruction{
 846            .format_3a = .{
 847                .op = op,
 848                .rd = rd.enc(),
 849                .op3 = op3,
 850                .rs1 = rs1.enc(),
 851                .rs2 = rs2.enc(),
 852            },
 853        };
 854    }
 855    fn format3b(op: u2, op3: u6, rs1: Register, imm: i13, rd: Register) Instruction {
 856        return Instruction{
 857            .format_3b = .{
 858                .op = op,
 859                .rd = rd.enc(),
 860                .op3 = op3,
 861                .rs1 = rs1.enc(),
 862                .simm13 = @as(u13, @bitCast(imm)),
 863            },
 864        };
 865    }
 866    fn format3c(op: u2, op3: u6, rs1: Register, rs2: Register) Instruction {
 867        return Instruction{
 868            .format_3c = .{
 869                .op = op,
 870                .op3 = op3,
 871                .rs1 = rs1.enc(),
 872                .rs2 = rs2.enc(),
 873            },
 874        };
 875    }
 876    fn format3d(op: u2, op3: u6, rs1: Register, imm: i13) Instruction {
 877        return Instruction{
 878            .format_3d = .{
 879                .op = op,
 880                .op3 = op3,
 881                .rs1 = rs1.enc(),
 882                .simm13 = @as(u13, @bitCast(imm)),
 883            },
 884        };
 885    }
 886    fn format3e(op: u2, op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction {
 887        return Instruction{
 888            .format_3e = .{
 889                .op = op,
 890                .rd = rd.enc(),
 891                .op3 = op3,
 892                .rs1 = rs1.enc(),
 893                .rcond = @intFromEnum(rcond),
 894                .rs2 = rs2.enc(),
 895            },
 896        };
 897    }
 898    fn format3f(op: u2, op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction {
 899        return Instruction{
 900            .format_3f = .{
 901                .op = op,
 902                .rd = rd.enc(),
 903                .op3 = op3,
 904                .rs1 = rs1.enc(),
 905                .rcond = @intFromEnum(rcond),
 906                .simm10 = @as(u10, @bitCast(imm)),
 907            },
 908        };
 909    }
 910    fn format3g(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction {
 911        return Instruction{
 912            .format_3g = .{
 913                .op = op,
 914                .rd = rd.enc(),
 915                .op3 = op3,
 916                .rs1 = rs1.enc(),
 917                .rs2 = rs2.enc(),
 918            },
 919        };
 920    }
 921    fn format3h(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction {
 922        return Instruction{
 923            .format_3h = .{
 924                .cmask = @as(u3, @bitCast(cmask)),
 925                .mmask = @as(u4, @bitCast(mmask)),
 926            },
 927        };
 928    }
 929    fn format3i(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction {
 930        return Instruction{
 931            .format_3i = .{
 932                .op = op,
 933                .rd = rd.enc(),
 934                .op3 = op3,
 935                .rs1 = rs1.enc(),
 936                .imm_asi = @intFromEnum(asi),
 937                .rs2 = rs2.enc(),
 938            },
 939        };
 940    }
 941    fn format3j(op: u2, op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction {
 942        return Instruction{
 943            .format_3j = .{
 944                .op = op,
 945                .impl_dep1 = impl_dep1,
 946                .op3 = op3,
 947                .impl_dep2 = impl_dep2,
 948            },
 949        };
 950    }
 951    fn format3k(op: u2, op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction {
 952        return Instruction{
 953            .format_3k = .{
 954                .op = op,
 955                .rd = rd.enc(),
 956                .op3 = op3,
 957                .rs1 = rs1.enc(),
 958                .x = @intFromEnum(sw),
 959                .rs2 = rs2.enc(),
 960            },
 961        };
 962    }
 963    fn format3l(op: u2, op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction {
 964        return Instruction{
 965            .format_3l = .{
 966                .op = op,
 967                .rd = rd.enc(),
 968                .op3 = op3,
 969                .rs1 = rs1.enc(),
 970                .shcnt32 = shift_count,
 971            },
 972        };
 973    }
 974    fn format3m(op: u2, op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction {
 975        return Instruction{
 976            .format_3m = .{
 977                .op = op,
 978                .rd = rd.enc(),
 979                .op3 = op3,
 980                .rs1 = rs1.enc(),
 981                .shcnt64 = shift_count,
 982            },
 983        };
 984    }
 985    fn format3n(op: u2, op3: u6, opf: u9, rs2: Register, rd: Register) Instruction {
 986        return Instruction{
 987            .format_3n = .{
 988                .op = op,
 989                .rd = rd.enc(),
 990                .op3 = op3,
 991                .opf = opf,
 992                .rs2 = rs2.enc(),
 993            },
 994        };
 995    }
 996    fn format3o(op: u2, op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction {
 997        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
 998        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
 999        return Instruction{
1000            .format_3o = .{
1001                .op = op,
1002                .cc1 = ccr_cc1,
1003                .cc0 = ccr_cc0,
1004                .op3 = op3,
1005                .rs1 = rs1.enc(),
1006                .opf = opf,
1007                .rs2 = rs2.enc(),
1008            },
1009        };
1010    }
1011    fn format3p(op: u2, op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction {
1012        return Instruction{
1013            .format_3p = .{
1014                .op = op,
1015                .rd = rd.enc(),
1016                .op3 = op3,
1017                .rs1 = rs1.enc(),
1018                .opf = opf,
1019                .rs2 = rs2.enc(),
1020            },
1021        };
1022    }
1023    fn format3q(op: u2, op3: u6, rs1: Register, rd: Register) Instruction {
1024        return Instruction{
1025            .format_3q = .{
1026                .op = op,
1027                .rd = rd.enc(),
1028                .op3 = op3,
1029                .rs1 = rs1.enc(),
1030            },
1031        };
1032    }
1033    fn format3r(op: u2, op3: u6, fcn: u5) Instruction {
1034        return Instruction{
1035            .format_3r = .{
1036                .op = op,
1037                .fcn = fcn,
1038                .op3 = op3,
1039            },
1040        };
1041    }
1042    fn format3s(op: u2, op3: u6, rd: Register) Instruction {
1043        return Instruction{
1044            .format_3s = .{
1045                .op = op,
1046                .rd = rd.enc(),
1047                .op3 = op3,
1048            },
1049        };
1050    }
1051
1052    fn format4a(op3: u6, ccr: CCR, rs1: Register, rs2: Register, rd: Register) Instruction {
1053        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
1054        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
1055        return Instruction{
1056            .format_4a = .{
1057                .rd = rd.enc(),
1058                .op3 = op3,
1059                .rs1 = rs1.enc(),
1060                .cc1 = ccr_cc1,
1061                .cc0 = ccr_cc0,
1062                .rs2 = rs2.enc(),
1063            },
1064        };
1065    }
1066
1067    fn format4b(op3: u6, ccr: CCR, rs1: Register, imm: i11, rd: Register) Instruction {
1068        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
1069        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
1070        return Instruction{
1071            .format_4b = .{
1072                .rd = rd.enc(),
1073                .op3 = op3,
1074                .rs1 = rs1.enc(),
1075                .cc1 = ccr_cc1,
1076                .cc0 = ccr_cc0,
1077                .simm11 = @as(u11, @bitCast(imm)),
1078            },
1079        };
1080    }
1081
1082    fn format4c(op3: u6, cond: Condition, ccr: CCR, rs2: Register, rd: Register) Instruction {
1083        const ccr_cc2 = @as(u1, @truncate(@intFromEnum(ccr) >> 2));
1084        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
1085        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
1086        return Instruction{
1087            .format_4c = .{
1088                .rd = rd.enc(),
1089                .op3 = op3,
1090                .cc2 = ccr_cc2,
1091                .cond = cond.enc(),
1092                .cc1 = ccr_cc1,
1093                .cc0 = ccr_cc0,
1094                .rs2 = rs2.enc(),
1095            },
1096        };
1097    }
1098
1099    fn format4d(op3: u6, cond: Condition, ccr: CCR, imm: i11, rd: Register) Instruction {
1100        const ccr_cc2 = @as(u1, @truncate(@intFromEnum(ccr) >> 2));
1101        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
1102        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
1103        return Instruction{
1104            .format_4d = .{
1105                .rd = rd.enc(),
1106                .op3 = op3,
1107                .cc2 = ccr_cc2,
1108                .cond = cond.enc(),
1109                .cc1 = ccr_cc1,
1110                .cc0 = ccr_cc0,
1111                .simm11 = @as(u11, @bitCast(imm)),
1112            },
1113        };
1114    }
1115
1116    fn format4e(op3: u6, ccr: CCR, rs1: Register, rd: Register, sw_trap: u7) Instruction {
1117        const ccr_cc1 = @as(u1, @truncate(@intFromEnum(ccr) >> 1));
1118        const ccr_cc0 = @as(u1, @truncate(@intFromEnum(ccr)));
1119        return Instruction{
1120            .format_4e = .{
1121                .rd = rd.enc(),
1122                .op3 = op3,
1123                .rs1 = rs1.enc(),
1124                .cc1 = ccr_cc1,
1125                .cc0 = ccr_cc0,
1126                .sw_trap = sw_trap,
1127            },
1128        };
1129    }
1130
1131    fn format4f(
1132        op3: u6,
1133        opf_low: u5,
1134        rcond: RCondition,
1135        rs1: Register,
1136        rs2: Register,
1137        rd: Register,
1138    ) Instruction {
1139        return Instruction{
1140            .format_4f = .{
1141                .rd = rd.enc(),
1142                .op3 = op3,
1143                .rs1 = rs1.enc(),
1144                .rcond = @intFromEnum(rcond),
1145                .opf_low = opf_low,
1146                .rs2 = rs2.enc(),
1147            },
1148        };
1149    }
1150
1151    fn format4g(op3: u6, opf_low: u6, opf_cc: u3, cond: Condition, rs2: Register, rd: Register) Instruction {
1152        return Instruction{
1153            .format_4g = .{
1154                .rd = rd.enc(),
1155                .op3 = op3,
1156                .cond = cond.enc(),
1157                .opf_cc = opf_cc,
1158                .opf_low = opf_low,
1159                .rs2 = rs2.enc(),
1160            },
1161        };
1162    }
1163
1164    // SPARCv9 Instruction definition.
1165    // See appendix A of the SPARCv9 ISA manual.
1166
1167    pub fn add(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1168        return switch (s2) {
1169            Register => format3a(0b10, 0b00_0000, rs1, rs2, rd),
1170            i13 => format3b(0b10, 0b00_0000, rs1, rs2, rd),
1171            else => unreachable,
1172        };
1173    }
1174
1175    pub fn addcc(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1176        return switch (s2) {
1177            Register => format3a(0b10, 0b01_0000, rs1, rs2, rd),
1178            i13 => format3b(0b10, 0b01_0000, rs1, rs2, rd),
1179            else => unreachable,
1180        };
1181    }
1182
1183    pub fn bpcc(cond: ICondition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction {
1184        return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);
1185    }
1186
1187    pub fn bpr(cond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
1188        return format2d(0b011, cond, annul, pt, rs1, disp);
1189    }
1190
1191    pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1192        return switch (s2) {
1193            Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),
1194            i13 => format3b(0b10, 0b11_1000, rs1, rs2, rd),
1195            else => unreachable,
1196        };
1197    }
1198
1199    pub fn ldub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1200        return switch (s2) {
1201            Register => format3a(0b11, 0b00_0001, rs1, rs2, rd),
1202            i13 => format3b(0b11, 0b00_0001, rs1, rs2, rd),
1203            else => unreachable,
1204        };
1205    }
1206
1207    pub fn lduh(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1208        return switch (s2) {
1209            Register => format3a(0b11, 0b00_0010, rs1, rs2, rd),
1210            i13 => format3b(0b11, 0b00_0010, rs1, rs2, rd),
1211            else => unreachable,
1212        };
1213    }
1214
1215    pub fn lduw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1216        return switch (s2) {
1217            Register => format3a(0b11, 0b00_0000, rs1, rs2, rd),
1218            i13 => format3b(0b11, 0b00_0000, rs1, rs2, rd),
1219            else => unreachable,
1220        };
1221    }
1222
1223    pub fn ldx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1224        return switch (s2) {
1225            Register => format3a(0b11, 0b00_1011, rs1, rs2, rd),
1226            i13 => format3b(0b11, 0b00_1011, rs1, rs2, rd),
1227            else => unreachable,
1228        };
1229    }
1230
1231    pub fn lduba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1232        return format3i(0b11, 0b01_0001, rs1, rs2, rd, asi);
1233    }
1234
1235    pub fn lduha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1236        return format3i(0b11, 0b01_0010, rs1, rs2, rd, asi);
1237    }
1238
1239    pub fn lduwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1240        return format3i(0b11, 0b01_0000, rs1, rs2, rd, asi);
1241    }
1242
1243    pub fn ldxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1244        return format3i(0b11, 0b01_1011, rs1, rs2, rd, asi);
1245    }
1246
1247    pub fn @"and"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1248        return switch (s2) {
1249            Register => format3a(0b10, 0b00_0001, rs1, rs2, rd),
1250            i13 => format3b(0b10, 0b00_0001, rs1, rs2, rd),
1251            else => unreachable,
1252        };
1253    }
1254
1255    pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1256        return switch (s2) {
1257            Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
1258            i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
1259            else => unreachable,
1260        };
1261    }
1262
1263    pub fn xor(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1264        return switch (s2) {
1265            Register => format3a(0b10, 0b00_0011, rs1, rs2, rd),
1266            i13 => format3b(0b10, 0b00_0011, rs1, rs2, rd),
1267            else => unreachable,
1268        };
1269    }
1270
1271    pub fn xnor(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1272        return switch (s2) {
1273            Register => format3a(0b10, 0b00_0111, rs1, rs2, rd),
1274            i13 => format3b(0b10, 0b00_0111, rs1, rs2, rd),
1275            else => unreachable,
1276        };
1277    }
1278
1279    pub fn membar(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction {
1280        return format3h(cmask, mmask);
1281    }
1282
1283    pub fn movcc(comptime s2: type, cond: Condition, ccr: CCR, rs2: s2, rd: Register) Instruction {
1284        return switch (s2) {
1285            Register => format4c(0b10_1100, cond, ccr, rs2, rd),
1286            i11 => format4d(0b10_1100, cond, ccr, rs2, rd),
1287            else => unreachable,
1288        };
1289    }
1290
1291    pub fn movr(comptime s2: type, cond: RCondition, rs1: Register, rs2: s2, rd: Register) Instruction {
1292        return switch (s2) {
1293            Register => format3e(0b10, 0b10_1111, cond, rs1, rs2, rd),
1294            i10 => format3f(0b10, 0b10_1111, cond, rs1, rs2, rd),
1295            else => unreachable,
1296        };
1297    }
1298
1299    pub fn mulx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1300        return switch (s2) {
1301            Register => format3a(0b10, 0b00_1001, rs1, rs2, rd),
1302            i13 => format3b(0b10, 0b00_1001, rs1, rs2, rd),
1303            else => unreachable,
1304        };
1305    }
1306
1307    pub fn sdivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1308        return switch (s2) {
1309            Register => format3a(0b10, 0b10_1101, rs1, rs2, rd),
1310            i13 => format3b(0b10, 0b10_1101, rs1, rs2, rd),
1311            else => unreachable,
1312        };
1313    }
1314
1315    pub fn udivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1316        return switch (s2) {
1317            Register => format3a(0b10, 0b00_1101, rs1, rs2, rd),
1318            i13 => format3b(0b10, 0b00_1101, rs1, rs2, rd),
1319            else => unreachable,
1320        };
1321    }
1322
1323    pub fn nop() Instruction {
1324        return sethi(0, .g0);
1325    }
1326
1327    pub fn @"return"(comptime s2: type, rs1: Register, rs2: s2) Instruction {
1328        return switch (s2) {
1329            Register => format3c(0b10, 0b11_1001, rs1, rs2),
1330            i13 => format3d(0b10, 0b11_1001, rs1, rs2),
1331            else => unreachable,
1332        };
1333    }
1334
1335    pub fn save(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1336        return switch (s2) {
1337            Register => format3a(0b10, 0b11_1100, rs1, rs2, rd),
1338            i13 => format3b(0b10, 0b11_1100, rs1, rs2, rd),
1339            else => unreachable,
1340        };
1341    }
1342
1343    pub fn restore(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1344        return switch (s2) {
1345            Register => format3a(0b10, 0b11_1101, rs1, rs2, rd),
1346            i13 => format3b(0b10, 0b11_1101, rs1, rs2, rd),
1347            else => unreachable,
1348        };
1349    }
1350
1351    pub fn sethi(imm: u22, rd: Register) Instruction {
1352        return format2a(0b100, imm, rd);
1353    }
1354
1355    pub fn sll(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1356        return switch (s2) {
1357            Register => format3k(0b10, 0b10_0101, .shift32, rs1, rs2, rd),
1358            u5 => format3l(0b10, 0b10_0101, rs1, rs2, rd),
1359            else => unreachable,
1360        };
1361    }
1362
1363    pub fn srl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1364        return switch (s2) {
1365            Register => format3k(0b10, 0b10_0110, .shift32, rs1, rs2, rd),
1366            u5 => format3l(0b10, 0b10_0110, rs1, rs2, rd),
1367            else => unreachable,
1368        };
1369    }
1370
1371    pub fn sra(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1372        return switch (s2) {
1373            Register => format3k(0b10, 0b10_0111, .shift32, rs1, rs2, rd),
1374            u5 => format3l(0b10, 0b10_0111, rs1, rs2, rd),
1375            else => unreachable,
1376        };
1377    }
1378
1379    pub fn sllx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1380        return switch (s2) {
1381            Register => format3k(0b10, 0b10_0101, .shift64, rs1, rs2, rd),
1382            u6 => format3m(0b10, 0b10_0101, rs1, rs2, rd),
1383            else => unreachable,
1384        };
1385    }
1386
1387    pub fn srlx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1388        return switch (s2) {
1389            Register => format3k(0b10, 0b10_0110, .shift64, rs1, rs2, rd),
1390            u6 => format3m(0b10, 0b10_0110, rs1, rs2, rd),
1391            else => unreachable,
1392        };
1393    }
1394
1395    pub fn srax(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1396        return switch (s2) {
1397            Register => format3k(0b10, 0b10_0111, .shift64, rs1, rs2, rd),
1398            u6 => format3m(0b10, 0b10_0111, rs1, rs2, rd),
1399            else => unreachable,
1400        };
1401    }
1402
1403    pub fn stb(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1404        return switch (s2) {
1405            Register => format3a(0b11, 0b00_0101, rs1, rs2, rd),
1406            i13 => format3b(0b11, 0b00_0101, rs1, rs2, rd),
1407            else => unreachable,
1408        };
1409    }
1410
1411    pub fn sth(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1412        return switch (s2) {
1413            Register => format3a(0b11, 0b00_0110, rs1, rs2, rd),
1414            i13 => format3b(0b11, 0b00_0110, rs1, rs2, rd),
1415            else => unreachable,
1416        };
1417    }
1418
1419    pub fn stw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1420        return switch (s2) {
1421            Register => format3a(0b11, 0b00_0100, rs1, rs2, rd),
1422            i13 => format3b(0b11, 0b00_0100, rs1, rs2, rd),
1423            else => unreachable,
1424        };
1425    }
1426
1427    pub fn stx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1428        return switch (s2) {
1429            Register => format3a(0b11, 0b00_1110, rs1, rs2, rd),
1430            i13 => format3b(0b11, 0b00_1110, rs1, rs2, rd),
1431            else => unreachable,
1432        };
1433    }
1434
1435    pub fn stba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1436        return format3i(0b11, 0b01_0101, rs1, rs2, rd, asi);
1437    }
1438
1439    pub fn stha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1440        return format3i(0b11, 0b01_0110, rs1, rs2, rd, asi);
1441    }
1442
1443    pub fn stwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1444        return format3i(0b11, 0b01_0100, rs1, rs2, rd, asi);
1445    }
1446
1447    pub fn stxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction {
1448        return format3i(0b11, 0b01_1110, rs1, rs2, rd, asi);
1449    }
1450
1451    pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1452        return switch (s2) {
1453            Register => format3a(0b10, 0b00_0100, rs1, rs2, rd),
1454            i13 => format3b(0b10, 0b00_0100, rs1, rs2, rd),
1455            else => unreachable,
1456        };
1457    }
1458
1459    pub fn subcc(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1460        return switch (s2) {
1461            Register => format3a(0b10, 0b01_0100, rs1, rs2, rd),
1462            i13 => format3b(0b10, 0b01_0100, rs1, rs2, rd),
1463            else => unreachable,
1464        };
1465    }
1466
1467    pub fn trap(comptime s2: type, cond: ICondition, ccr: CCR, rs1: Register, rs2: s2) Instruction {
1468        // Tcc instructions abuse the rd field to store the conditionals.
1469        return switch (s2) {
1470            Register => format4a(0b11_1010, ccr, rs1, rs2, @as(Register, @enumFromInt(@intFromEnum(cond)))),
1471            u7 => format4e(0b11_1010, ccr, rs1, @as(Register, @enumFromInt(@intFromEnum(cond))), rs2),
1472            else => unreachable,
1473        };
1474    }
1475};
1476
1477test "Serialize formats" {
1478    const Testcase = struct {
1479        inst: Instruction,
1480        expected: u32,
1481    };
1482
1483    // Note that the testcases might or might not be a valid instruction
1484    // This is mostly just to check the behavior of the format packed structs
1485    // since currently stage1 doesn't properly implement it in all cases
1486    const testcases = [_]Testcase{
1487        .{
1488            .inst = Instruction.format1(4),
1489            .expected = 0b01_000000000000000000000000000001,
1490        },
1491        .{
1492            .inst = Instruction.format2a(4, 0, .g0),
1493            .expected = 0b00_00000_100_0000000000000000000000,
1494        },
1495        .{
1496            .inst = Instruction.format2b(6, .{ .icond = .lt }, true, -4),
1497            .expected = 0b00_1_0011_110_1111111111111111111111,
1498        },
1499        .{
1500            .inst = Instruction.format2c(3, .{ .icond = .nv }, false, true, .xcc, 8),
1501            .expected = 0b00_0_0000_011_1_0_1_0000000000000000010,
1502        },
1503        .{
1504            .inst = Instruction.format2d(7, .eq_zero, false, true, .o0, 20),
1505            .expected = 0b00_0_0_001_111_00_1_01000_00000000000101,
1506        },
1507        .{
1508            .inst = Instruction.format3a(3, 5, .g0, .o1, .l2),
1509            .expected = 0b11_10010_000101_00000_0_00000000_01001,
1510        },
1511        .{
1512            .inst = Instruction.format3b(3, 5, .g0, -1, .l2),
1513            .expected = 0b11_10010_000101_00000_1_1111111111111,
1514        },
1515        .{
1516            .inst = Instruction.format3c(3, 5, .g0, .o1),
1517            .expected = 0b11_00000_000101_00000_0_00000000_01001,
1518        },
1519        .{
1520            .inst = Instruction.format3d(3, 5, .g0, 0),
1521            .expected = 0b11_00000_000101_00000_1_0000000000000,
1522        },
1523        .{
1524            .inst = Instruction.format3e(3, 5, .ne_zero, .g0, .o1, .l2),
1525            .expected = 0b11_10010_000101_00000_0_101_00000_01001,
1526        },
1527        .{
1528            .inst = Instruction.format3f(3, 5, .ne_zero, .g0, -1, .l2),
1529            .expected = 0b11_10010_000101_00000_1_101_1111111111,
1530        },
1531        .{
1532            .inst = Instruction.format3g(3, 5, .g0, .o1, .l2),
1533            .expected = 0b11_10010_000101_00000_1_00000000_01001,
1534        },
1535        .{
1536            .inst = Instruction.format3h(.{}, .{}),
1537            .expected = 0b10_00000_101000_01111_1_000000_000_0000,
1538        },
1539        .{
1540            .inst = Instruction.format3i(3, 5, .g0, .o1, .l2, .asi_primary_little),
1541            .expected = 0b11_10010_000101_00000_0_10001000_01001,
1542        },
1543        .{
1544            .inst = Instruction.format3j(3, 5, 31, 0),
1545            .expected = 0b11_11111_000101_0000000000000000000,
1546        },
1547        .{
1548            .inst = Instruction.format3k(3, 5, .shift32, .g0, .o1, .l2),
1549            .expected = 0b11_10010_000101_00000_0_0_0000000_01001,
1550        },
1551        .{
1552            .inst = Instruction.format3l(3, 5, .g0, 31, .l2),
1553            .expected = 0b11_10010_000101_00000_1_0_0000000_11111,
1554        },
1555        .{
1556            .inst = Instruction.format3m(3, 5, .g0, 63, .l2),
1557            .expected = 0b11_10010_000101_00000_1_1_000000_111111,
1558        },
1559        .{
1560            .inst = Instruction.format3n(3, 5, 0, .o1, .l2),
1561            .expected = 0b11_10010_000101_00000_000000000_01001,
1562        },
1563        .{
1564            .inst = Instruction.format3o(3, 5, 0, .xcc, .o1, .l2),
1565            .expected = 0b11_000_1_0_000101_01001_000000000_10010,
1566        },
1567        .{
1568            .inst = Instruction.format3p(3, 5, 0, .g0, .o1, .l2),
1569            .expected = 0b11_10010_000101_00000_000000000_01001,
1570        },
1571        .{
1572            .inst = Instruction.format3q(3, 5, .g0, .o1),
1573            .expected = 0b11_01001_000101_00000_00000000000000,
1574        },
1575        .{
1576            .inst = Instruction.format3r(3, 5, 4),
1577            .expected = 0b11_00100_000101_0000000000000000000,
1578        },
1579        .{
1580            .inst = Instruction.format3s(3, 5, .g0),
1581            .expected = 0b11_00000_000101_0000000000000000000,
1582        },
1583        .{
1584            .inst = Instruction.format4a(8, .xcc, .g0, .o1, .l2),
1585            .expected = 0b10_10010_001000_00000_0_1_0_000000_01001,
1586        },
1587        .{
1588            .inst = Instruction.format4b(8, .xcc, .g0, -1, .l2),
1589            .expected = 0b10_10010_001000_00000_1_1_0_11111111111,
1590        },
1591        .{
1592            .inst = Instruction.format4c(8, .{ .icond = .nv }, .xcc, .g0, .o1),
1593            .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000,
1594        },
1595        .{
1596            .inst = Instruction.format4d(8, .{ .icond = .nv }, .xcc, 0, .l2),
1597            .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000,
1598        },
1599        .{
1600            .inst = Instruction.format4e(8, .xcc, .g0, .o1, 0),
1601            .expected = 0b10_01001_001000_00000_1_1_0_0000_0000000,
1602        },
1603        .{
1604            .inst = Instruction.format4f(8, 4, .eq_zero, .g0, .o1, .l2),
1605            .expected = 0b10_10010_001000_00000_0_001_00100_01001,
1606        },
1607        .{
1608            .inst = Instruction.format4g(8, 4, 2, .{ .icond = .nv }, .o1, .l2),
1609            .expected = 0b10_10010_001000_0_0000_010_000100_01001,
1610        },
1611    };
1612
1613    for (testcases) |case| {
1614        const actual = case.inst.toU32();
1615        testing.expectEqual(case.expected, actual) catch |err| {
1616            std.debug.print("error: {}\n", .{err});
1617            std.debug.print("case: {}\n", .{case});
1618            return err;
1619        };
1620    }
1621}