| ... | ... | @@ -560,19 +560,20 @@ pub const Instruction = union(enum) { |
| 560 | 560 | rt1: Register, |
| 561 | 561 | rt2: Register, |
| 562 | 562 | rn: Register, |
| 563 | | imm7: i7, |
| 563 | offset: i9, |
| 564 | 564 | encoding: u2, |
| 565 | 565 | load: bool, |
| 566 | 566 | ) Instruction { |
| 567 | | const imm7_u: u7 = @bitCast(u7, imm7); |
| 568 | 567 | switch (rt1.size()) { |
| 569 | 568 | 32 => { |
| 569 | assert(-256 <= offset and offset <= 252); |
| 570 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 2)); |
| 570 | 571 | return Instruction{ |
| 571 | 572 | .LoadStorePairOfRegisters = .{ |
| 572 | 573 | .rt1 = rt1.id(), |
| 573 | 574 | .rn = rn.id(), |
| 574 | 575 | .rt2 = rt2.id(), |
| 575 | | .imm7 = imm7_u, |
| 576 | .imm7 = imm7, |
| 576 | 577 | .load = @boolToInt(load), |
| 577 | 578 | .encoding = encoding, |
| 578 | 579 | .opc = 0b00, |
| ... | ... | @@ -580,12 +581,14 @@ pub const Instruction = union(enum) { |
| 580 | 581 | }; |
| 581 | 582 | }, |
| 582 | 583 | 64 => { |
| 584 | assert(-512 <= offset and offset <= 504); |
| 585 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 3)); |
| 583 | 586 | return Instruction{ |
| 584 | 587 | .LoadStorePairOfRegisters = .{ |
| 585 | 588 | .rt1 = rt1.id(), |
| 586 | 589 | .rn = rn.id(), |
| 587 | 590 | .rt2 = rt2.id(), |
| 588 | | .imm7 = imm7_u, |
| 591 | .imm7 = imm7, |
| 589 | 592 | .load = @boolToInt(load), |
| 590 | 593 | .encoding = encoding, |
| 591 | 594 | .opc = 0b10, |
| ... | ... | @@ -731,20 +734,20 @@ pub const Instruction = union(enum) { |
| 731 | 734 | SignedOffset = 0b10, |
| 732 | 735 | PreIndex = 0b11, |
| 733 | 736 | }; |
| 734 | | pub fn ldp(rt1: Register, rt2: Register, rn: Register, imm: i7, encoding: LoadStorePairEncoding) Instruction { |
| 735 | | return loadStorePairOfRegisters(rt1, rt2, rn, imm, @enumToInt(encoding), true); |
| 737 | pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction { |
| 738 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), true); |
| 736 | 739 | } |
| 737 | 740 | |
| 738 | | pub fn ldnp(rt1: Register, rt2: Register, rn: Register, imm: i7) Instruction { |
| 739 | | return loadStorePairOfRegisters(rt1, rt2, rn, imm, 0, true); |
| 741 | pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { |
| 742 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true); |
| 740 | 743 | } |
| 741 | 744 | |
| 742 | | pub fn stp(rt1: Register, rt2: Register, rn: Register, imm: i7, encoding: LoadStorePairEncoding) Instruction { |
| 743 | | return loadStorePairOfRegisters(rt1, rt2, rn, imm, @enumToInt(encoding), false); |
| 745 | pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction { |
| 746 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), false); |
| 744 | 747 | } |
| 745 | 748 | |
| 746 | | pub fn stnp(rt1: Register, rt2: Register, rn: Register, imm: i7) Instruction { |
| 747 | | return loadStorePairOfRegisters(rt1, rt2, rn, imm, 0, false); |
| 749 | pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { |
| 750 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, false); |
| 748 | 751 | } |
| 749 | 752 | |
| 750 | 753 | // Exception generation |
| ... | ... | @@ -903,29 +906,26 @@ test "serialize instructions" { |
| 903 | 906 | .inst = Instruction.adrp(.x2, -0x8), |
| 904 | 907 | .expected = 0b1_00_10000_1111111111111111110_00010, |
| 905 | 908 | }, |
| 906 | | .{ // stp x1, x2, [sp, #1] |
| 907 | | .inst = Instruction.stp(.x1, .x2, Register.sp, 1, .SignedOffset), |
| 909 | .{ // stp x1, x2, [sp, #8] |
| 910 | .inst = Instruction.stp(.x1, .x2, Register.sp, 8, .SignedOffset), |
| 908 | 911 | .expected = 0b10_101_0_010_0_0000001_00010_11111_00001, |
| 909 | 912 | }, |
| 910 | 913 | .{ // stp x1, x2, [sp, #-16] |
| 911 | 914 | .inst = Instruction.stp(.x1, .x2, Register.sp, -16, .SignedOffset), |
| 912 | | .expected = 0b10_101_0_010_0_1110000_00010_11111_00001, |
| 915 | .expected = 0b10_101_0_010_0_1111110_00010_11111_00001, |
| 913 | 916 | }, |
| 914 | | .{ // ldp x1, x2, [sp, #1] |
| 915 | | .inst = Instruction.ldp(.x1, .x2, Register.sp, 1, .SignedOffset), |
| 917 | .{ // ldp x1, x2, [sp, #8] |
| 918 | .inst = Instruction.ldp(.x1, .x2, Register.sp, 8, .SignedOffset), |
| 916 | 919 | .expected = 0b10_101_0_010_1_0000001_00010_11111_00001, |
| 917 | 920 | }, |
| 918 | 921 | .{ // ldp x1, x2, [sp, #16] |
| 919 | 922 | .inst = Instruction.ldp(.x1, .x2, Register.sp, 16, .SignedOffset), |
| 920 | | .expected = 0b10_101_0_010_1_0010000_00010_11111_00001, |
| 923 | .expected = 0b10_101_0_010_1_0000010_00010_11111_00001, |
| 921 | 924 | }, |
| 922 | 925 | }; |
| 923 | 926 | |
| 924 | 927 | for (testcases) |case| { |
| 925 | 928 | const actual = case.inst.toU32(); |
| 926 | | if (case.expected != actual) { |
| 927 | | std.debug.print("0b{b} != 0b{b}\n", .{ case.expected, actual }); |
| 928 | | } |
| 929 | 929 | testing.expectEqual(case.expected, actual); |
| 930 | 930 | } |
| 931 | 931 | } |