aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen.zig441
-rw-r--r--src/main.zig2
2 files changed, 434 insertions, 9 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index da1acd2..89daaa4 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -4,9 +4,437 @@ const Allocator = std.mem.Allocator;
const root = @import("root");
const Block = root.Block;
+const Register = enum(u5) {
+ // zig fmt: off
+ zero, ra, sp, gp, tp,
+ t0, t1, t2,
+ s0, s1,
+ a0, a1, a2, a3, a4, a5, a6, a7,
+ s2, s3, s4, s5, s6, s7, s8, s9, s10, s11,
+ t3, t4, t5, t6,
+ // zig fmt: on
+
+ const fp = .s0;
+
+ fn x(number: u5) @This() {
+ return @enumFromInt(number);
+ }
+};
+
+const Opcode = u7;
+
+const Instruction = packed union {
+ r: R,
+ i: I,
+ s: S,
+ b: B,
+ u: U,
+ j: J,
+
+ const R = packed struct(u32) {
+ opcode: Opcode,
+ rd: Register,
+ funct3: u3,
+ rs1: Register,
+ rs2: Register,
+ funct7: u7,
+
+ fn init(opcode: Opcode, rd: Register, funct3: u3, rs1: Register, rs2: Register, funct7: u7) Self {
+ return .{ .r = .{
+ .opcode = opcode,
+ .rd = rd,
+ .funct3 = funct3,
+ .rs1 = rs1,
+ .rs2 = rs2,
+ .funct7 = funct7,
+ } };
+ }
+ };
+ /// rd = rs1 + rs2
+ fn add(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 0, rs1, rs2, 0);
+ }
+ /// rd = rs1 + rs2
+ fn addw(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0111011, rd, 0, rs1, rs2, 0);
+ }
+ /// rd = rs1 - rs2
+ fn sub(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 0, rs1, rs2, 32);
+ }
+ /// rd = rs1 - rs2
+ fn subw(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0111011, rd, 0, rs1, rs2, 32);
+ }
+ /// Bitwise xor.
+ /// rd = rs1 ^ rs2
+ fn xor(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 4, rs1, rs2, 0);
+ }
+ /// Bitwise or.
+ /// rd = rs1 | rs2
+ fn or_(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 6, rs1, rs2, 0);
+ }
+ /// Bitwise and.
+ /// rd = rs1 & rs2
+ fn and_(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 7, rs1, rs2, 0);
+ }
+ /// Shift left logical.
+ /// rd = rs1 << rs2
+ fn sll(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 1, rs1, rs2, 0);
+ }
+ /// Shift left logical word.
+ /// rd = rs1 << rs2
+ fn sllw(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0111011, rd, 1, rs1, rs2, 0);
+ }
+ /// Shift right logical.
+ /// rd = rs1 >> rs2
+ fn srl(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 5, rs1, rs2, 0);
+ }
+ /// Shift right logical word.
+ /// rd = rs1 >> rs2
+ fn srlw(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0111011, rd, 5, rs1, rs2, 0);
+ }
+ /// Shift right arithmetic (preserves sign bit).
+ /// rd = (rs1 >> rs2) | (rs1 & (1 << (bits - 1)))
+ fn sra(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 5, rs1, rs2, 32);
+ }
+ /// Shift right arithmetic (preserves sign bit) word.
+ /// rd = (rs1 >> rs2) | (rs1 & (1 << (bits - 1)))
+ fn sraw(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0111011, rd, 5, rs1, rs2, 32);
+ }
+ /// Set less than, signed.
+ /// rd = rs1 s< rs2 ? 1 : 0
+ fn slt(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 2, rs1, rs2, 0);
+ }
+ /// Set less than, unsigned.
+ /// rd = rs1 u< rs2 ? 1 : 0
+ fn sltu(rd: Register, rs1: Register, rs2: Register) Self {
+ return R.init(0b0110011, rd, 3, rs1, rs2, 0);
+ }
+
+ const I = packed struct(u32) {
+ opcode: Opcode,
+ rd: Register,
+ funct3: u3,
+ rs1: Register,
+ imm: u12,
+
+ fn init(opcode: Opcode, rd: Register, funct3: u3, rs1: Register, imm: i12) Self {
+ return .{ .i = .{
+ .opcode = opcode,
+ .rd = rd,
+ .funct3 = funct3,
+ .rs1 = rs1,
+ .imm = @bitCast(imm),
+ } };
+ }
+ };
+ /// Add immediate.
+ /// rd = rs1 + imm
+ fn addi(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 0, rs1, imm);
+ }
+ /// Add immediate word.
+ /// rd = rs1 + imm
+ fn addiw(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0011011, rd, 0, rs1, imm);
+ }
+ /// Xor immediate.
+ /// rd = rs1 ^ imm
+ fn xori(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 4, rs1, imm);
+ }
+ /// Or immediate.
+ /// rd = rs1 | imm
+ fn ori(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 6, rs1, imm);
+ }
+ /// And immediate.
+ /// rd = rs1 & imm
+ fn andi(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 7, rs1, imm);
+ }
+ /// Shift left logical immediate.
+ /// rd = rs1 << by
+ fn slli(rd: Register, rs1: Register, by: u6) Self {
+ return I.init(0b0010011, rd, 1, rs1, @intCast(by));
+ }
+ /// Shift left logical word immediate.
+ /// rd = rs1 << by
+ fn slliw(rd: Register, rs1: Register, by: u5) Self {
+ return I.init(0b0011011, rd, 1, rs1, @intCast(by));
+ }
+ /// Shift right logical immediate.
+ /// rd = rs1 >> by
+ fn srli(rd: Register, rs1: Register, by: u6) Self {
+ return I.init(0b0010011, rd, 5, rs1, @intCast(by));
+ }
+ /// Shift right logical word immediate.
+ /// rd = rs1 >> by
+ fn srliw(rd: Register, rs1: Register, by: u6) Self {
+ return I.init(0b0011011, rd, 5, rs1, @intCast(by));
+ }
+ /// Shift right arithmetic immediate (preserves sign bit).
+ /// rd = ((((~0 * (rs1 >> (bits - 1))) << bits) | rs1) >> by)
+ fn srai(rd: Register, rs1: Register, by: u6) Self {
+ return I.init(0b0010011, rd, 5, rs1, 0x20 << 5 | @as(i12, @intCast(by)));
+ }
+ /// Shift right arithmetic word immediate (preserves sign bit).
+ /// rd = ((((~0 * (rs1 >> (bits - 1))) << bits) | rs1) >> by)
+ fn sraiw(rd: Register, rs1: Register, by: u6) Self {
+ return I.init(0b0011011, rd, 5, rs1, 0x20 << 5 | @as(i12, @intCast(by)));
+ }
+ /// Set less than immediate, signed.
+ /// rd = rs1 s< rs2 ? 1 : 0
+ fn slti(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 2, rs1, imm);
+ }
+ /// Set less than sign extended immediate, unsigned comparison.
+ /// rd = rs1 u< rs2 ? 1 : 0
+ fn sltiu(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0010011, rd, 3, rs1, imm);
+ }
+ /// Load byte and sign extend.
+ /// rd = @as(*i8, @ptrFromInt(rs1 + imm)).*
+ fn lb(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 0, rs1, imm);
+ }
+ /// Load half and sign extend.
+ /// rd = @as(*i16, @ptrFromInt(rs1 + imm)).*
+ fn lh(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 1, rs1, imm);
+ }
+ /// Load word and sign extend.
+ /// rd = @as(*i32, @ptrFromInt(rs1 + imm)).*
+ fn lw(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 2, rs1, imm);
+ }
+ /// Load double.
+ /// rd = @as(*u64, @ptrFromInt(rs1 + imm)).*
+ fn ld(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 3, rs1, imm);
+ }
+ /// Load byte and zero extend.
+ /// rd = @as(*u8, @ptrFromInt(rs1 + imm)).*
+ fn lbu(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 4, rs1, imm);
+ }
+ /// Load half and zero extend.
+ /// rd = @as(*u16, @ptrFromInt(rs1 + imm)).*
+ fn lhu(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 5, rs1, imm);
+ }
+ /// Load word and zero extend.
+ /// rd = @as(*u32, @ptrFromInt(rs1 + imm)).*
+ fn lwu(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b0000011, rd, 6, rs1, imm);
+ }
+ /// Jump and link register.
+ /// rd = pc + 4; pc = rs1 + imm
+ fn jalr(rd: Register, rs1: Register, imm: i12) Self {
+ return I.init(0b1100111, rd, 0, rs1, imm);
+ }
+ /// Environment call. Issue a syscall on linux
+ fn ecall() Self {
+ return I.init(0b1110011, .zero, 0, .zero, 0);
+ }
+
+ const S = packed struct(u32) {
+ opcode: Opcode,
+ imm4_0: u5,
+ funct3: u3,
+ rs1: Register,
+ rs2: Register,
+ imm11_5: u7,
+
+ fn init(opcode: Opcode, funct3: u3, rs1: Register, rs2: Register, imm: i12) Self {
+ const umm: u12 = @bitCast(imm);
+ return .{ .s = .{
+ .opcode = opcode,
+ .imm4_0 = @truncate(umm),
+ .funct3 = funct3,
+ .rs1 = rs1,
+ .rs2 = rs2,
+ .imm11_5 = umm >> 5,
+ } };
+ }
+ };
+ /// Store byte.
+ /// @as(*u8, @ptrFromInt(rs1 + imm)).* = @truncate(rs2)
+ fn sb(rs1: Register, imm: i12, rs2: Register) Self {
+ return S.init(0b0100011, 0, rs1, rs2, imm);
+ }
+ /// Store half.
+ /// @as(*u16, @ptrFromInt(rs1 + imm)).* = @truncate(rs2)
+ fn sh(rs1: Register, imm: i12, rs2: Register) Self {
+ return S.init(0b0100011, 1, rs1, rs2, imm);
+ }
+ /// Store word.
+ /// @as(*u32, @ptrFromInt(rs1 + imm)).* = @truncate(rs2)
+ fn sw(rs1: Register, imm: i12, rs2: Register) Self {
+ return S.init(0b0100011, 2, rs1, rs2, imm);
+ }
+ /// Store double.
+ /// @as(*u64, @ptrFromInt(rs1 + imm)).* = @truncate(rs2)
+ fn sd(rs1: Register, imm: i12, rs2: Register) Self {
+ return S.init(0b0100011, 3, rs1, rs2, imm);
+ }
+
+ /// The lowest bit of the immediate value, imm, is not stored as imm will always be even.
+ const B = packed struct(u32) {
+ opcode: Opcode,
+ imm11: u1,
+ imm4_1: u4,
+ funct3: u3,
+ rs1: Register,
+ rs2: Register,
+ imm10_5: u6,
+ imm12: u1,
+
+ fn init(opcode: Opcode, funct3: u3, rs1: Register, rs2: Register, imm: i13) Self {
+ std.debug.assert(imm % 2 == 0);
+ const umm: u13 = @bitCast(imm);
+ return .{ .s = .{
+ .opcode = opcode,
+ .imm11 = @truncate(umm >> 11),
+ .imm4_1 = @truncate(umm >> 1),
+ .funct3 = funct3,
+ .rs1 = rs1,
+ .rs2 = rs2,
+ .imm10_5 = @truncate(umm >> 5),
+ .imm12 = umm >> 12,
+ } };
+ }
+ };
+ /// Branch if equal.
+ /// pc = if (rs1 == rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn beq(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 0, rs1, rs2, imm);
+ }
+ /// Branch if not equal.
+ /// pc = if (rs1 != rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn bne(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 1, rs1, rs2, imm);
+ }
+ /// Branch if less than, signed.
+ /// pc = if (rs1 s< rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn blt(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 4, rs1, rs2, imm);
+ }
+ /// Branch if greater than or equal, signed.
+ /// pc = if (rs1 s>= rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn bge(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 5, rs1, rs2, imm);
+ }
+ /// Branch if less than, unsigned.
+ /// pc = if (rs1 u< rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn bltu(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 6, rs1, rs2, imm);
+ }
+ /// Branch if greater than or equal, unsigned.
+ /// pc = if (rs1 u>= rs2) then pc + imm else pc + 4
+ ///
+ /// Advancing pc by 4 is done by all instructions, but shown here for clarity.
+ /// Note that `imm` must be even since function addresses always are.
+ fn bgeu(rs1: Register, rs2: Register, imm: i13) Self {
+ return B.init(0b1100011, 7, rs1, rs2, imm);
+ }
+
+ const U = packed struct(u32) {
+ opcode: Opcode,
+ rd: Register,
+ imm12_31: u20,
+
+ fn init(opcode: Opcode, rd: Register, imm: i20) Self {
+ return .{ .s = .{
+ .opcode = opcode,
+ .rd = rd,
+ .imm12_31 = @bitCast(imm),
+ } };
+ }
+ };
+ /// Load upper immediate.
+ /// rd = imm << 12
+ fn lui(rd: Register, imm: i20) Self {
+ return U.init(0b0110111, rd, imm);
+ }
+ /// Add upper immediate to pc.
+ /// rd = pc + (imm << 12)
+ fn auipc(rd: Register, imm: i20) Self {
+ return U.init(0b0010111, rd, imm);
+ }
+
+ const J = packed struct(u32) {
+ opcode: Opcode,
+ rd: Register,
+ imm12_19: u8,
+ imm11: u1,
+ imm1_10: u10,
+ imm20: u1,
+
+ fn init(opcode: Opcode, rd: Register, imm: i21) Self {
+ std.debug.assert(imm % 2 == 0);
+ const umm: u21 = @bitCast(imm);
+ return .{ .j = .{
+ .opcode = opcode,
+ .rd = rd,
+ .imm12_19 = @truncate(umm >> 12),
+ .imm11 = @truncate(umm >> 11),
+ .imm1_10 = @truncate(umm >> 1),
+ .imm20 = umm >> 20,
+ } };
+ }
+ };
+ /// Jump and link.
+ /// rd = pc + 4; pc = pc + imm
+ fn jal(rd: Register, imm: i21) Self {
+ return J.init(0b1101111, rd, imm);
+ }
+
+ const Self = @This();
+};
+
pub fn create_elf(allocator: Allocator, block: Block) ![]u8 {
_ = block;
+ var output_buffer: std.ArrayList(u8) = .init(allocator);
+ errdefer output_buffer.deinit();
+ try output_buffer.appendNTimes(undefined, @sizeOf(elf.Elf64_Ehdr) + @sizeOf(elf.Elf64_Phdr));
+ const output = output_buffer.writer();
+ for ([_]Instruction{
+ .addi(.a7, .zero, 93),
+ .addi(.a0, .zero, 71),
+ .xori(.a0, .a0, 2),
+ .ecall(),
+ }) |instr| {
+ try output.writeInt(u32, @bitCast(instr), .little);
+ }
+
const base_addr = 0x10000000;
const elf_header: elf.Elf64_Ehdr = .{
.e_ident = elf.MAGIC.* ++ [_]u8{
@@ -36,16 +464,13 @@ pub fn create_elf(allocator: Allocator, block: Block) ![]u8 {
.p_offset = 0,
.p_vaddr = base_addr,
.p_paddr = base_addr,
- .p_filesz = @sizeOf(elf.Elf64_Ehdr) + @sizeOf(elf.Elf64_Phdr) + 40,
- .p_memsz = @sizeOf(elf.Elf64_Ehdr) + @sizeOf(elf.Elf64_Phdr) + 40,
+ .p_filesz = output_buffer.items.len,
+ .p_memsz = output_buffer.items.len,
.p_align = 0x1000,
};
- var output_buffer: std.ArrayList(u8) = .init(allocator);
- errdefer output_buffer.deinit();
- const output = output_buffer.writer();
- try output.writeAll(std.mem.asBytes(&elf_header));
- try output.writeAll(std.mem.asBytes(&program_header));
- for (0..10) |_| try output.writeAll(&std.mem.toBytes(@as(u32, 0x13)));
+ @memcpy(output_buffer.items[0..@sizeOf(elf.Elf64_Ehdr)], std.mem.asBytes(&elf_header));
+ @memcpy(output_buffer.items[@sizeOf(elf.Elf64_Ehdr)..][0..@sizeOf(elf.Elf64_Phdr)], std.mem.asBytes(&program_header));
+
return output_buffer.toOwnedSlice();
}
diff --git a/src/main.zig b/src/main.zig
index a7874d8..34da76b 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -17,7 +17,7 @@ pub fn main() !void {
var args = std.process.args();
_ = args.next();
- const out_file = if (args.next()) |path| try std.fs.cwd().createFile(path, .{}) else std.io.getStdOut();
+ const out_file = if (args.next()) |path| try std.fs.cwd().createFile(path, .{ .mode = 0o777 }) else std.io.getStdOut();
const output = out_file.writer();
// var br = std.io.bufferedReader(std.io.getStdIn().reader());