| 1 | pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytype) void { |
| 2 | const mask: u8 = 0b11_000000; |
| 3 | const actual: i8 = @truncate(addend); |
| 4 | var value: u8 = mem.readInt(u8, code, .little); |
| 5 | switch (op) { |
| 6 | .set => value = (value & mask) | @as(u8, @bitCast(actual & ~mask)), |
| 7 | .sub => value = (value & mask) | (@as(u8, @bitCast(@as(i8, @bitCast(value)) -| actual)) & ~mask), |
| 8 | } |
| 9 | mem.writeInt(u8, code, value, .little); |
| 10 | } |
| 11 | |
| 12 | pub fn writeSubUleb(code: []u8, addend: i64) void { |
| 13 | var reader: std.Io.Reader = .fixed(code); |
| 14 | const value = reader.takeLeb128(u64) catch unreachable; |
| 15 | overwriteUleb(code, value -% @as(u64, @intCast(addend))); |
| 16 | } |
| 17 | |
| 18 | pub fn writeSetUleb(code: []u8, addend: i64) void { |
| 19 | overwriteUleb(code, @intCast(addend)); |
| 20 | } |
| 21 | |
| 22 | fn overwriteUleb(code: []u8, addend: u64) void { |
| 23 | var value: u64 = addend; |
| 24 | var i: usize = 0; |
| 25 | |
| 26 | while (true) { |
| 27 | const byte = code[i]; |
| 28 | if (byte & 0x80 == 0) break; |
| 29 | code[i] = 0x80 | @as(u8, @truncate(value & 0x7f)); |
| 30 | i += 1; |
| 31 | value >>= 7; |
| 32 | } |
| 33 | code[i] = @truncate(value & 0x7f); |
| 34 | } |
| 35 | |
| 36 | pub fn writeAddend( |
| 37 | comptime Int: type, |
| 38 | comptime op: enum { add, sub }, |
| 39 | code: *[@typeInfo(Int).int.bits / 8]u8, |
| 40 | value: anytype, |
| 41 | ) void { |
| 42 | var V: Int = mem.readInt(Int, code, .little); |
| 43 | const addend: Int = @truncate(value); |
| 44 | switch (op) { |
| 45 | .add => V +|= addend, // TODO: I think saturating arithmetic is correct here |
| 46 | .sub => V -|= addend, |
| 47 | } |
| 48 | mem.writeInt(Int, code, V, .little); |
| 49 | } |
| 50 | |
| 51 | pub fn writeInstU(code: *[4]u8, value: u32) void { |
| 52 | var data: Instruction = .{ .U = mem.bytesToValue(@FieldType(Instruction, "U"), code) }; |
| 53 | const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800); |
| 54 | data.U.imm12_31 = bitSlice(compensated, 31, 12); |
| 55 | mem.writeInt(u32, code, data.toU32(), .little); |
| 56 | } |
| 57 | |
| 58 | pub fn writeInstI(code: *[4]u8, value: u32) void { |
| 59 | var data: Instruction = .{ .I = mem.bytesToValue(@FieldType(Instruction, "I"), code) }; |
| 60 | data.I.imm0_11 = bitSlice(value, 11, 0); |
| 61 | mem.writeInt(u32, code, data.toU32(), .little); |
| 62 | } |
| 63 | |
| 64 | pub fn writeInstS(code: *[4]u8, value: u32) void { |
| 65 | var data: Instruction = .{ .S = mem.bytesToValue(@FieldType(Instruction, "S"), code) }; |
| 66 | data.S.imm0_4 = bitSlice(value, 4, 0); |
| 67 | data.S.imm5_11 = bitSlice(value, 11, 5); |
| 68 | mem.writeInt(u32, code, data.toU32(), .little); |
| 69 | } |
| 70 | |
| 71 | pub fn writeInstJ(code: *[4]u8, value: u32) void { |
| 72 | var data: Instruction = .{ .J = mem.bytesToValue(@FieldType(Instruction, "J"), code) }; |
| 73 | data.J.imm1_10 = bitSlice(value, 10, 1); |
| 74 | data.J.imm11 = bitSlice(value, 11, 11); |
| 75 | data.J.imm12_19 = bitSlice(value, 19, 12); |
| 76 | data.J.imm20 = bitSlice(value, 20, 20); |
| 77 | mem.writeInt(u32, code, data.toU32(), .little); |
| 78 | } |
| 79 | |
| 80 | pub fn writeInstB(code: *[4]u8, value: u32) void { |
| 81 | var data: Instruction = .{ .B = mem.bytesToValue(@FieldType(Instruction, "B"), code) }; |
| 82 | data.B.imm1_4 = bitSlice(value, 4, 1); |
| 83 | data.B.imm5_10 = bitSlice(value, 10, 5); |
| 84 | data.B.imm11 = bitSlice(value, 11, 11); |
| 85 | data.B.imm12 = bitSlice(value, 12, 12); |
| 86 | mem.writeInt(u32, code, data.toU32(), .little); |
| 87 | } |
| 88 | |
| 89 | fn bitSlice( |
| 90 | value: anytype, |
| 91 | comptime high: comptime_int, |
| 92 | comptime low: comptime_int, |
| 93 | ) std.math.IntFittingRange(0, 1 << high - low) { |
| 94 | return @truncate((value >> low) & (1 << (high - low + 1)) - 1); |
| 95 | } |
| 96 | |
| 97 | pub const Eflags = packed struct(u32) { |
| 98 | rvc: bool, |
| 99 | fabi: FloatAbi, |
| 100 | rve: bool, |
| 101 | tso: bool, |
| 102 | _reserved: u19 = 0, |
| 103 | _unused: u8 = 0, |
| 104 | |
| 105 | pub const FloatAbi = enum(u2) { |
| 106 | soft = 0b00, |
| 107 | single = 0b01, |
| 108 | double = 0b10, |
| 109 | quad = 0b11, |
| 110 | }; |
| 111 | }; |
| 112 | |
| 113 | const mem = std.mem; |
| 114 | const std = @import("std"); |
| 115 | |
| 116 | const encoding = @import("../codegen/riscv64/encoding.zig"); |
| 117 | const Instruction = encoding.Instruction; |