diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-21 22:48:19 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-21 22:48:19 +0100 |
| commit | 9fd112804fbdeb288b90cf8323d3ebefaa26372f (patch) | |
| tree | 937d9c1192d8b3e67cefba78792756cd8bdbbbe2 /src/link | |
| parent | 8ba31ed39a84ba00e85c456e74d0ea4d682d86c0 (diff) | |
| download | zig-9fd112804fbdeb288b90cf8323d3ebefaa26372f.tar.gz zig-9fd112804fbdeb288b90cf8323d3ebefaa26372f.zip | |
link: commit missing files
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/aarch64.zig | 106 | ||||
| -rw-r--r-- | src/link/riscv.zig | 58 |
2 files changed, 164 insertions, 0 deletions
diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig new file mode 100644 index 0000000000..a9295026d2 --- /dev/null +++ b/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; diff --git a/src/link/riscv.zig b/src/link/riscv.zig new file mode 100644 index 0000000000..2cdc050996 --- /dev/null +++ b/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"); |
