| ... | ... | @@ -192,7 +192,7 @@ pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 }; |
| 192 | 192 | |
| 193 | 193 | /// Represents an instruction in the ARM instruction set architecture |
| 194 | 194 | pub const Instruction = union(enum) { |
| 195 | | DataProcessing: packed struct { |
| 195 | data_processing: packed struct { |
| 196 | 196 | // Note to self: The order of the fields top-to-bottom is |
| 197 | 197 | // right-to-left in the actual 32-bit int representation |
| 198 | 198 | op2: u12, |
| ... | ... | @@ -204,7 +204,7 @@ pub const Instruction = union(enum) { |
| 204 | 204 | fixed: u2 = 0b00, |
| 205 | 205 | cond: u4, |
| 206 | 206 | }, |
| 207 | | Multiply: packed struct { |
| 207 | multiply: packed struct { |
| 208 | 208 | rn: u4, |
| 209 | 209 | fixed_1: u4 = 0b1001, |
| 210 | 210 | rm: u4, |
| ... | ... | @@ -215,7 +215,7 @@ pub const Instruction = union(enum) { |
| 215 | 215 | fixed_2: u6 = 0b000000, |
| 216 | 216 | cond: u4, |
| 217 | 217 | }, |
| 218 | | MultiplyLong: packed struct { |
| 218 | multiply_long: packed struct { |
| 219 | 219 | rn: u4, |
| 220 | 220 | fixed_1: u4 = 0b1001, |
| 221 | 221 | rm: u4, |
| ... | ... | @@ -227,7 +227,17 @@ pub const Instruction = union(enum) { |
| 227 | 227 | fixed_2: u5 = 0b00001, |
| 228 | 228 | cond: u4, |
| 229 | 229 | }, |
| 230 | | SingleDataTransfer: packed struct { |
| 230 | integer_saturating_arithmetic: packed struct { |
| 231 | rm: u4, |
| 232 | fixed_1: u8 = 0b0000_0101, |
| 233 | rd: u4, |
| 234 | rn: u4, |
| 235 | fixed_2: u1 = 0b0, |
| 236 | opc: u2, |
| 237 | fixed_3: u5 = 0b00010, |
| 238 | cond: u4, |
| 239 | }, |
| 240 | single_data_transfer: packed struct { |
| 231 | 241 | offset: u12, |
| 232 | 242 | rd: u4, |
| 233 | 243 | rn: u4, |
| ... | ... | @@ -240,7 +250,7 @@ pub const Instruction = union(enum) { |
| 240 | 250 | fixed: u2 = 0b01, |
| 241 | 251 | cond: u4, |
| 242 | 252 | }, |
| 243 | | ExtraLoadStore: packed struct { |
| 253 | extra_load_store: packed struct { |
| 244 | 254 | imm4l: u4, |
| 245 | 255 | fixed_1: u1 = 0b1, |
| 246 | 256 | op2: u2, |
| ... | ... | @@ -256,7 +266,7 @@ pub const Instruction = union(enum) { |
| 256 | 266 | fixed_3: u3 = 0b000, |
| 257 | 267 | cond: u4, |
| 258 | 268 | }, |
| 259 | | BlockDataTransfer: packed struct { |
| 269 | block_data_transfer: packed struct { |
| 260 | 270 | register_list: u16, |
| 261 | 271 | rn: u4, |
| 262 | 272 | load_store: u1, |
| ... | ... | @@ -267,25 +277,25 @@ pub const Instruction = union(enum) { |
| 267 | 277 | fixed: u3 = 0b100, |
| 268 | 278 | cond: u4, |
| 269 | 279 | }, |
| 270 | | Branch: packed struct { |
| 280 | branch: packed struct { |
| 271 | 281 | offset: u24, |
| 272 | 282 | link: u1, |
| 273 | 283 | fixed: u3 = 0b101, |
| 274 | 284 | cond: u4, |
| 275 | 285 | }, |
| 276 | | BranchExchange: packed struct { |
| 286 | branch_exchange: packed struct { |
| 277 | 287 | rn: u4, |
| 278 | 288 | fixed_1: u1 = 0b1, |
| 279 | 289 | link: u1, |
| 280 | 290 | fixed_2: u22 = 0b0001_0010_1111_1111_1111_00, |
| 281 | 291 | cond: u4, |
| 282 | 292 | }, |
| 283 | | SupervisorCall: packed struct { |
| 293 | supervisor_call: packed struct { |
| 284 | 294 | comment: u24, |
| 285 | 295 | fixed: u4 = 0b1111, |
| 286 | 296 | cond: u4, |
| 287 | 297 | }, |
| 288 | | Breakpoint: packed struct { |
| 298 | breakpoint: packed struct { |
| 289 | 299 | imm4: u4, |
| 290 | 300 | fixed_1: u4 = 0b0111, |
| 291 | 301 | imm12: u12, |
| ... | ... | @@ -293,7 +303,7 @@ pub const Instruction = union(enum) { |
| 293 | 303 | }, |
| 294 | 304 | |
| 295 | 305 | /// Represents the possible operations which can be performed by a |
| 296 | | /// DataProcessing instruction |
| 306 | /// Data Processing instruction |
| 297 | 307 | const Opcode = enum(u4) { |
| 298 | 308 | // Rd := Op1 AND Op2 |
| 299 | 309 | @"and", |
| ... | ... | @@ -530,16 +540,17 @@ pub const Instruction = union(enum) { |
| 530 | 540 | |
| 531 | 541 | pub fn toU32(self: Instruction) u32 { |
| 532 | 542 | return switch (self) { |
| 533 | | .DataProcessing => |v| @bitCast(u32, v), |
| 534 | | .Multiply => |v| @bitCast(u32, v), |
| 535 | | .MultiplyLong => |v| @bitCast(u32, v), |
| 536 | | .SingleDataTransfer => |v| @bitCast(u32, v), |
| 537 | | .ExtraLoadStore => |v| @bitCast(u32, v), |
| 538 | | .BlockDataTransfer => |v| @bitCast(u32, v), |
| 539 | | .Branch => |v| @bitCast(u32, v), |
| 540 | | .BranchExchange => |v| @bitCast(u32, v), |
| 541 | | .SupervisorCall => |v| @bitCast(u32, v), |
| 542 | | .Breakpoint => |v| @intCast(u32, v.imm4) | (@intCast(u32, v.fixed_1) << 4) | (@intCast(u32, v.imm12) << 8) | (@intCast(u32, v.fixed_2_and_cond) << 20), |
| 543 | .data_processing => |v| @bitCast(u32, v), |
| 544 | .multiply => |v| @bitCast(u32, v), |
| 545 | .multiply_long => |v| @bitCast(u32, v), |
| 546 | .integer_saturating_arithmetic => |v| @bitCast(u32, v), |
| 547 | .single_data_transfer => |v| @bitCast(u32, v), |
| 548 | .extra_load_store => |v| @bitCast(u32, v), |
| 549 | .block_data_transfer => |v| @bitCast(u32, v), |
| 550 | .branch => |v| @bitCast(u32, v), |
| 551 | .branch_exchange => |v| @bitCast(u32, v), |
| 552 | .supervisor_call => |v| @bitCast(u32, v), |
| 553 | .breakpoint => |v| @intCast(u32, v.imm4) | (@intCast(u32, v.fixed_1) << 4) | (@intCast(u32, v.imm12) << 8) | (@intCast(u32, v.fixed_2_and_cond) << 20), |
| 543 | 554 | }; |
| 544 | 555 | } |
| 545 | 556 | |
| ... | ... | @@ -554,7 +565,7 @@ pub const Instruction = union(enum) { |
| 554 | 565 | op2: Operand, |
| 555 | 566 | ) Instruction { |
| 556 | 567 | return Instruction{ |
| 557 | | .DataProcessing = .{ |
| 568 | .data_processing = .{ |
| 558 | 569 | .cond = @enumToInt(cond), |
| 559 | 570 | .i = @boolToInt(op2 == .Immediate), |
| 560 | 571 | .opcode = @enumToInt(opcode), |
| ... | ... | @@ -573,7 +584,7 @@ pub const Instruction = union(enum) { |
| 573 | 584 | top: bool, |
| 574 | 585 | ) Instruction { |
| 575 | 586 | return Instruction{ |
| 576 | | .DataProcessing = .{ |
| 587 | .data_processing = .{ |
| 577 | 588 | .cond = @enumToInt(cond), |
| 578 | 589 | .i = 1, |
| 579 | 590 | .opcode = if (top) 0b1010 else 0b1000, |
| ... | ... | @@ -594,7 +605,7 @@ pub const Instruction = union(enum) { |
| 594 | 605 | ra: ?Register, |
| 595 | 606 | ) Instruction { |
| 596 | 607 | return Instruction{ |
| 597 | | .Multiply = .{ |
| 608 | .multiply = .{ |
| 598 | 609 | .cond = @enumToInt(cond), |
| 599 | 610 | .accumulate = @boolToInt(ra != null), |
| 600 | 611 | .set_cond = set_cond, |
| ... | ... | @@ -617,7 +628,7 @@ pub const Instruction = union(enum) { |
| 617 | 628 | rn: Register, |
| 618 | 629 | ) Instruction { |
| 619 | 630 | return Instruction{ |
| 620 | | .MultiplyLong = .{ |
| 631 | .multiply_long = .{ |
| 621 | 632 | .cond = @enumToInt(cond), |
| 622 | 633 | .unsigned = signed, |
| 623 | 634 | .accumulate = accumulate, |
| ... | ... | @@ -630,6 +641,24 @@ pub const Instruction = union(enum) { |
| 630 | 641 | }; |
| 631 | 642 | } |
| 632 | 643 | |
| 644 | fn integerSaturationArithmetic( |
| 645 | cond: Condition, |
| 646 | rd: Register, |
| 647 | rm: Register, |
| 648 | rn: Register, |
| 649 | opc: u2, |
| 650 | ) Instruction { |
| 651 | return Instruction{ |
| 652 | .integer_saturating_arithmetic = .{ |
| 653 | .rm = rm.id(), |
| 654 | .rd = rd.id(), |
| 655 | .rn = rn.id(), |
| 656 | .opc = opc, |
| 657 | .cond = @enumToInt(cond), |
| 658 | }, |
| 659 | }; |
| 660 | } |
| 661 | |
| 633 | 662 | fn singleDataTransfer( |
| 634 | 663 | cond: Condition, |
| 635 | 664 | rd: Register, |
| ... | ... | @@ -642,7 +671,7 @@ pub const Instruction = union(enum) { |
| 642 | 671 | load_store: u1, |
| 643 | 672 | ) Instruction { |
| 644 | 673 | return Instruction{ |
| 645 | | .SingleDataTransfer = .{ |
| 674 | .single_data_transfer = .{ |
| 646 | 675 | .cond = @enumToInt(cond), |
| 647 | 676 | .rn = rn.id(), |
| 648 | 677 | .rd = rd.id(), |
| ... | ... | @@ -678,7 +707,7 @@ pub const Instruction = union(enum) { |
| 678 | 707 | }; |
| 679 | 708 | |
| 680 | 709 | return Instruction{ |
| 681 | | .ExtraLoadStore = .{ |
| 710 | .extra_load_store = .{ |
| 682 | 711 | .imm4l = imm4l, |
| 683 | 712 | .op2 = op2, |
| 684 | 713 | .imm4h = imm4h, |
| ... | ... | @@ -705,7 +734,7 @@ pub const Instruction = union(enum) { |
| 705 | 734 | load_store: u1, |
| 706 | 735 | ) Instruction { |
| 707 | 736 | return Instruction{ |
| 708 | | .BlockDataTransfer = .{ |
| 737 | .block_data_transfer = .{ |
| 709 | 738 | .register_list = @bitCast(u16, reg_list), |
| 710 | 739 | .rn = rn.id(), |
| 711 | 740 | .load_store = load_store, |
| ... | ... | @@ -720,7 +749,7 @@ pub const Instruction = union(enum) { |
| 720 | 749 | |
| 721 | 750 | fn branch(cond: Condition, offset: i26, link: u1) Instruction { |
| 722 | 751 | return Instruction{ |
| 723 | | .Branch = .{ |
| 752 | .branch = .{ |
| 724 | 753 | .cond = @enumToInt(cond), |
| 725 | 754 | .link = link, |
| 726 | 755 | .offset = @bitCast(u24, @intCast(i24, offset >> 2)), |
| ... | ... | @@ -730,7 +759,7 @@ pub const Instruction = union(enum) { |
| 730 | 759 | |
| 731 | 760 | fn branchExchange(cond: Condition, rn: Register, link: u1) Instruction { |
| 732 | 761 | return Instruction{ |
| 733 | | .BranchExchange = .{ |
| 762 | .branch_exchange = .{ |
| 734 | 763 | .cond = @enumToInt(cond), |
| 735 | 764 | .link = link, |
| 736 | 765 | .rn = rn.id(), |
| ... | ... | @@ -740,7 +769,7 @@ pub const Instruction = union(enum) { |
| 740 | 769 | |
| 741 | 770 | fn supervisorCall(cond: Condition, comment: u24) Instruction { |
| 742 | 771 | return Instruction{ |
| 743 | | .SupervisorCall = .{ |
| 772 | .supervisor_call = .{ |
| 744 | 773 | .cond = @enumToInt(cond), |
| 745 | 774 | .comment = comment, |
| 746 | 775 | }, |
| ... | ... | @@ -749,7 +778,7 @@ pub const Instruction = union(enum) { |
| 749 | 778 | |
| 750 | 779 | fn breakpoint(imm: u16) Instruction { |
| 751 | 780 | return Instruction{ |
| 752 | | .Breakpoint = .{ |
| 781 | .breakpoint = .{ |
| 753 | 782 | .imm12 = @truncate(u12, imm >> 4), |
| 754 | 783 | .imm4 = @truncate(u4, imm), |
| 755 | 784 | }, |
| ... | ... | @@ -873,6 +902,24 @@ pub const Instruction = union(enum) { |
| 873 | 902 | return dataProcessing(cond, .mvn, 1, rd, .r0, op2); |
| 874 | 903 | } |
| 875 | 904 | |
| 905 | // Integer Saturating Arithmetic |
| 906 | |
| 907 | pub fn qadd(cond: Condition, rd: Register, rm: Register, rn: Register) Instruction { |
| 908 | return integerSaturationArithmetic(cond, rd, rm, rn, 0b00); |
| 909 | } |
| 910 | |
| 911 | pub fn qsub(cond: Condition, rd: Register, rm: Register, rn: Register) Instruction { |
| 912 | return integerSaturationArithmetic(cond, rd, rm, rn, 0b01); |
| 913 | } |
| 914 | |
| 915 | pub fn qdadd(cond: Condition, rd: Register, rm: Register, rn: Register) Instruction { |
| 916 | return integerSaturationArithmetic(cond, rd, rm, rn, 0b10); |
| 917 | } |
| 918 | |
| 919 | pub fn qdsub(cond: Condition, rd: Register, rm: Register, rn: Register) Instruction { |
| 920 | return integerSaturationArithmetic(cond, rd, rm, rn, 0b11); |
| 921 | } |
| 922 | |
| 876 | 923 | // movw and movt |
| 877 | 924 | |
| 878 | 925 | pub fn movw(cond: Condition, rd: Register, imm: u16) Instruction { |
| ... | ... | @@ -887,7 +934,7 @@ pub const Instruction = union(enum) { |
| 887 | 934 | |
| 888 | 935 | pub fn mrs(cond: Condition, rd: Register, psr: Psr) Instruction { |
| 889 | 936 | return Instruction{ |
| 890 | | .DataProcessing = .{ |
| 937 | .data_processing = .{ |
| 891 | 938 | .cond = @enumToInt(cond), |
| 892 | 939 | .i = 0, |
| 893 | 940 | .opcode = if (psr == .spsr) 0b1010 else 0b1000, |
| ... | ... | @@ -901,7 +948,7 @@ pub const Instruction = union(enum) { |
| 901 | 948 | |
| 902 | 949 | pub fn msr(cond: Condition, psr: Psr, op: Operand) Instruction { |
| 903 | 950 | return Instruction{ |
| 904 | | .DataProcessing = .{ |
| 951 | .data_processing = .{ |
| 905 | 952 | .cond = @enumToInt(cond), |
| 906 | 953 | .i = 0, |
| 907 | 954 | .opcode = if (psr == .spsr) 0b1011 else 0b1001, |
| ... | ... | @@ -1294,6 +1341,10 @@ test "serialize instructions" { |
| 1294 | 1341 | .inst = Instruction.ldmea(.al, .r4, true, .{ .r2 = true, .r5 = true }), |
| 1295 | 1342 | .expected = 0b1110_100_1_0_0_1_1_0100_0000000000100100, |
| 1296 | 1343 | }, |
| 1344 | .{ // qadd r0, r7, r8 |
| 1345 | .inst = Instruction.qadd(.al, .r0, .r7, .r8), |
| 1346 | .expected = 0b1110_00010_00_0_1000_0000_0000_0101_0111, |
| 1347 | }, |
| 1297 | 1348 | }; |
| 1298 | 1349 | |
| 1299 | 1350 | for (testcases) |case| { |