| ... | @@ -487,11 +487,17 @@ pub const Instruction = union(enum) { | ... | @@ -487,11 +487,17 @@ pub const Instruction = union(enum) { |
| 487 | /// Which kind of load/store to perform | 487 | /// Which kind of load/store to perform |
| 488 | const LoadStoreVariant = enum { | 488 | const LoadStoreVariant = enum { |
| 489 | /// 32-bit or 64-bit | 489 | /// 32-bit or 64-bit |
| 490 | normal, | 490 | str, |
| 491 | /// 16-bit | 491 | /// 16-bit, zero-extended |
| 492 | half, | 492 | strh, |
| 493 | /// 8-bit | 493 | /// 8-bit, zero-extended |
| 494 | byte, | 494 | strb, |
| | 495 | /// 32-bit or 64-bit |
| | 496 | ldr, |
| | 497 | /// 16-bit, zero-extended |
| | 498 | ldrh, |
| | 499 | /// 8-bit, zero-extended |
| | 500 | ldrb, |
| 495 | }; | 501 | }; |
| 496 | | 502 | |
| 497 | fn loadStoreRegister( | 503 | fn loadStoreRegister( |
| ... | @@ -499,7 +505,6 @@ pub const Instruction = union(enum) { | ... | @@ -499,7 +505,6 @@ pub const Instruction = union(enum) { |
| 499 | rn: Register, | 505 | rn: Register, |
| 500 | offset: LoadStoreOffset, | 506 | offset: LoadStoreOffset, |
| 501 | variant: LoadStoreVariant, | 507 | variant: LoadStoreVariant, |
| 502 | load: bool, | | |
| 503 | ) Instruction { | 508 | ) Instruction { |
| 504 | const off = offset.toU12(); | 509 | const off = offset.toU12(); |
| 505 | const op1: u2 = blk: { | 510 | const op1: u2 = blk: { |
| ... | @@ -512,7 +517,10 @@ pub const Instruction = union(enum) { | ... | @@ -512,7 +517,10 @@ pub const Instruction = union(enum) { |
| 512 | } | 517 | } |
| 513 | break :blk 0b00; | 518 | break :blk 0b00; |
| 514 | }; | 519 | }; |
| 515 | const opc: u2 = if (load) 0b01 else 0b00; | 520 | const opc: u2 = switch (variant) { |
| | 521 | .ldr, .ldrh, .ldrb => 0b01, |
| | 522 | .str, .strh, .strb => 0b00, |
| | 523 | }; |
| 516 | return Instruction{ | 524 | return Instruction{ |
| 517 | .LoadStoreRegister = .{ | 525 | .LoadStoreRegister = .{ |
| 518 | .rt = rt.id(), | 526 | .rt = rt.id(), |
| ... | @@ -523,13 +531,13 @@ pub const Instruction = union(enum) { | ... | @@ -523,13 +531,13 @@ pub const Instruction = union(enum) { |
| 523 | .v = 0, | 531 | .v = 0, |
| 524 | .size = blk: { | 532 | .size = blk: { |
| 525 | switch (variant) { | 533 | switch (variant) { |
| 526 | .normal => switch (rt.size()) { | 534 | .ldr, .str => switch (rt.size()) { |
| 527 | 32 => break :blk 0b10, | 535 | 32 => break :blk 0b10, |
| 528 | 64 => break :blk 0b11, | 536 | 64 => break :blk 0b11, |
| 529 | else => unreachable, // unexpected register size | 537 | else => unreachable, // unexpected register size |
| 530 | }, | 538 | }, |
| 531 | .half => break :blk 0b01, | 539 | .ldrh, .strh => break :blk 0b01, |
| 532 | .byte => break :blk 0b00, | 540 | .ldrb, .strb => break :blk 0b00, |
| 533 | } | 541 | } |
| 534 | }, | 542 | }, |
| 535 | }, | 543 | }, |
| ... | @@ -756,25 +764,33 @@ pub const Instruction = union(enum) { | ... | @@ -756,25 +764,33 @@ pub const Instruction = union(enum) { |
| 756 | | 764 | |
| 757 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { | 765 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { |
| 758 | switch (args) { | 766 | switch (args) { |
| 759 | .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true), | 767 | .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .ldr), |
| 760 | .literal => |literal| return loadLiteral(rt, literal), | 768 | .literal => |literal| return loadLiteral(rt, literal), |
| 761 | } | 769 | } |
| 762 | } | 770 | } |
| 763 | | 771 | |
| | 772 | pub fn ldrh(rt: Register, rn: Register, args: StrArgs) Instruction { |
| | 773 | return loadStoreRegister(rt, rn, args.offset, .ldrh); |
| | 774 | } |
| | 775 | |
| | 776 | pub fn ldrb(rt: Register, rn: Register, args: StrArgs) Instruction { |
| | 777 | return loadStoreRegister(rt, rn, args.offset, .ldrb); |
| | 778 | } |
| | 779 | |
| 764 | pub const StrArgs = struct { | 780 | pub const StrArgs = struct { |
| 765 | offset: LoadStoreOffset = LoadStoreOffset.none, | 781 | offset: LoadStoreOffset = LoadStoreOffset.none, |
| 766 | }; | 782 | }; |
| 767 | | 783 | |
| 768 | pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { | 784 | pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { |
| 769 | return loadStoreRegister(rt, rn, args.offset, .normal, false); | 785 | return loadStoreRegister(rt, rn, args.offset, .str); |
| 770 | } | 786 | } |
| 771 | | 787 | |
| 772 | pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction { | 788 | pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction { |
| 773 | return loadStoreRegister(rt, rn, args.offset, .half, false); | 789 | return loadStoreRegister(rt, rn, args.offset, .strh); |
| 774 | } | 790 | } |
| 775 | | 791 | |
| 776 | pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction { | 792 | pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction { |
| 777 | return loadStoreRegister(rt, rn, args.offset, .byte, false); | 793 | return loadStoreRegister(rt, rn, args.offset, .strb); |
| 778 | } | 794 | } |
| 779 | | 795 | |
| 780 | // Load or store pair of registers | 796 | // Load or store pair of registers |
| ... | @@ -1004,6 +1020,14 @@ test "serialize instructions" { | ... | @@ -1004,6 +1020,14 @@ test "serialize instructions" { |
| 1004 | .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }), | 1020 | .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }), |
| 1005 | .expected = 0b01_011_0_00_0000000000000000001_00010, | 1021 | .expected = 0b01_011_0_00_0000000000000000001_00010, |
| 1006 | }, | 1022 | }, |
| | 1023 | .{ // ldrh x7, [x4], #0xaa |
| | 1024 | .inst = Instruction.ldrh(.x7, .x4, .{ .offset = Instruction.LoadStoreOffset.imm_post_index(0xaa) }), |
| | 1025 | .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111, |
| | 1026 | }, |
| | 1027 | .{ // ldrb x9, [x15, #0xff]! |
| | 1028 | .inst = Instruction.ldrb(.x9, .x15, .{ .offset = Instruction.LoadStoreOffset.imm_pre_index(0xff) }), |
| | 1029 | .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001, |
| | 1030 | }, |
| 1007 | .{ // str x2, [x1] | 1031 | .{ // str x2, [x1] |
| 1008 | .inst = Instruction.str(.x2, .x1, .{}), | 1032 | .inst = Instruction.str(.x2, .x1, .{}), |
| 1009 | .expected = 0b11_111_0_01_00_000000000000_00001_00010, | 1033 | .expected = 0b11_111_0_01_00_000000000000_00001_00010, |