| ... | ... | @@ -0,0 +1,1101 @@ |
| 1 | const std = @import("std"); |
| 2 | const DW = std.dwarf; |
| 3 | const assert = std.debug.assert; |
| 4 | const testing = std.testing; |
| 5 | |
| 6 | /// General purpose registers in the SPARCv9 instruction set |
| 7 | pub const Register = enum(u6) { |
| 8 | // zig fmt: off |
| 9 | g0, g1, g2, g3, g4, g5, g6, g7, |
| 10 | o0, o1, o2, o3, o4, o5, o6, o7, |
| 11 | l0, l1, l2, l3, l4, l5, l6, l7, |
| 12 | @"i0", @"i1", @"i2", @"i3", @"i4", @"i5", @"i6", @"i7", |
| 13 | |
| 14 | sp = 46, // stack pointer (o6) |
| 15 | fp = 62, // frame pointer (i6) |
| 16 | // zig fmt: on |
| 17 | |
| 18 | pub fn id(self: Register) u5 { |
| 19 | return @truncate(u5, @enumToInt(self)); |
| 20 | } |
| 21 | |
| 22 | pub fn enc(self: Register) u5 { |
| 23 | // For integer registers, enc() == id(). |
| 24 | return self.id(); |
| 25 | } |
| 26 | |
| 27 | pub fn dwarfLocOp(reg: Register) u8 { |
| 28 | return @as(u8, reg.id()) + DW.OP.reg0; |
| 29 | } |
| 30 | }; |
| 31 | |
| 32 | test "Register.id" { |
| 33 | // SP |
| 34 | try testing.expectEqual(@as(u5, 14), Register.o6.id()); |
| 35 | try testing.expectEqual(Register.o6.id(), Register.sp.id()); |
| 36 | |
| 37 | // FP |
| 38 | try testing.expectEqual(@as(u5, 30), Register.@"i6".id()); |
| 39 | try testing.expectEqual(Register.@"i6".id(), Register.fp.id()); |
| 40 | |
| 41 | // x0 |
| 42 | try testing.expectEqual(@as(u5, 0), Register.g0.id()); |
| 43 | try testing.expectEqual(@as(u5, 8), Register.o0.id()); |
| 44 | try testing.expectEqual(@as(u5, 16), Register.l0.id()); |
| 45 | try testing.expectEqual(@as(u5, 24), Register.@"i0".id()); |
| 46 | } |
| 47 | |
| 48 | test "Register.enc" { |
| 49 | // x0 |
| 50 | try testing.expectEqual(@as(u5, 0), Register.g0.enc()); |
| 51 | try testing.expectEqual(@as(u5, 8), Register.o0.enc()); |
| 52 | try testing.expectEqual(@as(u5, 16), Register.l0.enc()); |
| 53 | try testing.expectEqual(@as(u5, 24), Register.@"i0".enc()); |
| 54 | |
| 55 | // For integer registers, enc() == id(). |
| 56 | try testing.expectEqual(Register.g0.enc(), Register.g0.id()); |
| 57 | try testing.expectEqual(Register.o0.enc(), Register.o0.id()); |
| 58 | try testing.expectEqual(Register.l0.enc(), Register.l0.id()); |
| 59 | try testing.expectEqual(Register.@"i0".enc(), Register.@"i0".id()); |
| 60 | } |
| 61 | |
| 62 | /// Scalar floating point registers in the SPARCv9 instruction set |
| 63 | pub const FloatingPointRegister = enum(u7) { |
| 64 | // SPARCv9 has 64 f32 registers, 32 f64 registers, and 16 f128 registers, |
| 65 | // which are aliased in this way: |
| 66 | // |
| 67 | // | %d0 | %d2 | |
| 68 | // %q0 | %f0 | %f1 | %f2 | %f3 | |
| 69 | // | %d4 | %d6 | |
| 70 | // %q4 | %f4 | %f5 | %f6 | %f7 | |
| 71 | // ... |
| 72 | // | %d60 | %d62 | |
| 73 | // %q60 | %f60 | %f61 | %f62 | %f63 | |
| 74 | // |
| 75 | // Though, since the instructions uses five-bit addressing, only %f0-%f31 |
| 76 | // is usable with f32 instructions. |
| 77 | |
| 78 | // zig fmt: off |
| 79 | |
| 80 | // 32-bit registers |
| 81 | @"f0", @"f1", @"f2", @"f3", @"f4", @"f5", @"f6", @"f7", |
| 82 | @"f8", @"f9", @"f10", @"f11", @"f12", @"f13", @"f14", @"f15", |
| 83 | @"f16", @"f17", @"f18", @"f19", @"f20", @"f21", @"f22", @"f23", |
| 84 | @"f24", @"f25", @"f26", @"f27", @"f28", @"f29", @"f30", @"f31", |
| 85 | |
| 86 | // 64-bit registers |
| 87 | d0, d2, d4, d6, d8, d10, d12, d14, |
| 88 | d16, d18, d20, d22, d24, d26, d28, d30, |
| 89 | d32, d34, d36, d38, d40, d42, d44, d46, |
| 90 | d48, d50, d52, d54, d56, d58, d60, d62, |
| 91 | |
| 92 | // 128-bit registers |
| 93 | q0, q4, q8, q12, q16, q20, q24, q28, |
| 94 | q32, q36, q40, q44, q48, q52, q56, q60, |
| 95 | // zig fmt: on |
| 96 | |
| 97 | pub fn id(self: FloatingPointRegister) u6 { |
| 98 | return switch (self.size()) { |
| 99 | 32 => @truncate(u6, @enumToInt(self)), |
| 100 | 64 => @truncate(u6, (@enumToInt(self) - 32) * 2), |
| 101 | 128 => @truncate(u6, (@enumToInt(self) - 64) * 4), |
| 102 | else => unreachable, |
| 103 | }; |
| 104 | } |
| 105 | |
| 106 | pub fn enc(self: FloatingPointRegister) u5 { |
| 107 | // Floating point registers use an encoding scheme to map from the 6-bit |
| 108 | // ID to 5-bit encoded value. |
| 109 | // (See section 5.1.4.1 of SPARCv9 ISA specification) |
| 110 | |
| 111 | const reg_id = self.id(); |
| 112 | return @truncate(u5, reg_id | (reg_id >> 5)); |
| 113 | } |
| 114 | |
| 115 | /// Returns the bit-width of the register. |
| 116 | pub fn size(self: FloatingPointRegister) u8 { |
| 117 | return switch (@enumToInt(self)) { |
| 118 | 0...31 => 32, |
| 119 | 32...63 => 64, |
| 120 | 64...79 => 128, |
| 121 | else => unreachable, |
| 122 | }; |
| 123 | } |
| 124 | }; |
| 125 | |
| 126 | test "FloatingPointRegister.id" { |
| 127 | // Low region |
| 128 | try testing.expectEqual(@as(u6, 0), FloatingPointRegister.q0.id()); |
| 129 | try testing.expectEqual(FloatingPointRegister.q0.id(), FloatingPointRegister.d0.id()); |
| 130 | try testing.expectEqual(FloatingPointRegister.d0.id(), FloatingPointRegister.@"f0".id()); |
| 131 | |
| 132 | try testing.expectEqual(@as(u6, 28), FloatingPointRegister.q28.id()); |
| 133 | try testing.expectEqual(FloatingPointRegister.q28.id(), FloatingPointRegister.d28.id()); |
| 134 | try testing.expectEqual(FloatingPointRegister.d28.id(), FloatingPointRegister.@"f28".id()); |
| 135 | |
| 136 | // High region |
| 137 | try testing.expectEqual(@as(u6, 32), FloatingPointRegister.q32.id()); |
| 138 | try testing.expectEqual(FloatingPointRegister.q32.id(), FloatingPointRegister.d32.id()); |
| 139 | |
| 140 | try testing.expectEqual(@as(u6, 60), FloatingPointRegister.q60.id()); |
| 141 | try testing.expectEqual(FloatingPointRegister.q60.id(), FloatingPointRegister.d60.id()); |
| 142 | } |
| 143 | |
| 144 | test "FloatingPointRegister.enc" { |
| 145 | // f registers |
| 146 | try testing.expectEqual(@as(u5, 0), FloatingPointRegister.@"f0".enc()); |
| 147 | try testing.expectEqual(@as(u5, 1), FloatingPointRegister.@"f1".enc()); |
| 148 | try testing.expectEqual(@as(u5, 31), FloatingPointRegister.@"f31".enc()); |
| 149 | |
| 150 | // d registers |
| 151 | try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.enc()); |
| 152 | try testing.expectEqual(@as(u5, 1), FloatingPointRegister.d32.enc()); |
| 153 | try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d62.enc()); |
| 154 | |
| 155 | // q registers |
| 156 | try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.enc()); |
| 157 | try testing.expectEqual(@as(u5, 1), FloatingPointRegister.q32.enc()); |
| 158 | try testing.expectEqual(@as(u5, 29), FloatingPointRegister.q60.enc()); |
| 159 | } |
| 160 | |
| 161 | /// Represents an instruction in the SPARCv9 instruction set |
| 162 | pub const Instruction = union(enum) { |
| 163 | // Some of the instruction formats have several minor formats, here I |
| 164 | // name them with letters since there's no official naming scheme. |
| 165 | // TODO: need to rename the minor formats to a more descriptive name. |
| 166 | |
| 167 | // Format 1 (op = 1): CALL |
| 168 | format_1: packed struct { |
| 169 | op: u2 = 0b01, |
| 170 | disp30: u30, |
| 171 | }, |
| 172 | |
| 173 | // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc) |
| 174 | format_2a: packed struct { |
| 175 | op: u2 = 0b00, |
| 176 | rd: u5, |
| 177 | op2: u3, |
| 178 | imm22: u22, |
| 179 | }, |
| 180 | format_2b: packed struct { |
| 181 | op: u2 = 0b00, |
| 182 | a: u1, |
| 183 | cond: u4, |
| 184 | op2: u3, |
| 185 | disp22: u22, |
| 186 | }, |
| 187 | format_2c: packed struct { |
| 188 | op: u2 = 0b00, |
| 189 | a: u1, |
| 190 | cond: u4, |
| 191 | op2: u3, |
| 192 | cc1: u1, |
| 193 | cc0: u1, |
| 194 | p: u1, |
| 195 | disp19: u19, |
| 196 | }, |
| 197 | format_2d: packed struct { |
| 198 | op: u2 = 0b00, |
| 199 | a: u1, |
| 200 | fixed: u1 = 0b0, |
| 201 | rcond: u3, |
| 202 | op2: u3, |
| 203 | d16hi: u2, |
| 204 | p: u1, |
| 205 | rs1: u5, |
| 206 | d16lo: u14, |
| 207 | }, |
| 208 | |
| 209 | // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store |
| 210 | format_3a: packed struct { |
| 211 | op: u2, |
| 212 | rd: u5, |
| 213 | op3: u6, |
| 214 | rs1: u5, |
| 215 | i: u1 = 0b0, |
| 216 | reserved: u8 = 0b00000000, |
| 217 | rs2: u5, |
| 218 | }, |
| 219 | format_3b: struct { |
| 220 | op: u2, |
| 221 | rd: u5, |
| 222 | op3: u6, |
| 223 | rs1: u5, |
| 224 | i: u1 = 0b1, |
| 225 | simm13: u13, |
| 226 | }, |
| 227 | format_3c: packed struct { |
| 228 | op: u2, |
| 229 | reserved1: u5 = 0b00000, |
| 230 | op3: u6, |
| 231 | rs1: u5, |
| 232 | i: u1 = 0b0, |
| 233 | reserved2: u8 = 0b00000000, |
| 234 | rs2: u5, |
| 235 | }, |
| 236 | format_3d: struct { |
| 237 | op: u2, |
| 238 | reserved: u5 = 0b00000, |
| 239 | op3: u6, |
| 240 | rs1: u5, |
| 241 | i: u1 = 0b1, |
| 242 | simm13: u13, |
| 243 | }, |
| 244 | format_3e: packed struct { |
| 245 | op: u2, |
| 246 | rd: u5, |
| 247 | op3: u6, |
| 248 | rs1: u5, |
| 249 | i: u1 = 0b0, |
| 250 | rcond: u3, |
| 251 | reserved: u5 = 0b00000, |
| 252 | rs2: u5, |
| 253 | }, |
| 254 | format_3f: struct { |
| 255 | op: u2, |
| 256 | rd: u5, |
| 257 | op3: u6, |
| 258 | rs1: u5, |
| 259 | i: u1 = 0b1, |
| 260 | rcond: u3, |
| 261 | simm10: u10, |
| 262 | }, |
| 263 | format_3g: packed struct { |
| 264 | op: u2, |
| 265 | rd: u5, |
| 266 | op3: u6, |
| 267 | rs1: u5, |
| 268 | i: u1 = 0b1, |
| 269 | reserved: u8 = 0b00000000, |
| 270 | rs2: u5, |
| 271 | }, |
| 272 | format_3h: packed struct { |
| 273 | op: u2 = 0b10, |
| 274 | fixed1: u5 = 0b00000, |
| 275 | op3: u6 = 0b101000, |
| 276 | fixed2: u5 = 0b01111, |
| 277 | i: u1 = 0b1, |
| 278 | reserved: u6 = 0b000000, |
| 279 | cmask: u3, |
| 280 | mmask: u4, |
| 281 | }, |
| 282 | format_3i: packed struct { |
| 283 | op: u2, |
| 284 | rd: u5, |
| 285 | op3: u6, |
| 286 | rs1: u5, |
| 287 | i: u1 = 0b0, |
| 288 | imm_asi: u8, |
| 289 | rs2: u5, |
| 290 | }, |
| 291 | format_3j: packed struct { |
| 292 | op: u2, |
| 293 | impl_dep1: u5, |
| 294 | op3: u6, |
| 295 | impl_dep2: u19, |
| 296 | }, |
| 297 | format_3k: packed struct { |
| 298 | op: u2, |
| 299 | rd: u5, |
| 300 | op3: u6, |
| 301 | rs1: u5, |
| 302 | i: u1 = 0b0, |
| 303 | x: u1, |
| 304 | reserved: u7 = 0b0000000, |
| 305 | rs2: u5, |
| 306 | }, |
| 307 | format_3l: packed struct { |
| 308 | op: u2, |
| 309 | rd: u5, |
| 310 | op3: u6, |
| 311 | rs1: u5, |
| 312 | i: u1 = 0b1, |
| 313 | x: u1 = 0b0, |
| 314 | reserved: u7 = 0b0000000, |
| 315 | shcnt32: u5, |
| 316 | }, |
| 317 | format_3m: packed struct { |
| 318 | op: u2, |
| 319 | rd: u5, |
| 320 | op3: u6, |
| 321 | rs1: u5, |
| 322 | i: u1 = 0b1, |
| 323 | x: u1 = 0b1, |
| 324 | reserved: u6 = 0b000000, |
| 325 | shcnt64: u6, |
| 326 | }, |
| 327 | format_3n: packed struct { |
| 328 | op: u2, |
| 329 | rd: u5, |
| 330 | op3: u6, |
| 331 | reserved: u5 = 0b00000, |
| 332 | opf: u9, |
| 333 | rs2: u5, |
| 334 | }, |
| 335 | format_3o: packed struct { |
| 336 | op: u2, |
| 337 | fixed: u3 = 0b000, |
| 338 | cc1: u1, |
| 339 | cc0: u1, |
| 340 | op3: u6, |
| 341 | rs1: u5, |
| 342 | opf: u9, |
| 343 | rs2: u5, |
| 344 | }, |
| 345 | format_3p: packed struct { |
| 346 | op: u2, |
| 347 | rd: u5, |
| 348 | op3: u6, |
| 349 | rs1: u5, |
| 350 | opf: u9, |
| 351 | rs2: u5, |
| 352 | }, |
| 353 | format_3q: packed struct { |
| 354 | op: u2, |
| 355 | rd: u5, |
| 356 | op3: u6, |
| 357 | rs1: u5, |
| 358 | reserved: u14 = 0b00000000000000, |
| 359 | }, |
| 360 | format_3r: packed struct { |
| 361 | op: u2, |
| 362 | fcn: u5, |
| 363 | op3: u6, |
| 364 | reserved: u19 = 0b0000000000000000000, |
| 365 | }, |
| 366 | format_3s: packed struct { |
| 367 | op: u2, |
| 368 | rd: u5, |
| 369 | op3: u6, |
| 370 | reserved: u19 = 0b0000000000000000000, |
| 371 | }, |
| 372 | |
| 373 | //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc |
| 374 | format_4a: packed struct { |
| 375 | op: u2 = 0b10, |
| 376 | rd: u5, |
| 377 | op3: u6, |
| 378 | rs1: u5, |
| 379 | i: u1 = 0b0, |
| 380 | cc1: u1, |
| 381 | cc0: u1, |
| 382 | reserved: u6 = 0b000000, |
| 383 | rs2: u5, |
| 384 | }, |
| 385 | format_4b: struct { |
| 386 | op: u2 = 0b10, |
| 387 | rd: u5, |
| 388 | op3: u6, |
| 389 | rs1: u5, |
| 390 | i: u1 = 0b1, |
| 391 | cc1: u1, |
| 392 | cc0: u1, |
| 393 | simm11: u11, |
| 394 | }, |
| 395 | format_4c: packed struct { |
| 396 | op: u2 = 0b10, |
| 397 | rd: u5, |
| 398 | op3: u6, |
| 399 | cc2: u1, |
| 400 | cond: u4, |
| 401 | i: u1 = 0b0, |
| 402 | cc1: u1, |
| 403 | cc0: u1, |
| 404 | reserved: u6 = 0b000000, |
| 405 | rs2: u5, |
| 406 | }, |
| 407 | format_4d: struct { |
| 408 | op: u2 = 0b10, |
| 409 | rd: u5, |
| 410 | op3: u6, |
| 411 | cc2: u1, |
| 412 | cond: u4, |
| 413 | i: u1 = 0b1, |
| 414 | cc1: u1, |
| 415 | cc0: u1, |
| 416 | simm11: u11, |
| 417 | }, |
| 418 | format_4e: packed struct { |
| 419 | op: u2 = 0b10, |
| 420 | rd: u5, |
| 421 | op3: u6, |
| 422 | rs1: u5, |
| 423 | i: u1 = 0b1, |
| 424 | cc1: u1, |
| 425 | cc0: u1, |
| 426 | reserved: u4 = 0b0000, |
| 427 | sw_trap: u7, |
| 428 | }, |
| 429 | format_4f: packed struct { |
| 430 | op: u2 = 0b10, |
| 431 | rd: u5, |
| 432 | op3: u6, |
| 433 | rs1: u5, |
| 434 | fixed: u1 = 0b0, |
| 435 | rcond: u3, |
| 436 | opf_low: u5, |
| 437 | rs2: u5, |
| 438 | }, |
| 439 | format_4g: packed struct { |
| 440 | op: u2 = 0b10, |
| 441 | rd: u5, |
| 442 | op3: u6, |
| 443 | fixed: u1 = 0b0, |
| 444 | cond: u4, |
| 445 | opf_cc: u3, |
| 446 | opf_low: u6, |
| 447 | rs2: u5, |
| 448 | }, |
| 449 | |
| 450 | pub const CCR = enum(u3) { |
| 451 | fcc0, |
| 452 | fcc1, |
| 453 | fcc2, |
| 454 | fcc3, |
| 455 | icc, |
| 456 | reserved1, |
| 457 | xcc, |
| 458 | reserved2, |
| 459 | }; |
| 460 | |
| 461 | pub const RCondition = enum(u3) { |
| 462 | reserved1, |
| 463 | eq_zero, |
| 464 | le_zero, |
| 465 | lt_zero, |
| 466 | reserved2, |
| 467 | ne_zero, |
| 468 | gt_zero, |
| 469 | ge_zero, |
| 470 | }; |
| 471 | |
| 472 | pub const ASI = enum(u8) { |
| 473 | asi_nucleus = 0x04, |
| 474 | asi_nucleus_little = 0x0c, |
| 475 | asi_as_if_user_primary = 0x10, |
| 476 | asi_as_if_user_secondary = 0x11, |
| 477 | asi_as_if_user_primary_little = 0x18, |
| 478 | asi_as_if_user_secondary_little = 0x19, |
| 479 | asi_primary = 0x80, |
| 480 | asi_secondary = 0x81, |
| 481 | asi_primary_nofault = 0x82, |
| 482 | asi_secondary_nofault = 0x83, |
| 483 | asi_primary_little = 0x88, |
| 484 | asi_secondary_little = 0x89, |
| 485 | asi_primary_nofault_little = 0x8a, |
| 486 | asi_secondary_nofault_little = 0x8b, |
| 487 | }; |
| 488 | |
| 489 | pub const ShiftWidth = enum(u1) { |
| 490 | shift32, |
| 491 | shift64, |
| 492 | }; |
| 493 | |
| 494 | pub const MemOrderingConstraint = packed struct { |
| 495 | store_store: bool = false, |
| 496 | load_store: bool = false, |
| 497 | store_load: bool = false, |
| 498 | load_load: bool = false, |
| 499 | }; |
| 500 | |
| 501 | pub const MemCompletionConstraint = packed struct { |
| 502 | sync: bool = false, |
| 503 | mem_issue: bool = false, |
| 504 | lookaside: bool = false, |
| 505 | }; |
| 506 | |
| 507 | // TODO: Need to define an enum for `cond` values |
| 508 | // This is kinda challenging since the cond values have different meanings |
| 509 | // depending on whether it's operating on integer or FP CCR. |
| 510 | pub const Condition = u4; |
| 511 | |
| 512 | pub fn toU32(self: Instruction) u32 { |
| 513 | // TODO: Remove this once packed structs work. |
| 514 | return switch (self) { |
| 515 | .format_1 => |v| @bitCast(u32, v), |
| 516 | .format_2a => |v| @bitCast(u32, v), |
| 517 | .format_2b => |v| @bitCast(u32, v), |
| 518 | .format_2c => |v| @bitCast(u32, v), |
| 519 | .format_2d => |v| @bitCast(u32, v), |
| 520 | .format_3a => |v| @bitCast(u32, v), |
| 521 | .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), |
| 522 | .format_3c => |v| @bitCast(u32, v), |
| 523 | .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), |
| 524 | .format_3e => |v| @bitCast(u32, v), |
| 525 | .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), |
| 526 | .format_3g => |v| @bitCast(u32, v), |
| 527 | .format_3h => |v| @bitCast(u32, v), |
| 528 | .format_3i => |v| @bitCast(u32, v), |
| 529 | .format_3j => |v| @bitCast(u32, v), |
| 530 | .format_3k => |v| @bitCast(u32, v), |
| 531 | .format_3l => |v| @bitCast(u32, v), |
| 532 | .format_3m => |v| @bitCast(u32, v), |
| 533 | .format_3n => |v| @bitCast(u32, v), |
| 534 | .format_3o => |v| @bitCast(u32, v), |
| 535 | .format_3p => |v| @bitCast(u32, v), |
| 536 | .format_3q => |v| @bitCast(u32, v), |
| 537 | .format_3r => |v| @bitCast(u32, v), |
| 538 | .format_3s => |v| @bitCast(u32, v), |
| 539 | .format_4a => |v| @bitCast(u32, v), |
| 540 | .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), |
| 541 | .format_4c => |v| @bitCast(u32, v), |
| 542 | .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), |
| 543 | .format_4e => |v| @bitCast(u32, v), |
| 544 | .format_4f => |v| @bitCast(u32, v), |
| 545 | .format_4g => |v| @bitCast(u32, v), |
| 546 | }; |
| 547 | } |
| 548 | |
| 549 | fn format1(disp: i32) Instruction { |
| 550 | const udisp = @bitCast(u32, disp); |
| 551 | |
| 552 | // In SPARC, branch target needs to be aligned to 4 bytes. |
| 553 | assert(udisp % 4 == 0); |
| 554 | |
| 555 | // Discard the last two bits since those are implicitly zero. |
| 556 | const udisp_truncated = @truncate(u30, udisp >> 2); |
| 557 | return Instruction{ |
| 558 | .format_1 = .{ |
| 559 | .disp30 = udisp_truncated, |
| 560 | }, |
| 561 | }; |
| 562 | } |
| 563 | |
| 564 | fn format2a(op2: u3, rd: Register, imm: u22) Instruction { |
| 565 | return Instruction{ |
| 566 | .format_2a = .{ |
| 567 | .rd = rd.enc(), |
| 568 | .op2 = op2, |
| 569 | .imm22 = imm, |
| 570 | }, |
| 571 | }; |
| 572 | } |
| 573 | |
| 574 | fn format2b(op2: u3, cond: Condition, annul: bool, disp: i24) Instruction { |
| 575 | const udisp = @bitCast(u24, disp); |
| 576 | |
| 577 | // In SPARC, branch target needs to be aligned to 4 bytes. |
| 578 | assert(udisp % 4 == 0); |
| 579 | |
| 580 | // Discard the last two bits since those are implicitly zero. |
| 581 | const udisp_truncated = @truncate(u22, udisp >> 2); |
| 582 | return Instruction{ |
| 583 | .format_2b = .{ |
| 584 | .a = @boolToInt(annul), |
| 585 | .cond = cond, |
| 586 | .op2 = op2, |
| 587 | .disp22 = udisp_truncated, |
| 588 | }, |
| 589 | }; |
| 590 | } |
| 591 | |
| 592 | fn format2c(op2: u3, cond: Condition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction { |
| 593 | const udisp = @bitCast(u21, disp); |
| 594 | |
| 595 | // In SPARC, branch target needs to be aligned to 4 bytes. |
| 596 | assert(udisp % 4 == 0); |
| 597 | |
| 598 | // Discard the last two bits since those are implicitly zero. |
| 599 | const udisp_truncated = @truncate(u19, udisp >> 2); |
| 600 | |
| 601 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 602 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 603 | return Instruction{ |
| 604 | .format_2c = .{ |
| 605 | .a = @boolToInt(annul), |
| 606 | .cond = cond, |
| 607 | .op2 = op2, |
| 608 | .cc1 = ccr_cc1, |
| 609 | .cc0 = ccr_cc0, |
| 610 | .p = @boolToInt(pt), |
| 611 | .disp19 = udisp_truncated, |
| 612 | }, |
| 613 | }; |
| 614 | } |
| 615 | |
| 616 | fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction { |
| 617 | const udisp = @bitCast(u18, disp); |
| 618 | |
| 619 | // In SPARC, branch target needs to be aligned to 4 bytes. |
| 620 | assert(udisp % 4 == 0); |
| 621 | |
| 622 | // Discard the last two bits since those are implicitly zero, |
| 623 | // and split it into low and high parts. |
| 624 | const udisp_truncated = @truncate(u16, udisp >> 2); |
| 625 | const udisp_hi = @truncate(u2, (udisp_truncated & 0b1100_0000_0000_0000) >> 14); |
| 626 | const udisp_lo = @truncate(u14, udisp_truncated & 0b0011_1111_1111_1111); |
| 627 | return Instruction{ |
| 628 | .format_2d = .{ |
| 629 | .a = @boolToInt(annul), |
| 630 | .rcond = @enumToInt(rcond), |
| 631 | .op2 = op2, |
| 632 | .p = @boolToInt(pt), |
| 633 | .rs1 = rs1.enc(), |
| 634 | .d16hi = udisp_hi, |
| 635 | .d16lo = udisp_lo, |
| 636 | }, |
| 637 | }; |
| 638 | } |
| 639 | |
| 640 | fn format3a(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 641 | return Instruction{ |
| 642 | .format_3a = .{ |
| 643 | .op = op, |
| 644 | .rd = rd.enc(), |
| 645 | .op3 = op3, |
| 646 | .rs1 = rs1.enc(), |
| 647 | .rs2 = rs2.enc(), |
| 648 | }, |
| 649 | }; |
| 650 | } |
| 651 | fn format3b(op: u2, op3: u6, rs1: Register, imm: i13, rd: Register) Instruction { |
| 652 | return Instruction{ |
| 653 | .format_3b = .{ |
| 654 | .op = op, |
| 655 | .rd = rd.enc(), |
| 656 | .op3 = op3, |
| 657 | .rs1 = rs1.enc(), |
| 658 | .simm13 = @bitCast(u13, imm), |
| 659 | }, |
| 660 | }; |
| 661 | } |
| 662 | fn format3c(op: u2, op3: u6, rs1: Register, rs2: Register) Instruction { |
| 663 | return Instruction{ |
| 664 | .format_3c = .{ |
| 665 | .op = op, |
| 666 | .op3 = op3, |
| 667 | .rs1 = rs1.enc(), |
| 668 | .rs2 = rs2.enc(), |
| 669 | }, |
| 670 | }; |
| 671 | } |
| 672 | fn format3d(op: u2, op3: u6, rs1: Register, imm: i13) Instruction { |
| 673 | return Instruction{ |
| 674 | .format_3d = .{ |
| 675 | .op = op, |
| 676 | .op3 = op3, |
| 677 | .rs1 = rs1.enc(), |
| 678 | .simm13 = @bitCast(u13, imm), |
| 679 | }, |
| 680 | }; |
| 681 | } |
| 682 | fn format3e(op: u2, op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 683 | return Instruction{ |
| 684 | .format_3e = .{ |
| 685 | .op = op, |
| 686 | .rd = rd.enc(), |
| 687 | .op3 = op3, |
| 688 | .rs1 = rs1.enc(), |
| 689 | .rcond = @enumToInt(rcond), |
| 690 | .rs2 = rs2.enc(), |
| 691 | }, |
| 692 | }; |
| 693 | } |
| 694 | fn format3f(op: u2, op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction { |
| 695 | return Instruction{ |
| 696 | .format_3f = .{ |
| 697 | .op = op, |
| 698 | .rd = rd.enc(), |
| 699 | .op3 = op3, |
| 700 | .rs1 = rs1.enc(), |
| 701 | .rcond = @enumToInt(rcond), |
| 702 | .simm10 = @bitCast(u10, imm), |
| 703 | }, |
| 704 | }; |
| 705 | } |
| 706 | fn format3g(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 707 | return Instruction{ |
| 708 | .format_3g = .{ |
| 709 | .op = op, |
| 710 | .rd = rd.enc(), |
| 711 | .op3 = op3, |
| 712 | .rs1 = rs1.enc(), |
| 713 | .rs2 = rs2.enc(), |
| 714 | }, |
| 715 | }; |
| 716 | } |
| 717 | fn format3h(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction { |
| 718 | return Instruction{ |
| 719 | .format_3h = .{ |
| 720 | .cmask = @bitCast(u3, cmask), |
| 721 | .mmask = @bitCast(u4, mmask), |
| 722 | }, |
| 723 | }; |
| 724 | } |
| 725 | fn format3i(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction { |
| 726 | return Instruction{ |
| 727 | .format_3i = .{ |
| 728 | .op = op, |
| 729 | .rd = rd.enc(), |
| 730 | .op3 = op3, |
| 731 | .rs1 = rs1.enc(), |
| 732 | .imm_asi = @enumToInt(asi), |
| 733 | .rs2 = rs2.enc(), |
| 734 | }, |
| 735 | }; |
| 736 | } |
| 737 | fn format3j(op: u2, op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction { |
| 738 | return Instruction{ |
| 739 | .format_3j = .{ |
| 740 | .op = op, |
| 741 | .impl_dep1 = impl_dep1, |
| 742 | .op3 = op3, |
| 743 | .impl_dep2 = impl_dep2, |
| 744 | }, |
| 745 | }; |
| 746 | } |
| 747 | fn format3k(op: u2, op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 748 | return Instruction{ |
| 749 | .format_3k = .{ |
| 750 | .op = op, |
| 751 | .rd = rd.enc(), |
| 752 | .op3 = op3, |
| 753 | .rs1 = rs1.enc(), |
| 754 | .x = @enumToInt(sw), |
| 755 | .rs2 = rs2.enc(), |
| 756 | }, |
| 757 | }; |
| 758 | } |
| 759 | fn format3l(op: u2, op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction { |
| 760 | return Instruction{ |
| 761 | .format_3l = .{ |
| 762 | .op = op, |
| 763 | .rd = rd.enc(), |
| 764 | .op3 = op3, |
| 765 | .rs1 = rs1.enc(), |
| 766 | .shcnt32 = shift_count, |
| 767 | }, |
| 768 | }; |
| 769 | } |
| 770 | fn format3m(op: u2, op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction { |
| 771 | return Instruction{ |
| 772 | .format_3m = .{ |
| 773 | .op = op, |
| 774 | .rd = rd.enc(), |
| 775 | .op3 = op3, |
| 776 | .rs1 = rs1.enc(), |
| 777 | .shcnt64 = shift_count, |
| 778 | }, |
| 779 | }; |
| 780 | } |
| 781 | fn format3n(op: u2, op3: u6, opf: u9, rs2: Register, rd: Register) Instruction { |
| 782 | return Instruction{ |
| 783 | .format_3n = .{ |
| 784 | .op = op, |
| 785 | .rd = rd.enc(), |
| 786 | .op3 = op3, |
| 787 | .opf = opf, |
| 788 | .rs2 = rs2.enc(), |
| 789 | }, |
| 790 | }; |
| 791 | } |
| 792 | fn format3o(op: u2, op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction { |
| 793 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 794 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 795 | return Instruction{ |
| 796 | .format_3o = .{ |
| 797 | .op = op, |
| 798 | .cc1 = ccr_cc1, |
| 799 | .cc0 = ccr_cc0, |
| 800 | .op3 = op3, |
| 801 | .rs1 = rs1.enc(), |
| 802 | .opf = opf, |
| 803 | .rs2 = rs2.enc(), |
| 804 | }, |
| 805 | }; |
| 806 | } |
| 807 | fn format3p(op: u2, op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 808 | return Instruction{ |
| 809 | .format_3p = .{ |
| 810 | .op = op, |
| 811 | .rd = rd.enc(), |
| 812 | .op3 = op3, |
| 813 | .rs1 = rs1.enc(), |
| 814 | .opf = opf, |
| 815 | .rs2 = rs2.enc(), |
| 816 | }, |
| 817 | }; |
| 818 | } |
| 819 | fn format3q(op: u2, op3: u6, rs1: Register, rd: Register) Instruction { |
| 820 | return Instruction{ |
| 821 | .format_3q = .{ |
| 822 | .op = op, |
| 823 | .rd = rd.enc(), |
| 824 | .op3 = op3, |
| 825 | .rs1 = rs1.enc(), |
| 826 | }, |
| 827 | }; |
| 828 | } |
| 829 | fn format3r(op: u2, op3: u6, fcn: u5) Instruction { |
| 830 | return Instruction{ |
| 831 | .format_3r = .{ |
| 832 | .op = op, |
| 833 | .fcn = fcn, |
| 834 | .op3 = op3, |
| 835 | }, |
| 836 | }; |
| 837 | } |
| 838 | fn format3s(op: u2, op3: u6, rd: Register) Instruction { |
| 839 | return Instruction{ |
| 840 | .format_3s = .{ |
| 841 | .op = op, |
| 842 | .rd = rd.enc(), |
| 843 | .op3 = op3, |
| 844 | }, |
| 845 | }; |
| 846 | } |
| 847 | |
| 848 | fn format4a(op3: u6, ccr: CCR, rs1: Register, rs2: Register, rd: Register) Instruction { |
| 849 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 850 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 851 | return Instruction{ |
| 852 | .format_4a = .{ |
| 853 | .rd = rd.enc(), |
| 854 | .op3 = op3, |
| 855 | .rs1 = rs1.enc(), |
| 856 | .cc1 = ccr_cc1, |
| 857 | .cc0 = ccr_cc0, |
| 858 | .rs2 = rs2.enc(), |
| 859 | }, |
| 860 | }; |
| 861 | } |
| 862 | |
| 863 | fn format4b(op3: u6, ccr: CCR, rs1: Register, imm: i11, rd: Register) Instruction { |
| 864 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 865 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 866 | return Instruction{ |
| 867 | .format_4b = .{ |
| 868 | .rd = rd.enc(), |
| 869 | .op3 = op3, |
| 870 | .rs1 = rs1.enc(), |
| 871 | .cc1 = ccr_cc1, |
| 872 | .cc0 = ccr_cc0, |
| 873 | .simm11 = @bitCast(u11, imm), |
| 874 | }, |
| 875 | }; |
| 876 | } |
| 877 | |
| 878 | fn format4c(op3: u6, cond: Condition, ccr: CCR, rs2: Register, rd: Register) Instruction { |
| 879 | const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); |
| 880 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 881 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 882 | return Instruction{ |
| 883 | .format_4c = .{ |
| 884 | .rd = rd.enc(), |
| 885 | .op3 = op3, |
| 886 | .cc2 = ccr_cc2, |
| 887 | .cond = cond, |
| 888 | .cc1 = ccr_cc1, |
| 889 | .cc0 = ccr_cc0, |
| 890 | .rs2 = rs2.enc(), |
| 891 | }, |
| 892 | }; |
| 893 | } |
| 894 | |
| 895 | fn format4d(op3: u6, cond: Condition, ccr: CCR, imm: i11, rd: Register) Instruction { |
| 896 | const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); |
| 897 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 898 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 899 | return Instruction{ |
| 900 | .format_4d = .{ |
| 901 | .rd = rd.enc(), |
| 902 | .op3 = op3, |
| 903 | .cc2 = ccr_cc2, |
| 904 | .cond = cond, |
| 905 | .cc1 = ccr_cc1, |
| 906 | .cc0 = ccr_cc0, |
| 907 | .simm11 = @bitCast(u11, imm), |
| 908 | }, |
| 909 | }; |
| 910 | } |
| 911 | |
| 912 | fn format4e(op3: u6, ccr: CCR, rs1: Register, rd: Register, sw_trap: u7) Instruction { |
| 913 | const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); |
| 914 | const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); |
| 915 | return Instruction{ |
| 916 | .format_4e = .{ |
| 917 | .rd = rd.enc(), |
| 918 | .op3 = op3, |
| 919 | .rs1 = rs1.enc(), |
| 920 | .cc1 = ccr_cc1, |
| 921 | .cc0 = ccr_cc0, |
| 922 | .sw_trap = sw_trap, |
| 923 | }, |
| 924 | }; |
| 925 | } |
| 926 | |
| 927 | fn format4f( |
| 928 | op3: u6, |
| 929 | opf_low: u5, |
| 930 | rcond: RCondition, |
| 931 | rs1: Register, |
| 932 | rs2: Register, |
| 933 | rd: Register, |
| 934 | ) Instruction { |
| 935 | return Instruction{ |
| 936 | .format_4f = .{ |
| 937 | .rd = rd.enc(), |
| 938 | .op3 = op3, |
| 939 | .rs1 = rs1.enc(), |
| 940 | .rcond = @enumToInt(rcond), |
| 941 | .opf_low = opf_low, |
| 942 | .rs2 = rs2.enc(), |
| 943 | }, |
| 944 | }; |
| 945 | } |
| 946 | |
| 947 | fn format4g(op3: u6, opf_low: u6, opf_cc: u3, cond: Condition, rs2: Register, rd: Register) Instruction { |
| 948 | return Instruction{ |
| 949 | .format_4g = .{ |
| 950 | .rd = rd.enc(), |
| 951 | .op3 = op3, |
| 952 | .cond = cond, |
| 953 | .opf_cc = opf_cc, |
| 954 | .opf_low = opf_low, |
| 955 | .rs2 = rs2.enc(), |
| 956 | }, |
| 957 | }; |
| 958 | } |
| 959 | }; |
| 960 | |
| 961 | test "Serialize formats" { |
| 962 | const Testcase = struct { |
| 963 | inst: Instruction, |
| 964 | expected: u32, |
| 965 | }; |
| 966 | |
| 967 | // Note that the testcases might or might not be a valid instruction |
| 968 | // This is mostly just to check the behavior of the format packed structs |
| 969 | // since currently stage1 doesn't properly implement it in all cases |
| 970 | const testcases = [_]Testcase{ |
| 971 | .{ |
| 972 | .inst = Instruction.format1(4), |
| 973 | .expected = 0b01_000000000000000000000000000001, |
| 974 | }, |
| 975 | .{ |
| 976 | .inst = Instruction.format2a(4, .g0, 0), |
| 977 | .expected = 0b00_00000_100_0000000000000000000000, |
| 978 | }, |
| 979 | .{ |
| 980 | .inst = Instruction.format2b(6, 3, true, -4), |
| 981 | .expected = 0b00_1_0011_110_1111111111111111111111, |
| 982 | }, |
| 983 | .{ |
| 984 | .inst = Instruction.format2c(3, 0, false, true, .xcc, 8), |
| 985 | .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, |
| 986 | }, |
| 987 | .{ |
| 988 | .inst = Instruction.format2d(7, .eq_zero, false, true, .o0, 20), |
| 989 | .expected = 0b00_0_0_001_111_00_1_01000_00000000000101, |
| 990 | }, |
| 991 | .{ |
| 992 | .inst = Instruction.format3a(3, 5, .g0, .o1, .l2), |
| 993 | .expected = 0b11_10010_000101_00000_0_00000000_01001, |
| 994 | }, |
| 995 | .{ |
| 996 | .inst = Instruction.format3b(3, 5, .g0, -1, .l2), |
| 997 | .expected = 0b11_10010_000101_00000_1_1111111111111, |
| 998 | }, |
| 999 | .{ |
| 1000 | .inst = Instruction.format3c(3, 5, .g0, .o1), |
| 1001 | .expected = 0b11_00000_000101_00000_0_00000000_01001, |
| 1002 | }, |
| 1003 | .{ |
| 1004 | .inst = Instruction.format3d(3, 5, .g0, 0), |
| 1005 | .expected = 0b11_00000_000101_00000_1_0000000000000, |
| 1006 | }, |
| 1007 | .{ |
| 1008 | .inst = Instruction.format3e(3, 5, .ne_zero, .g0, .o1, .l2), |
| 1009 | .expected = 0b11_10010_000101_00000_0_101_00000_01001, |
| 1010 | }, |
| 1011 | .{ |
| 1012 | .inst = Instruction.format3f(3, 5, .ne_zero, .g0, -1, .l2), |
| 1013 | .expected = 0b11_10010_000101_00000_1_101_1111111111, |
| 1014 | }, |
| 1015 | .{ |
| 1016 | .inst = Instruction.format3g(3, 5, .g0, .o1, .l2), |
| 1017 | .expected = 0b11_10010_000101_00000_1_00000000_01001, |
| 1018 | }, |
| 1019 | .{ |
| 1020 | .inst = Instruction.format3h(.{}, .{}), |
| 1021 | .expected = 0b10_00000_101000_01111_1_000000_000_0000, |
| 1022 | }, |
| 1023 | .{ |
| 1024 | .inst = Instruction.format3i(3, 5, .g0, .o1, .l2, .asi_primary_little), |
| 1025 | .expected = 0b11_10010_000101_00000_0_10001000_01001, |
| 1026 | }, |
| 1027 | .{ |
| 1028 | .inst = Instruction.format3j(3, 5, 31, 0), |
| 1029 | .expected = 0b11_11111_000101_0000000000000000000, |
| 1030 | }, |
| 1031 | .{ |
| 1032 | .inst = Instruction.format3k(3, 5, .shift32, .g0, .o1, .l2), |
| 1033 | .expected = 0b11_10010_000101_00000_0_0_0000000_01001, |
| 1034 | }, |
| 1035 | .{ |
| 1036 | .inst = Instruction.format3l(3, 5, .g0, 31, .l2), |
| 1037 | .expected = 0b11_10010_000101_00000_1_0_0000000_11111, |
| 1038 | }, |
| 1039 | .{ |
| 1040 | .inst = Instruction.format3m(3, 5, .g0, 63, .l2), |
| 1041 | .expected = 0b11_10010_000101_00000_1_1_000000_111111, |
| 1042 | }, |
| 1043 | .{ |
| 1044 | .inst = Instruction.format3n(3, 5, 0, .o1, .l2), |
| 1045 | .expected = 0b11_10010_000101_00000_000000000_01001, |
| 1046 | }, |
| 1047 | .{ |
| 1048 | .inst = Instruction.format3o(3, 5, 0, .xcc, .o1, .l2), |
| 1049 | .expected = 0b11_000_1_0_000101_01001_000000000_10010, |
| 1050 | }, |
| 1051 | .{ |
| 1052 | .inst = Instruction.format3p(3, 5, 0, .g0, .o1, .l2), |
| 1053 | .expected = 0b11_10010_000101_00000_000000000_01001, |
| 1054 | }, |
| 1055 | .{ |
| 1056 | .inst = Instruction.format3q(3, 5, .g0, .o1), |
| 1057 | .expected = 0b11_01001_000101_00000_00000000000000, |
| 1058 | }, |
| 1059 | .{ |
| 1060 | .inst = Instruction.format3r(3, 5, 4), |
| 1061 | .expected = 0b11_00100_000101_0000000000000000000, |
| 1062 | }, |
| 1063 | .{ |
| 1064 | .inst = Instruction.format3s(3, 5, .g0), |
| 1065 | .expected = 0b11_00000_000101_0000000000000000000, |
| 1066 | }, |
| 1067 | .{ |
| 1068 | .inst = Instruction.format4a(8, .xcc, .g0, .o1, .l2), |
| 1069 | .expected = 0b10_10010_001000_00000_0_1_0_000000_01001, |
| 1070 | }, |
| 1071 | .{ |
| 1072 | .inst = Instruction.format4b(8, .xcc, .g0, -1, .l2), |
| 1073 | .expected = 0b10_10010_001000_00000_1_1_0_11111111111, |
| 1074 | }, |
| 1075 | .{ |
| 1076 | .inst = Instruction.format4c(8, 0, .xcc, .g0, .o1), |
| 1077 | .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000, |
| 1078 | }, |
| 1079 | .{ |
| 1080 | .inst = Instruction.format4d(8, 0, .xcc, 0, .l2), |
| 1081 | .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, |
| 1082 | }, |
| 1083 | .{ |
| 1084 | .inst = Instruction.format4e(8, .xcc, .g0, .o1, 0), |
| 1085 | .expected = 0b10_01001_001000_00000_1_1_0_0000_0000000, |
| 1086 | }, |
| 1087 | .{ |
| 1088 | .inst = Instruction.format4f(8, 4, .eq_zero, .g0, .o1, .l2), |
| 1089 | .expected = 0b10_10010_001000_00000_0_001_00100_01001, |
| 1090 | }, |
| 1091 | .{ |
| 1092 | .inst = Instruction.format4g(8, 4, 2, 0, .o1, .l2), |
| 1093 | .expected = 0b10_10010_001000_0_0000_010_000100_01001, |
| 1094 | }, |
| 1095 | }; |
| 1096 | |
| 1097 | for (testcases) |case| { |
| 1098 | const actual = case.inst.toU32(); |
| 1099 | try testing.expectEqual(case.expected, actual); |
| 1100 | } |
| 1101 | } |