| ... | ... | @@ -332,6 +332,17 @@ pub const Instruction = union(enum) { |
| 332 | 332 | op: u1, |
| 333 | 333 | sf: u1, |
| 334 | 334 | }, |
| 335 | data_processing_3_source: packed struct { |
| 336 | rd: u5, |
| 337 | rn: u5, |
| 338 | ra: u5, |
| 339 | o0: u1, |
| 340 | rm: u5, |
| 341 | op31: u3, |
| 342 | fixed: u5 = 0b11011, |
| 343 | op54: u2, |
| 344 | sf: u1, |
| 345 | }, |
| 335 | 346 | |
| 336 | 347 | pub const Shift = struct { |
| 337 | 348 | shift: Type = .lsl, |
| ... | ... | @@ -470,6 +481,7 @@ pub const Instruction = union(enum) { |
| 470 | 481 | .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25), |
| 471 | 482 | .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), |
| 472 | 483 | .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, |
| 484 | .data_processing_3_source => |v| @bitCast(u32, v), |
| 473 | 485 | }; |
| 474 | 486 | } |
| 475 | 487 | |
| ... | ... | @@ -967,6 +979,33 @@ pub const Instruction = union(enum) { |
| 967 | 979 | }; |
| 968 | 980 | } |
| 969 | 981 | |
| 982 | fn dataProcessing3Source( |
| 983 | op54: u2, |
| 984 | op31: u3, |
| 985 | o0: u1, |
| 986 | rd: Register, |
| 987 | rn: Register, |
| 988 | rm: Register, |
| 989 | ra: Register, |
| 990 | ) Instruction { |
| 991 | return Instruction{ |
| 992 | .data_processing_3_source = .{ |
| 993 | .rd = rd.id(), |
| 994 | .rn = rn.id(), |
| 995 | .ra = ra.id(), |
| 996 | .o0 = o0, |
| 997 | .rm = rm.id(), |
| 998 | .op31 = op31, |
| 999 | .op54 = op54, |
| 1000 | .sf = switch (rd.size()) { |
| 1001 | 32 => 0b0, |
| 1002 | 64 => 0b1, |
| 1003 | else => unreachable, // unexpected register size |
| 1004 | }, |
| 1005 | }, |
| 1006 | }; |
| 1007 | } |
| 1008 | |
| 970 | 1009 | // Helper functions for assembly syntax functions |
| 971 | 1010 | |
| 972 | 1011 | // Move wide (immediate) |
| ... | ... | @@ -1245,6 +1284,24 @@ pub const Instruction = union(enum) { |
| 1245 | 1284 | pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { |
| 1246 | 1285 | return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond); |
| 1247 | 1286 | } |
| 1287 | |
| 1288 | // Data processing (3 source) |
| 1289 | |
| 1290 | pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1291 | return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra); |
| 1292 | } |
| 1293 | |
| 1294 | pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1295 | return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra); |
| 1296 | } |
| 1297 | |
| 1298 | pub fn mul(rd: Register, rn: Register, rm: Register) Instruction { |
| 1299 | return madd(rd, rn, rm, .xzr); |
| 1300 | } |
| 1301 | |
| 1302 | pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { |
| 1303 | return msub(rd, rn, rm, .xzr); |
| 1304 | } |
| 1248 | 1305 | }; |
| 1249 | 1306 | |
| 1250 | 1307 | test { |
| ... | ... | @@ -1414,6 +1471,10 @@ test "serialize instructions" { |
| 1414 | 1471 | .inst = Instruction.csinc(.x1, .x2, .x4, .eq), |
| 1415 | 1472 | .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001, |
| 1416 | 1473 | }, |
| 1474 | .{ // mul x1, x4, x9 |
| 1475 | .inst = Instruction.mul(.x1, .x4, .x9), |
| 1476 | .expected = 0b1_00_11011_000_01001_0_11111_00100_00001, |
| 1477 | }, |
| 1417 | 1478 | }; |
| 1418 | 1479 | |
| 1419 | 1480 | for (testcases) |case| { |