| ... | @@ -203,11 +203,11 @@ pub const Instruction = union(enum) { | ... | @@ -203,11 +203,11 @@ pub const Instruction = union(enum) { |
| 203 | opc: u2, | 203 | opc: u2, |
| 204 | sf: u1, | 204 | sf: u1, |
| 205 | }, | 205 | }, |
| 206 | LoadRegister: packed struct { | 206 | LoadStoreRegister: packed struct { |
| 207 | rt: u5, | 207 | rt: u5, |
| 208 | rn: u5, | 208 | rn: u5, |
| 209 | offset: u12, | 209 | offset: u12, |
| 210 | opc: u2 = 0b01, | 210 | opc: u2, |
| 211 | op1: u2, | 211 | op1: u2, |
| 212 | fixed: u4 = 0b111_0, | 212 | fixed: u4 = 0b111_0, |
| 213 | size: u2, | 213 | size: u2, |
| ... | @@ -242,7 +242,7 @@ pub const Instruction = union(enum) { | ... | @@ -242,7 +242,7 @@ pub const Instruction = union(enum) { |
| 242 | pub fn toU32(self: Instruction) u32 { | 242 | pub fn toU32(self: Instruction) u32 { |
| 243 | return switch (self) { | 243 | return switch (self) { |
| 244 | .MoveWideImmediate => |v| @bitCast(u32, v), | 244 | .MoveWideImmediate => |v| @bitCast(u32, v), |
| 245 | .LoadRegister => |v| @bitCast(u32, v), | 245 | .LoadStoreRegister => |v| @bitCast(u32, v), |
| 246 | .LoadLiteral => |v| @bitCast(u32, v), | 246 | .LoadLiteral => |v| @bitCast(u32, v), |
| 247 | .ExceptionGeneration => |v| @bitCast(u32, v), | 247 | .ExceptionGeneration => |v| @bitCast(u32, v), |
| 248 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), | 248 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), |
| ... | @@ -276,8 +276,8 @@ pub const Instruction = union(enum) { | ... | @@ -276,8 +276,8 @@ pub const Instruction = union(enum) { |
| 276 | pub fn toU12(self: Offset) u12 { | 276 | pub fn toU12(self: Offset) u12 { |
| 277 | return switch (self) { | 277 | return switch (self) { |
| 278 | .Immediate => |imm_type| switch (imm_type) { | 278 | .Immediate => |imm_type| switch (imm_type) { |
| 279 | .PostIndex => |v| @intCast(u12, @bitCast(u9, v)) << 2 + 1, | 279 | .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1, |
| 280 | .PreIndex => |v| @intCast(u12, @bitCast(u9, v)) << 2 + 3, | 280 | .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3, |
| 281 | .Unsigned => |v| v, | 281 | .Unsigned => |v| v, |
| 282 | }, | 282 | }, |
| 283 | .Register => |r| switch (r.shift) { | 283 | .Register => |r| switch (r.shift) { |
| ... | @@ -404,7 +404,7 @@ pub const Instruction = union(enum) { | ... | @@ -404,7 +404,7 @@ pub const Instruction = union(enum) { |
| 404 | } | 404 | } |
| 405 | } | 405 | } |
| 406 | | 406 | |
| 407 | fn loadRegister(rt: Register, rn: Register, offset: Offset) Instruction { | 407 | fn loadStoreRegister(rt: Register, rn: Register, offset: Offset, load: bool) Instruction { |
| 408 | const off = offset.toU12(); | 408 | const off = offset.toU12(); |
| 409 | const op1: u2 = blk: { | 409 | const op1: u2 = blk: { |
| 410 | switch (offset) { | 410 | switch (offset) { |
| ... | @@ -416,13 +416,15 @@ pub const Instruction = union(enum) { | ... | @@ -416,13 +416,15 @@ pub const Instruction = union(enum) { |
| 416 | } | 416 | } |
| 417 | break :blk 0b00; | 417 | break :blk 0b00; |
| 418 | }; | 418 | }; |
| | 419 | const opc: u2 = if (load) 0b01 else 0b00; |
| 419 | switch (rt.size()) { | 420 | switch (rt.size()) { |
| 420 | 32 => { | 421 | 32 => { |
| 421 | return Instruction{ | 422 | return Instruction{ |
| 422 | .LoadRegister = .{ | 423 | .LoadStoreRegister = .{ |
| 423 | .rt = rt.id(), | 424 | .rt = rt.id(), |
| 424 | .rn = rn.id(), | 425 | .rn = rn.id(), |
| 425 | .offset = offset.toU12(), | 426 | .offset = offset.toU12(), |
| | 427 | .opc = opc, |
| 426 | .op1 = op1, | 428 | .op1 = op1, |
| 427 | .size = 0b10, | 429 | .size = 0b10, |
| 428 | }, | 430 | }, |
| ... | @@ -430,10 +432,11 @@ pub const Instruction = union(enum) { | ... | @@ -430,10 +432,11 @@ pub const Instruction = union(enum) { |
| 430 | }, | 432 | }, |
| 431 | 64 => { | 433 | 64 => { |
| 432 | return Instruction{ | 434 | return Instruction{ |
| 433 | .LoadRegister = .{ | 435 | .LoadStoreRegister = .{ |
| 434 | .rt = rt.id(), | 436 | .rt = rt.id(), |
| 435 | .rn = rn.id(), | 437 | .rn = rn.id(), |
| 436 | .offset = offset.toU12(), | 438 | .offset = offset.toU12(), |
| | 439 | .opc = opc, |
| 437 | .op1 = op1, | 440 | .op1 = op1, |
| 438 | .size = 0b11, | 441 | .size = 0b11, |
| 439 | }, | 442 | }, |
| ... | @@ -529,7 +532,7 @@ pub const Instruction = union(enum) { | ... | @@ -529,7 +532,7 @@ pub const Instruction = union(enum) { |
| 529 | return moveWideImmediate(0b11, rd, imm16, shift); | 532 | return moveWideImmediate(0b11, rd, imm16, shift); |
| 530 | } | 533 | } |
| 531 | | 534 | |
| 532 | // Load register | 535 | // Load or store register |
| 533 | | 536 | |
| 534 | pub const LdrArgs = struct { | 537 | pub const LdrArgs = struct { |
| 535 | rn: ?Register = null, | 538 | rn: ?Register = null, |
| ... | @@ -538,12 +541,19 @@ pub const Instruction = union(enum) { | ... | @@ -538,12 +541,19 @@ pub const Instruction = union(enum) { |
| 538 | }; | 541 | }; |
| 539 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { | 542 | pub fn ldr(rt: Register, args: LdrArgs) Instruction { |
| 540 | if (args.rn) |rn| { | 543 | if (args.rn) |rn| { |
| 541 | return loadRegister(rt, rn, args.offset); | 544 | return loadStoreRegister(rt, rn, args.offset, true); |
| 542 | } else { | 545 | } else { |
| 543 | return loadLiteral(rt, args.literal.?); | 546 | return loadLiteral(rt, args.literal.?); |
| 544 | } | 547 | } |
| 545 | } | 548 | } |
| 546 | | 549 | |
| | 550 | pub const StrArgs = struct { |
| | 551 | offset: Offset = Offset.none, |
| | 552 | }; |
| | 553 | pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { |
| | 554 | return loadStoreRegister(rt, rn, args.offset, false); |
| | 555 | } |
| | 556 | |
| 547 | // Exception generation | 557 | // Exception generation |
| 548 | | 558 | |
| 549 | pub fn svc(imm16: u16) Instruction { | 559 | pub fn svc(imm16: u16) Instruction { |
| ... | @@ -646,6 +656,14 @@ test "serialize instructions" { | ... | @@ -646,6 +656,14 @@ test "serialize instructions" { |
| 646 | .inst = Instruction.ldr(.x2, .{ .rn = .x1 }), | 656 | .inst = Instruction.ldr(.x2, .{ .rn = .x1 }), |
| 647 | .expected = 0b11_111_0_01_01_000000000000_00001_00010, | 657 | .expected = 0b11_111_0_01_01_000000000000_00001_00010, |
| 648 | }, | 658 | }, |
| | 659 | .{ // ldr x2, [x1, #1]! |
| | 660 | .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_pre_index(1) }), |
| | 661 | .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010, |
| | 662 | }, |
| | 663 | .{ // ldr x2, [x1], #-1 |
| | 664 | .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_post_index(-1) }), |
| | 665 | .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010, |
| | 666 | }, |
| 649 | .{ // ldr x2, [x1], (x3) | 667 | .{ // ldr x2, [x1], (x3) |
| 650 | .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.reg(.x3) }), | 668 | .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.reg(.x3) }), |
| 651 | .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010, | 669 | .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010, |
| ... | @@ -654,6 +672,14 @@ test "serialize instructions" { | ... | @@ -654,6 +672,14 @@ test "serialize instructions" { |
| 654 | .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }), | 672 | .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }), |
| 655 | .expected = 0b01_011_0_00_0000000000000000001_00010, | 673 | .expected = 0b01_011_0_00_0000000000000000001_00010, |
| 656 | }, | 674 | }, |
| | 675 | .{ // str x2, [x1] |
| | 676 | .inst = Instruction.str(.x2, .x1, .{}), |
| | 677 | .expected = 0b11_111_0_01_00_000000000000_00001_00010, |
| | 678 | }, |
| | 679 | .{ // str x2, [x1], (x3) |
| | 680 | .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.Offset.reg(.x3) }), |
| | 681 | .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, |
| | 682 | }, |
| 657 | }; | 683 | }; |
| 658 | | 684 | |
| 659 | for (testcases) |case| { | 685 | for (testcases) |case| { |