| ... | ... | @@ -138,6 +138,29 @@ pub const Instruction = union(enum) { |
| 138 | 138 | fixed: u2 = 0b00, |
| 139 | 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 | 164 | SingleDataTransfer: packed struct { |
| 142 | 165 | offset: u12, |
| 143 | 166 | rd: u4, |
| ... | ... | @@ -403,6 +426,8 @@ pub const Instruction = union(enum) { |
| 403 | 426 | pub fn toU32(self: Instruction) u32 { |
| 404 | 427 | return switch (self) { |
| 405 | 428 | .DataProcessing => |v| @bitCast(u32, v), |
| 429 | .Multiply => |v| @bitCast(u32, v), |
| 430 | .MultiplyLong => |v| @bitCast(u32, v), |
| 406 | 431 | .SingleDataTransfer => |v| @bitCast(u32, v), |
| 407 | 432 | .BlockDataTransfer => |v| @bitCast(u32, v), |
| 408 | 433 | .Branch => |v| @bitCast(u32, v), |
| ... | ... | @@ -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 | 527 | fn singleDataTransfer( |
| 458 | 528 | cond: Condition, |
| 459 | 529 | rd: Register, |
| ... | ... | @@ -673,7 +743,83 @@ pub const Instruction = union(enum) { |
| 673 | 743 | // PSR transfer |
| 674 | 744 | |
| 675 | 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 | 825 | // Single data transfer |
| ... | ... | @@ -857,6 +1003,14 @@ test "serialize instructions" { |
| 857 | 1003 | .inst = Instruction.mrs(.al, .r5, .cpsr), |
| 858 | 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 | 1014 | .{ // ldr r0, [r2, #42] |
| 861 | 1015 | .inst = Instruction.ldr(.al, .r0, .r2, .{ |
| 862 | 1016 | .offset = Instruction.Offset.imm(42), |