| ... | @@ -484,7 +484,23 @@ pub const Instruction = union(enum) { | ... | @@ -484,7 +484,23 @@ pub const Instruction = union(enum) { |
| 484 | } | 484 | } |
| 485 | }; | 485 | }; |
| 486 | | 486 | |
| 487 | fn loadStoreRegister(rt: Register, rn: Register, offset: LoadStoreOffset, load: bool) Instruction { | 487 | /// Which kind of load/store to perform |
| | 488 | const LoadStoreVariant = enum { |
| | 489 | /// 32-bit or 64-bit |
| | 490 | normal, |
| | 491 | /// 16-bit |
| | 492 | half, |
| | 493 | /// 8-bit |
| | 494 | byte, |
| | 495 | }; |
| | 496 | |
| | 497 | fn loadStoreRegister( |
| | 498 | rt: Register, |
| | 499 | rn: Register, |
| | 500 | offset: LoadStoreOffset, |
| | 501 | variant: LoadStoreVariant, |
| | 502 | load: bool, |
| | 503 | ) Instruction { |
| 488 | const off = offset.toU12(); | 504 | const off = offset.toU12(); |
| 489 | const op1: u2 = blk: { | 505 | const op1: u2 = blk: { |
| 490 | switch (offset) { | 506 | switch (offset) { |
| ... | @@ -497,35 +513,27 @@ pub const Instruction = union(enum) { | ... | @@ -497,35 +513,27 @@ pub const Instruction = union(enum) { |
| 497 | break :blk 0b00; | 513 | break :blk 0b00; |
| 498 | }; | 514 | }; |
| 499 | const opc: u2 = if (load) 0b01 else 0b00; | 515 | const opc: u2 = if (load) 0b01 else 0b00; |
| 500 | switch (rt.size()) { | 516 | return Instruction{ |
| 501 | 32 => { | 517 | .LoadStoreRegister = .{ |
| 502 | return Instruction{ | 518 | .rt = rt.id(), |
| 503 | .LoadStoreRegister = .{ | 519 | .rn = rn.id(), |
| 504 | .rt = rt.id(), | 520 | .offset = off, |
| 505 | .rn = rn.id(), | 521 | .opc = opc, |
| 506 | .offset = offset.toU12(), | 522 | .op1 = op1, |
| 507 | .opc = opc, | 523 | .v = 0, |
| 508 | .op1 = op1, | 524 | .size = blk: { |
| 509 | .v = 0, | 525 | switch (variant) { |
| 510 | .size = 0b10, | 526 | .normal => switch (rt.size()) { |
| 511 | }, | 527 | 32 => break :blk 0b10, |
| 512 | }; | 528 | 64 => break :blk 0b11, |
| 513 | }, | 529 | else => unreachable, // unexpected register size |
| 514 | 64 => { | 530 | }, |
| 515 | return Instruction{ | 531 | .half => break :blk 0b01, |
| 516 | .LoadStoreRegister = .{ | 532 | .byte => break :blk 0b00, |
| 517 | .rt = rt.id(), | 533 | } |
| 518 | .rn = rn.id(), | 534 | }, |
| 519 | .offset = offset.toU12(), | | |
| 520 | .opc = opc, | | |
| 521 | .op1 = op1, | | |
| 522 | .v = 0, | | |
| 523 | .size = 0b11, | | |
| 524 | }, | | |
| 525 | }; | | |
| 526 | }, | 535 | }, |
| 527 | else => unreachable, // unexpected register size | 536 | }; |
| 528 | } | | |
| 529 | } | 537 | } |
| 530 | | 538 | |
| 531 | fn loadStorePairOfRegisters( | 539 | fn loadStorePairOfRegisters( |
| ... | @@ -748,7 +756,7 @@ pub const Instruction = union(enum) { | ... | @@ -748,7 +756,7 @@ pub const Instruction = union(enum) { |
| 748 | | 756 | |
| 749 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { | 757 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { |
| 750 | switch (args) { | 758 | switch (args) { |
| 751 | .register => |info| return loadStoreRegister(rt, info.rn, info.offset, true), | 759 | .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true), |
| 752 | .literal => |literal| return loadLiteral(rt, literal), | 760 | .literal => |literal| return loadLiteral(rt, literal), |
| 753 | } | 761 | } |
| 754 | } | 762 | } |
| ... | @@ -758,7 +766,15 @@ pub const Instruction = union(enum) { | ... | @@ -758,7 +766,15 @@ pub const Instruction = union(enum) { |
| 758 | }; | 766 | }; |
| 759 | | 767 | |
| 760 | pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { | 768 | pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { |
| 761 | return loadStoreRegister(rt, rn, args.offset, false); | 769 | return loadStoreRegister(rt, rn, args.offset, .normal, false); |
| | 770 | } |
| | 771 | |
| | 772 | pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction { |
| | 773 | return loadStoreRegister(rt, rn, args.offset, .half, false); |
| | 774 | } |
| | 775 | |
| | 776 | pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction { |
| | 777 | return loadStoreRegister(rt, rn, args.offset, .byte, false); |
| 762 | } | 778 | } |
| 763 | | 779 | |
| 764 | // Load or store pair of registers | 780 | // Load or store pair of registers |
| ... | @@ -996,6 +1012,14 @@ test "serialize instructions" { | ... | @@ -996,6 +1012,14 @@ test "serialize instructions" { |
| 996 | .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }), | 1012 | .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }), |
| 997 | .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, | 1013 | .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, |
| 998 | }, | 1014 | }, |
| | 1015 | .{ // strh w0, [x1] |
| | 1016 | .inst = Instruction.strh(.w0, .x1, .{}), |
| | 1017 | .expected = 0b01_111_0_01_00_000000000000_00001_00000, |
| | 1018 | }, |
| | 1019 | .{ // strb w8, [x9] |
| | 1020 | .inst = Instruction.strb(.w8, .x9, .{}), |
| | 1021 | .expected = 0b00_111_0_01_00_000000000000_01001_01000, |
| | 1022 | }, |
| 999 | .{ // adr x2, #0x8 | 1023 | .{ // adr x2, #0x8 |
| 1000 | .inst = Instruction.adr(.x2, 0x8), | 1024 | .inst = Instruction.adr(.x2, 0x8), |
| 1001 | .expected = 0b0_00_10000_0000000000000000010_00010, | 1025 | .expected = 0b0_00_10000_0000000000000000010_00010, |