Commit 9fd112804f

Jakub Konka <kubkon@jakubkonka.com>
2024-02-21 22:48:19
link: commit missing files
1 parent 8ba31ed
Changed files (2)
src/link/aarch64.zig
@@ -0,0 +1,106 @@
+pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
+    const group_decode = @as(u5, @truncate(inst[3]));
+    return ((group_decode >> 2) == 4);
+}
+
+pub const PageOffsetInstKind = enum {
+    arithmetic,
+    load_store_8,
+    load_store_16,
+    load_store_32,
+    load_store_64,
+    load_store_128,
+};
+
+pub fn classifyInst(code: *const [4]u8) PageOffsetInstKind {
+    if (isArithmeticOp(code)) return .arithmetic;
+    const inst = Instruction{
+        .load_store_register = mem.bytesToValue(std.meta.TagPayload(
+            Instruction,
+            Instruction.load_store_register,
+        ), code),
+    };
+    return switch (inst.load_store_register.size) {
+        0 => if (inst.load_store_register.v == 1) .load_store_128 else .load_store_8,
+        1 => .load_store_16,
+        2 => .load_store_32,
+        3 => .load_store_64,
+    };
+}
+
+pub fn calcPageOffset(kind: PageOffsetInstKind, taddr: u64) !u12 {
+    const narrowed = @as(u12, @truncate(taddr));
+    return switch (kind) {
+        .arithmetic, .load_store_8 => narrowed,
+        .load_store_16 => try math.divExact(u12, narrowed, 2),
+        .load_store_32 => try math.divExact(u12, narrowed, 4),
+        .load_store_64 => try math.divExact(u12, narrowed, 8),
+        .load_store_128 => try math.divExact(u12, narrowed, 16),
+    };
+}
+
+pub fn writePageOffset(kind: PageOffsetInstKind, taddr: u64, code: *[4]u8) !void {
+    const value = try calcPageOffset(kind, taddr);
+    switch (kind) {
+        .arithmetic => {
+            var inst = Instruction{
+                .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
+                    Instruction,
+                    Instruction.add_subtract_immediate,
+                ), code),
+            };
+            inst.add_subtract_immediate.imm12 = value;
+            mem.writeInt(u32, code, inst.toU32(), .little);
+        },
+        else => {
+            var inst: Instruction = .{
+                .load_store_register = mem.bytesToValue(std.meta.TagPayload(
+                    Instruction,
+                    Instruction.load_store_register,
+                ), code),
+            };
+            inst.load_store_register.offset = value;
+            mem.writeInt(u32, code, inst.toU32(), .little);
+        },
+    }
+}
+
+pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {
+    const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
+    const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
+    const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
+    return pages;
+}
+
+pub fn writePages(pages: u21, code: *[4]u8) !void {
+    var inst = Instruction{
+        .pc_relative_address = mem.bytesToValue(std.meta.TagPayload(
+            Instruction,
+            Instruction.pc_relative_address,
+        ), code),
+    };
+    inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
+    inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
+    mem.writeInt(u32, code, inst.toU32(), .little);
+}
+
+pub fn writeBranchImm(disp: i28, code: *[4]u8) !void {
+    var inst = Instruction{
+        .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload(
+            Instruction,
+            Instruction.unconditional_branch_immediate,
+        ), code),
+    };
+    inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2))));
+    mem.writeInt(u32, code, inst.toU32(), .little);
+}
+
+const assert = std.debug.assert;
+const bits = @import("../arch/aarch64/bits.zig");
+const builtin = @import("builtin");
+const math = std.math;
+const mem = std.mem;
+const std = @import("std");
+
+pub const Instruction = bits.Instruction;
+pub const Register = bits.Register;
src/link/riscv.zig
@@ -0,0 +1,58 @@
+pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytype) void {
+    const mask: u8 = 0b11_000000;
+    const actual: i8 = @truncate(addend);
+    var value: u8 = mem.readInt(u8, code, .little);
+    switch (op) {
+        .set => value = (value & mask) | @as(u8, @bitCast(actual & ~mask)),
+        .sub => value = (value & mask) | (@as(u8, @bitCast(@as(i8, @bitCast(value)) -| actual)) & ~mask),
+    }
+    mem.writeInt(u8, code, value, .little);
+}
+
+pub fn writeAddend(
+    comptime Int: type,
+    comptime op: enum { add, sub },
+    code: *[@typeInfo(Int).Int.bits / 8]u8,
+    value: anytype,
+) void {
+    var V: Int = mem.readInt(Int, code, .little);
+    const addend: Int = @truncate(value);
+    switch (op) {
+        .add => V +|= addend, // TODO: I think saturating arithmetic is correct here
+        .sub => V -|= addend,
+    }
+    mem.writeInt(Int, code, V, .little);
+}
+
+pub fn writeInstU(code: *[4]u8, value: u32) void {
+    const inst_mask: u32 = 0b00000000000000000000_11111_1111111;
+    const val_mask: u32 = 0xffff_f000;
+    var inst = mem.readInt(u32, code, .little);
+    inst &= inst_mask;
+    const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800);
+    inst |= (compensated & val_mask);
+    mem.writeInt(u32, code, inst, .little);
+}
+
+pub fn writeInstI(code: *[4]u8, value: u32) void {
+    const mask: u32 = 0b00000000000_11111_111_11111_1111111;
+    var inst = mem.readInt(u32, code, .little);
+    inst &= mask;
+    inst |= (bitSlice(value, 11, 0) << 20);
+    mem.writeInt(u32, code, inst, .little);
+}
+
+pub fn writeInstS(code: *[4]u8, value: u32) void {
+    const mask: u32 = 0b000000_11111_11111_111_00000_1111111;
+    var inst = mem.readInt(u32, code, .little);
+    inst &= mask;
+    inst |= (bitSlice(value, 11, 5) << 25) | (bitSlice(value, 4, 0) << 7);
+    mem.writeInt(u32, code, inst, .little);
+}
+
+fn bitSlice(value: anytype, high: std.math.Log2Int(@TypeOf(value)), low: std.math.Log2Int(@TypeOf(value))) @TypeOf(value) {
+    return (value >> low) & ((@as(@TypeOf(value), 1) << (high - low + 1)) - 1);
+}
+
+const mem = std.mem;
+const std = @import("std");