| ... | @@ -0,0 +1,106 @@ |
| 1 | pub inline fn isArithmeticOp(inst: *const [4]u8) bool { |
| 2 | const group_decode = @as(u5, @truncate(inst[3])); |
| 3 | return ((group_decode >> 2) == 4); |
| 4 | } |
| 5 | |
| 6 | pub const PageOffsetInstKind = enum { |
| 7 | arithmetic, |
| 8 | load_store_8, |
| 9 | load_store_16, |
| 10 | load_store_32, |
| 11 | load_store_64, |
| 12 | load_store_128, |
| 13 | }; |
| 14 | |
| 15 | pub fn classifyInst(code: *const [4]u8) PageOffsetInstKind { |
| 16 | if (isArithmeticOp(code)) return .arithmetic; |
| 17 | const inst = Instruction{ |
| 18 | .load_store_register = mem.bytesToValue(std.meta.TagPayload( |
| 19 | Instruction, |
| 20 | Instruction.load_store_register, |
| 21 | ), code), |
| 22 | }; |
| 23 | return switch (inst.load_store_register.size) { |
| 24 | 0 => if (inst.load_store_register.v == 1) .load_store_128 else .load_store_8, |
| 25 | 1 => .load_store_16, |
| 26 | 2 => .load_store_32, |
| 27 | 3 => .load_store_64, |
| 28 | }; |
| 29 | } |
| 30 | |
| 31 | pub fn calcPageOffset(kind: PageOffsetInstKind, taddr: u64) !u12 { |
| 32 | const narrowed = @as(u12, @truncate(taddr)); |
| 33 | return switch (kind) { |
| 34 | .arithmetic, .load_store_8 => narrowed, |
| 35 | .load_store_16 => try math.divExact(u12, narrowed, 2), |
| 36 | .load_store_32 => try math.divExact(u12, narrowed, 4), |
| 37 | .load_store_64 => try math.divExact(u12, narrowed, 8), |
| 38 | .load_store_128 => try math.divExact(u12, narrowed, 16), |
| 39 | }; |
| 40 | } |
| 41 | |
| 42 | pub fn writePageOffset(kind: PageOffsetInstKind, taddr: u64, code: *[4]u8) !void { |
| 43 | const value = try calcPageOffset(kind, taddr); |
| 44 | switch (kind) { |
| 45 | .arithmetic => { |
| 46 | var inst = Instruction{ |
| 47 | .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( |
| 48 | Instruction, |
| 49 | Instruction.add_subtract_immediate, |
| 50 | ), code), |
| 51 | }; |
| 52 | inst.add_subtract_immediate.imm12 = value; |
| 53 | mem.writeInt(u32, code, inst.toU32(), .little); |
| 54 | }, |
| 55 | else => { |
| 56 | var inst: Instruction = .{ |
| 57 | .load_store_register = mem.bytesToValue(std.meta.TagPayload( |
| 58 | Instruction, |
| 59 | Instruction.load_store_register, |
| 60 | ), code), |
| 61 | }; |
| 62 | inst.load_store_register.offset = value; |
| 63 | mem.writeInt(u32, code, inst.toU32(), .little); |
| 64 | }, |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 { |
| 69 | const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; |
| 70 | const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; |
| 71 | const pages = math.cast(i21, tpage - spage) orelse return error.Overflow; |
| 72 | return pages; |
| 73 | } |
| 74 | |
| 75 | pub fn writePages(pages: u21, code: *[4]u8) !void { |
| 76 | var inst = Instruction{ |
| 77 | .pc_relative_address = mem.bytesToValue(std.meta.TagPayload( |
| 78 | Instruction, |
| 79 | Instruction.pc_relative_address, |
| 80 | ), code), |
| 81 | }; |
| 82 | inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); |
| 83 | inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); |
| 84 | mem.writeInt(u32, code, inst.toU32(), .little); |
| 85 | } |
| 86 | |
| 87 | pub fn writeBranchImm(disp: i28, code: *[4]u8) !void { |
| 88 | var inst = Instruction{ |
| 89 | .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload( |
| 90 | Instruction, |
| 91 | Instruction.unconditional_branch_immediate, |
| 92 | ), code), |
| 93 | }; |
| 94 | inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2)))); |
| 95 | mem.writeInt(u32, code, inst.toU32(), .little); |
| 96 | } |
| 97 | |
| 98 | const assert = std.debug.assert; |
| 99 | const bits = @import("../arch/aarch64/bits.zig"); |
| 100 | const builtin = @import("builtin"); |
| 101 | const math = std.math; |
| 102 | const mem = std.mem; |
| 103 | const std = @import("std"); |
| 104 | |
| 105 | pub const Instruction = bits.Instruction; |
| 106 | pub const Register = bits.Register; |