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