| ... | @@ -138,6 +138,29 @@ pub const Instruction = union(enum) { | ... | @@ -138,6 +138,29 @@ pub const Instruction = union(enum) { |
| 138 | fixed: u2 = 0b00, | 138 | fixed: u2 = 0b00, |
| 139 | cond: u4, | 139 | cond: u4, |
| 140 | }, | 140 | }, |
| | 141 | Multiply: packed struct { |
| | 142 | rn: u4, |
| | 143 | fixed_1: u4 = 0b1001, |
| | 144 | rm: u4, |
| | 145 | ra: u4, |
| | 146 | rd: u4, |
| | 147 | set_cond: u1, |
| | 148 | accumulate: u1, |
| | 149 | fixed_2: u6 = 0b000000, |
| | 150 | cond: u4, |
| | 151 | }, |
| | 152 | MultiplyLong: packed struct { |
| | 153 | rn: u4, |
| | 154 | fixed_1: u4 = 0b1001, |
| | 155 | rm: u4, |
| | 156 | rdlo: u4, |
| | 157 | rdhi: u4, |
| | 158 | set_cond: u1, |
| | 159 | accumulate: u1, |
| | 160 | unsigned: u1, |
| | 161 | fixed_2: u5 = 0b00001, |
| | 162 | cond: u4, |
| | 163 | }, |
| 141 | SingleDataTransfer: packed struct { | 164 | SingleDataTransfer: packed struct { |
| 142 | offset: u12, | 165 | offset: u12, |
| 143 | rd: u4, | 166 | rd: u4, |
| ... | @@ -403,6 +426,8 @@ pub const Instruction = union(enum) { | ... | @@ -403,6 +426,8 @@ pub const Instruction = union(enum) { |
| 403 | pub fn toU32(self: Instruction) u32 { | 426 | pub fn toU32(self: Instruction) u32 { |
| 404 | return switch (self) { | 427 | return switch (self) { |
| 405 | .DataProcessing => |v| @bitCast(u32, v), | 428 | .DataProcessing => |v| @bitCast(u32, v), |
| | 429 | .Multiply => |v| @bitCast(u32, v), |
| | 430 | .MultiplyLong => |v| @bitCast(u32, v), |
| 406 | .SingleDataTransfer => |v| @bitCast(u32, v), | 431 | .SingleDataTransfer => |v| @bitCast(u32, v), |
| 407 | .BlockDataTransfer => |v| @bitCast(u32, v), | 432 | .BlockDataTransfer => |v| @bitCast(u32, v), |
| 408 | .Branch => |v| @bitCast(u32, v), | 433 | .Branch => |v| @bitCast(u32, v), |
| ... | @@ -454,6 +479,51 @@ pub const Instruction = union(enum) { | ... | @@ -454,6 +479,51 @@ pub const Instruction = union(enum) { |
| 454 | }; | 479 | }; |
| 455 | } | 480 | } |
| 456 | | 481 | |
| | 482 | fn multiply( |
| | 483 | cond: Condition, |
| | 484 | set_cond: u1, |
| | 485 | rd: Register, |
| | 486 | rn: Register, |
| | 487 | rm: Register, |
| | 488 | ra: ?Register, |
| | 489 | ) Instruction { |
| | 490 | return Instruction{ |
| | 491 | .Multiply = .{ |
| | 492 | .cond = @enumToInt(cond), |
| | 493 | .accumulate = @boolToInt(ra != null), |
| | 494 | .set_cond = set_cond, |
| | 495 | .rd = rd.id(), |
| | 496 | .rn = rn.id(), |
| | 497 | .ra = if (ra) |reg| reg.id() else 0b0000, |
| | 498 | .rm = rm.id(), |
| | 499 | }, |
| | 500 | }; |
| | 501 | } |
| | 502 | |
| | 503 | fn multiplyLong( |
| | 504 | cond: Condition, |
| | 505 | signed: u1, |
| | 506 | accumulate: u1, |
| | 507 | set_cond: u1, |
| | 508 | rdhi: Register, |
| | 509 | rdlo: Register, |
| | 510 | rm: Register, |
| | 511 | rn: Register, |
| | 512 | ) Instruction { |
| | 513 | return Instruction{ |
| | 514 | .MultiplyLong = .{ |
| | 515 | .cond = @enumToInt(cond), |
| | 516 | .unsigned = signed, |
| | 517 | .accumulate = accumulate, |
| | 518 | .set_cond = set_cond, |
| | 519 | .rdlo = rdlo.id(), |
| | 520 | .rdhi = rdhi.id(), |
| | 521 | .rn = rn.id(), |
| | 522 | .rm = rm.id(), |
| | 523 | }, |
| | 524 | }; |
| | 525 | } |
| | 526 | |
| 457 | fn singleDataTransfer( | 527 | fn singleDataTransfer( |
| 458 | cond: Condition, | 528 | cond: Condition, |
| 459 | rd: Register, | 529 | rd: Register, |
| ... | @@ -673,7 +743,83 @@ pub const Instruction = union(enum) { | ... | @@ -673,7 +743,83 @@ pub const Instruction = union(enum) { |
| 673 | // PSR transfer | 743 | // PSR transfer |
| 674 | | 744 | |
| 675 | pub fn mrs(cond: Condition, rd: Register, psr: Psr) Instruction { | 745 | pub fn mrs(cond: Condition, rd: Register, psr: Psr) Instruction { |
| 676 | return dataProcessing(cond, if (psr == .cpsr) .tst else .cmp, 0, rd, .r15, Operand.reg(.r0, Operand.Shift.none)); | 746 | return Instruction{ |
| | 747 | .DataProcessing = .{ |
| | 748 | .cond = @enumToInt(cond), |
| | 749 | .i = 0, |
| | 750 | .opcode = if (psr == .spsr) 0b1010 else 0b1000, |
| | 751 | .s = 0, |
| | 752 | .rn = 0b1111, |
| | 753 | .rd = rd.id(), |
| | 754 | .op2 = 0b0000_0000_0000, |
| | 755 | }, |
| | 756 | }; |
| | 757 | } |
| | 758 | |
| | 759 | pub fn msr(cond: Condition, psr: Psr, op: Operand) Instruction { |
| | 760 | return Instruction{ |
| | 761 | .DataProcessing = .{ |
| | 762 | .cond = @enumToInt(cond), |
| | 763 | .i = 0, |
| | 764 | .opcode = if (psr == .spsr) 0b1011 else 0b1001, |
| | 765 | .s = 0, |
| | 766 | .rn = 0b1111, |
| | 767 | .rd = 0b1111, |
| | 768 | .op2 = op.toU12(), |
| | 769 | }, |
| | 770 | }; |
| | 771 | } |
| | 772 | |
| | 773 | // Multiply |
| | 774 | |
| | 775 | pub fn mul(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { |
| | 776 | return multiply(cond, 0, rd, rn, rm, null); |
| | 777 | } |
| | 778 | |
| | 779 | pub fn muls(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { |
| | 780 | return multiply(cond, 1, rd, rn, rm, null); |
| | 781 | } |
| | 782 | |
| | 783 | pub fn mla(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| | 784 | return multiply(cond, 0, rd, rn, rm, ra); |
| | 785 | } |
| | 786 | |
| | 787 | pub fn mlas(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| | 788 | return multiply(cond, 1, rd, rn, rm, ra); |
| | 789 | } |
| | 790 | |
| | 791 | // Multiply long |
| | 792 | |
| | 793 | pub fn umull(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 794 | return multiplyLong(cond, 0, 0, 0, rdhi, rdlo, rm, rn); |
| | 795 | } |
| | 796 | |
| | 797 | pub fn umulls(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 798 | return multiplyLong(cond, 0, 0, 1, rdhi, rdlo, rm, rn); |
| | 799 | } |
| | 800 | |
| | 801 | pub fn umlal(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 802 | return multiplyLong(cond, 0, 1, 0, rdhi, rdlo, rm, rn); |
| | 803 | } |
| | 804 | |
| | 805 | pub fn umlals(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 806 | return multiplyLong(cond, 0, 1, 1, rdhi, rdlo, rm, rn); |
| | 807 | } |
| | 808 | |
| | 809 | pub fn smull(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 810 | return multiplyLong(cond, 1, 0, 0, rdhi, rdlo, rm, rn); |
| | 811 | } |
| | 812 | |
| | 813 | pub fn smulls(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 814 | return multiplyLong(cond, 1, 0, 1, rdhi, rdlo, rm, rn); |
| | 815 | } |
| | 816 | |
| | 817 | pub fn smlal(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 818 | return multiplyLong(cond, 1, 1, 0, rdhi, rdlo, rm, rn); |
| | 819 | } |
| | 820 | |
| | 821 | pub fn smlals(cond: Condition, rdlo: Register, rdhi: Register, rn: Register, rm: Register) Instruction { |
| | 822 | return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn); |
| 677 | } | 823 | } |
| 678 | | 824 | |
| 679 | // Single data transfer | 825 | // Single data transfer |
| ... | @@ -857,6 +1003,14 @@ test "serialize instructions" { | ... | @@ -857,6 +1003,14 @@ test "serialize instructions" { |
| 857 | .inst = Instruction.mrs(.al, .r5, .cpsr), | 1003 | .inst = Instruction.mrs(.al, .r5, .cpsr), |
| 858 | .expected = 0b1110_00010_0_001111_0101_000000000000, | 1004 | .expected = 0b1110_00010_0_001111_0101_000000000000, |
| 859 | }, | 1005 | }, |
| | 1006 | .{ // mul r0, r1, r2 |
| | 1007 | .inst = Instruction.mul(.al, .r0, .r1, .r2), |
| | 1008 | .expected = 0b1110_000000_0_0_0000_0000_0010_1001_0001, |
| | 1009 | }, |
| | 1010 | .{ // umlal r0, r1, r5, r6 |
| | 1011 | .inst = Instruction.umlal(.al, .r0, .r1, .r5, .r6), |
| | 1012 | .expected = 0b1110_00001_0_1_0_0001_0000_0110_1001_0101, |
| | 1013 | }, |
| 860 | .{ // ldr r0, [r2, #42] | 1014 | .{ // ldr r0, [r2, #42] |
| 861 | .inst = Instruction.ldr(.al, .r0, .r2, .{ | 1015 | .inst = Instruction.ldr(.al, .r0, .r2, .{ |
| 862 | .offset = Instruction.Offset.imm(42), | 1016 | .offset = Instruction.Offset.imm(42), |