| ... | ... | @@ -274,6 +274,16 @@ pub const Instruction = union(enum) { |
| 274 | 274 | opc: u2, |
| 275 | 275 | sf: u1, |
| 276 | 276 | }, |
| 277 | AddSubtractImmediate: packed struct { |
| 278 | rd: u5, |
| 279 | rn: u5, |
| 280 | imm12: u12, |
| 281 | sh: u1, |
| 282 | fixed: u6 = 0b100010, |
| 283 | s: u1, |
| 284 | op: u1, |
| 285 | sf: u1, |
| 286 | }, |
| 277 | 287 | |
| 278 | 288 | pub const Shift = struct { |
| 279 | 289 | shift: Type = .lsl, |
| ... | ... | @@ -304,6 +314,7 @@ pub const Instruction = union(enum) { |
| 304 | 314 | .UnconditionalBranchImmediate => |v| @bitCast(u32, v), |
| 305 | 315 | .NoOperation => |v| @bitCast(u32, v), |
| 306 | 316 | .LogicalShiftedRegister => |v| @bitCast(u32, v), |
| 317 | .AddSubtractImmediate => |v| @bitCast(u32, v), |
| 307 | 318 | }; |
| 308 | 319 | } |
| 309 | 320 | |
| ... | ... | @@ -671,6 +682,31 @@ pub const Instruction = union(enum) { |
| 671 | 682 | } |
| 672 | 683 | } |
| 673 | 684 | |
| 685 | fn addSubtractImmediate( |
| 686 | op: u1, |
| 687 | s: u1, |
| 688 | rd: Register, |
| 689 | rn: Register, |
| 690 | imm12: u12, |
| 691 | shift: bool, |
| 692 | ) Instruction { |
| 693 | return Instruction{ |
| 694 | .AddSubtractImmediate = .{ |
| 695 | .rd = rd.id(), |
| 696 | .rn = rn.id(), |
| 697 | .imm12 = imm12, |
| 698 | .sh = @boolToInt(shift), |
| 699 | .s = s, |
| 700 | .op = op, |
| 701 | .sf = switch (rd.size()) { |
| 702 | 32 => 0b0, |
| 703 | 64 => 0b1, |
| 704 | else => unreachable, // unexpected register size |
| 705 | }, |
| 706 | }, |
| 707 | }; |
| 708 | } |
| 709 | |
| 674 | 710 | // Helper functions for assembly syntax functions |
| 675 | 711 | |
| 676 | 712 | // Move wide (immediate) |
| ... | ... | @@ -850,6 +886,24 @@ pub const Instruction = union(enum) { |
| 850 | 886 | pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { |
| 851 | 887 | return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm); |
| 852 | 888 | } |
| 889 | |
| 890 | // Add/subtract (immediate) |
| 891 | |
| 892 | pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { |
| 893 | return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift); |
| 894 | } |
| 895 | |
| 896 | pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { |
| 897 | return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift); |
| 898 | } |
| 899 | |
| 900 | pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { |
| 901 | return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift); |
| 902 | } |
| 903 | |
| 904 | pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { |
| 905 | return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); |
| 906 | } |
| 853 | 907 | }; |
| 854 | 908 | |
| 855 | 909 | test "" { |
| ... | ... | @@ -979,6 +1033,14 @@ test "serialize instructions" { |
| 979 | 1033 | .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }), |
| 980 | 1034 | .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, |
| 981 | 1035 | }, |
| 1036 | .{ // add x0, x10, #10 |
| 1037 | .inst = Instruction.add(.x0, .x10, 10, false), |
| 1038 | .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000, |
| 1039 | }, |
| 1040 | .{ // subs x0, x5, #11, lsl #12 |
| 1041 | .inst = Instruction.subs(.x0, .x5, 11, true), |
| 1042 | .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000, |
| 1043 | }, |
| 982 | 1044 | }; |
| 983 | 1045 | |
| 984 | 1046 | for (testcases) |case| { |