| ... | @@ -240,6 +240,22 @@ pub const Instruction = union(enum) { | ... | @@ -240,6 +240,22 @@ pub const Instruction = union(enum) { |
| 240 | fixed: u2 = 0b01, | 240 | fixed: u2 = 0b01, |
| 241 | cond: u4, | 241 | cond: u4, |
| 242 | }, | 242 | }, |
| | 243 | ExtraLoadStore: packed struct { |
| | 244 | imm4l: u4, |
| | 245 | fixed_1: u1 = 0b1, |
| | 246 | op2: u2, |
| | 247 | fixed_2: u1 = 0b1, |
| | 248 | imm4h: u4, |
| | 249 | rt: u4, |
| | 250 | rn: u4, |
| | 251 | o1: u1, |
| | 252 | write_back: u1, |
| | 253 | imm: u1, |
| | 254 | up_down: u1, |
| | 255 | pre_index: u1, |
| | 256 | fixed_3: u3 = 0b000, |
| | 257 | cond: u4, |
| | 258 | }, |
| 243 | BlockDataTransfer: packed struct { | 259 | BlockDataTransfer: packed struct { |
| 244 | register_list: u16, | 260 | register_list: u16, |
| 245 | rn: u4, | 261 | rn: u4, |
| ... | @@ -468,6 +484,29 @@ pub const Instruction = union(enum) { | ... | @@ -468,6 +484,29 @@ pub const Instruction = union(enum) { |
| 468 | } | 484 | } |
| 469 | }; | 485 | }; |
| 470 | | 486 | |
| | 487 | /// Represents the offset operand of an extra load or store |
| | 488 | /// instruction. |
| | 489 | pub const ExtraLoadStoreOffset = union(enum) { |
| | 490 | immediate: u8, |
| | 491 | register: u4, |
| | 492 | |
| | 493 | pub const none = ExtraLoadStoreOffset{ |
| | 494 | .immediate = 0, |
| | 495 | }; |
| | 496 | |
| | 497 | pub fn reg(register: Register) ExtraLoadStoreOffset { |
| | 498 | return ExtraLoadStoreOffset{ |
| | 499 | .register = register.id(), |
| | 500 | }; |
| | 501 | } |
| | 502 | |
| | 503 | pub fn imm(immediate: u8) ExtraLoadStoreOffset { |
| | 504 | return ExtraLoadStoreOffset{ |
| | 505 | .immediate = immediate, |
| | 506 | }; |
| | 507 | } |
| | 508 | }; |
| | 509 | |
| 471 | /// Represents the register list operand to a block data transfer | 510 | /// Represents the register list operand to a block data transfer |
| 472 | /// instruction | 511 | /// instruction |
| 473 | pub const RegisterList = packed struct { | 512 | pub const RegisterList = packed struct { |
| ... | @@ -495,6 +534,7 @@ pub const Instruction = union(enum) { | ... | @@ -495,6 +534,7 @@ pub const Instruction = union(enum) { |
| 495 | .Multiply => |v| @bitCast(u32, v), | 534 | .Multiply => |v| @bitCast(u32, v), |
| 496 | .MultiplyLong => |v| @bitCast(u32, v), | 535 | .MultiplyLong => |v| @bitCast(u32, v), |
| 497 | .SingleDataTransfer => |v| @bitCast(u32, v), | 536 | .SingleDataTransfer => |v| @bitCast(u32, v), |
| | 537 | .ExtraLoadStore => |v| @bitCast(u32, v), |
| 498 | .BlockDataTransfer => |v| @bitCast(u32, v), | 538 | .BlockDataTransfer => |v| @bitCast(u32, v), |
| 499 | .Branch => |v| @bitCast(u32, v), | 539 | .Branch => |v| @bitCast(u32, v), |
| 500 | .BranchExchange => |v| @bitCast(u32, v), | 540 | .BranchExchange => |v| @bitCast(u32, v), |
| ... | @@ -617,6 +657,43 @@ pub const Instruction = union(enum) { | ... | @@ -617,6 +657,43 @@ pub const Instruction = union(enum) { |
| 617 | }; | 657 | }; |
| 618 | } | 658 | } |
| 619 | | 659 | |
| | 660 | fn extraLoadStore( |
| | 661 | cond: Condition, |
| | 662 | pre_index: bool, |
| | 663 | positive: bool, |
| | 664 | write_back: bool, |
| | 665 | o1: u1, |
| | 666 | op2: u2, |
| | 667 | rn: Register, |
| | 668 | rt: Register, |
| | 669 | offset: ExtraLoadStoreOffset, |
| | 670 | ) Instruction { |
| | 671 | const imm4l: u4 = switch (offset) { |
| | 672 | .immediate => |imm| @truncate(u4, imm), |
| | 673 | .register => |reg| reg, |
| | 674 | }; |
| | 675 | const imm4h: u4 = switch (offset) { |
| | 676 | .immediate => |imm| @truncate(u4, imm >> 4), |
| | 677 | .register => |reg| 0b0000, |
| | 678 | }; |
| | 679 | |
| | 680 | return Instruction{ |
| | 681 | .ExtraLoadStore = .{ |
| | 682 | .imm4l = imm4l, |
| | 683 | .op2 = op2, |
| | 684 | .imm4h = imm4h, |
| | 685 | .rt = rt.id(), |
| | 686 | .rn = rn.id(), |
| | 687 | .o1 = o1, |
| | 688 | .write_back = @boolToInt(write_back), |
| | 689 | .imm = @boolToInt(offset == .immediate), |
| | 690 | .up_down = @boolToInt(positive), |
| | 691 | .pre_index = @boolToInt(pre_index), |
| | 692 | .cond = @enumToInt(cond), |
| | 693 | }, |
| | 694 | }; |
| | 695 | } |
| | 696 | |
| 620 | fn blockDataTransfer( | 697 | fn blockDataTransfer( |
| 621 | cond: Condition, | 698 | cond: Condition, |
| 622 | rn: Register, | 699 | rn: Register, |
| ... | @@ -913,6 +990,23 @@ pub const Instruction = union(enum) { | ... | @@ -913,6 +990,23 @@ pub const Instruction = union(enum) { |
| 913 | return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0); | 990 | return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0); |
| 914 | } | 991 | } |
| 915 | | 992 | |
| | 993 | // Extra load/store |
| | 994 | |
| | 995 | pub const ExtraLoadStoreOffsetArgs = struct { |
| | 996 | pre_index: bool = true, |
| | 997 | positive: bool = true, |
| | 998 | offset: ExtraLoadStoreOffset, |
| | 999 | write_back: bool = false, |
| | 1000 | }; |
| | 1001 | |
| | 1002 | pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction { |
| | 1003 | return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset); |
| | 1004 | } |
| | 1005 | |
| | 1006 | pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction { |
| | 1007 | return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset); |
| | 1008 | } |
| | 1009 | |
| 916 | // Block data transfer | 1010 | // Block data transfer |
| 917 | | 1011 | |
| 918 | pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | 1012 | pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { |
| ... | @@ -1093,6 +1187,12 @@ test "serialize instructions" { | ... | @@ -1093,6 +1187,12 @@ test "serialize instructions" { |
| 1093 | }), | 1187 | }), |
| 1094 | .expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000, | 1188 | .expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000, |
| 1095 | }, | 1189 | }, |
| | 1190 | .{ // strh r1, [r5] |
| | 1191 | .inst = Instruction.strh(.al, .r1, .r5, .{ |
| | 1192 | .offset = Instruction.ExtraLoadStoreOffset.none, |
| | 1193 | }), |
| | 1194 | .expected = 0b1110_000_1_1_1_0_0_0101_0001_0000_1011_0000, |
| | 1195 | }, |
| 1096 | .{ // b #12 | 1196 | .{ // b #12 |
| 1097 | .inst = Instruction.b(.al, 12), | 1197 | .inst = Instruction.b(.al, 12), |
| 1098 | .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011, | 1198 | .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011, |