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}