| ... | @@ -332,6 +332,17 @@ pub const Instruction = union(enum) { | ... | @@ -332,6 +332,17 @@ pub const Instruction = union(enum) { |
| 332 | op: u1, | 332 | op: u1, |
| 333 | sf: u1, | 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 | pub const Shift = struct { | 347 | pub const Shift = struct { |
| 337 | shift: Type = .lsl, | 348 | shift: Type = .lsl, |
| ... | @@ -470,6 +481,7 @@ pub const Instruction = union(enum) { | ... | @@ -470,6 +481,7 @@ pub const Instruction = union(enum) { |
| 470 | .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), | 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 | .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), | 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 | .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, | 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,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 | // Helper functions for assembly syntax functions | 1009 | // Helper functions for assembly syntax functions |
| 971 | | 1010 | |
| 972 | // Move wide (immediate) | 1011 | // Move wide (immediate) |
| ... | @@ -1245,6 +1284,24 @@ pub const Instruction = union(enum) { | ... | @@ -1245,6 +1284,24 @@ pub const Instruction = union(enum) { |
| 1245 | pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { | 1284 | pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { |
| 1246 | return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond); | 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 | test { | 1307 | test { |
| ... | @@ -1414,6 +1471,10 @@ test "serialize instructions" { | ... | @@ -1414,6 +1471,10 @@ test "serialize instructions" { |
| 1414 | .inst = Instruction.csinc(.x1, .x2, .x4, .eq), | 1471 | .inst = Instruction.csinc(.x1, .x2, .x4, .eq), |
| 1415 | .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001, | 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 | for (testcases) |case| { | 1480 | for (testcases) |case| { |