Commit a212d5931d

Koakuma <koachan@protonmail.com>
2022-03-12 18:40:19
stage2 sparcv9: Add register definitions & instruction formats
This adds the GPR/FPR register definitions and instruction formats for SPARCv9. I need to implement a separate enc() function because the register values for the FPRs have to be encoded to a special format that's separate from the normal register ID.
1 parent 8a43d67
Changed files (1)
src
arch
sparcv9
src/arch/sparcv9/bits.zig
@@ -0,0 +1,447 @@
+const std = @import("std");
+const DW = std.dwarf;
+const testing = std.testing;
+
+/// General purpose registers in the SPARCv9 instruction set
+pub const Register = enum(u6) {
+    // zig fmt: off
+    g0,    g1,    g2,    g3,    g4,    g5,    g6,    g7,
+    o0,    o1,    o2,    o3,    o4,    o5,    o6,    o7,
+    l0,    l1,    l2,    l3,    l4,    l5,    l6,    l7,
+  @"i0", @"i1", @"i2", @"i3", @"i4", @"i5", @"i6", @"i7",
+
+    sp = 46, // stack pointer (o6)
+    fp = 62, // frame pointer (i6)
+    // zig fmt: on
+
+    pub fn id(self: Register) u5 {
+        return @truncate(u5, @enumToInt(self));
+    }
+
+    pub fn enc(self: Register) u5 {
+        // For integer registers, enc() == id().
+        return self.id();
+    }
+
+    pub fn dwarfLocOp(reg: Register) u8 {
+        return @as(u8, reg.id()) + DW.OP.reg0;
+    }
+};
+
+test "Register.id" {
+    // SP
+    try testing.expectEqual(@as(u5, 14), Register.o6.id());
+    try testing.expectEqual(Register.o6.id(), Register.sp.id());
+
+    // FP
+    try testing.expectEqual(@as(u5, 30), Register.@"i6".id());
+    try testing.expectEqual(Register.@"i6".id(), Register.fp.id());
+
+    // x0
+    try testing.expectEqual(@as(u5, 0), Register.g0.id());
+    try testing.expectEqual(@as(u5, 8), Register.o0.id());
+    try testing.expectEqual(@as(u5, 16), Register.l0.id());
+    try testing.expectEqual(@as(u5, 24), Register.@"i0".id());
+}
+
+test "Register.enc" {
+    // x0
+    try testing.expectEqual(@as(u5, 0), Register.g0.enc());
+    try testing.expectEqual(@as(u5, 8), Register.o0.enc());
+    try testing.expectEqual(@as(u5, 16), Register.l0.enc());
+    try testing.expectEqual(@as(u5, 24), Register.@"i0".enc());
+
+    // For integer registers, enc() == id().
+    try testing.expectEqual(Register.g0.enc(), Register.g0.id());
+    try testing.expectEqual(Register.o0.enc(), Register.o0.id());
+    try testing.expectEqual(Register.l0.enc(), Register.l0.id());
+    try testing.expectEqual(Register.@"i0".enc(), Register.@"i0".id());
+}
+
+/// Scalar floating point registers in the SPARCv9 instruction set
+pub const FloatingPointRegister = enum(u7) {
+    // SPARCv9 has 64 f32 registers, 32 f64 registers, and 16 f128 registers,
+    // which are aliased in this way:
+    //
+    //      |    %d0    |    %d2    |
+    // %q0  | %f0 | %f1 | %f2 | %f3 |
+    //      |    %d4    |    %d6    |
+    // %q4  | %f4 | %f5 | %f6 | %f7 |
+    // ...
+    //      |    %d60     |    %d62     |
+    // %q60 | %f60 | %f61 | %f62 | %f63 |
+    //
+    // Though, since the instructions uses five-bit addressing, only %f0-%f31
+    // is usable with f32 instructions.
+
+    // zig fmt: off
+
+    // 32-bit registers
+     @"f0",  @"f1",  @"f2",  @"f3",  @"f4",  @"f5",  @"f6",  @"f7",
+     @"f8",  @"f9", @"f10", @"f11", @"f12", @"f13", @"f14", @"f15",
+    @"f16", @"f17", @"f18", @"f19", @"f20", @"f21", @"f22", @"f23",
+    @"f24", @"f25", @"f26", @"f27", @"f28", @"f29", @"f30", @"f31",
+
+    // 64-bit registers
+     d0,  d2,  d4,  d6,  d8, d10, d12, d14,
+    d16, d18, d20, d22, d24, d26, d28, d30,
+    d32, d34, d36, d38, d40, d42, d44, d46,
+    d48, d50, d52, d54, d56, d58, d60, d62,
+
+    // 128-bit registers
+     q0,  q4,  q8, q12, q16, q20, q24, q28,
+    q32, q36, q40, q44, q48, q52, q56, q60,
+    // zig fmt: on
+
+    pub fn id(self: FloatingPointRegister) u6 {
+        return switch (self.size()) {
+            32 => @truncate(u6, @enumToInt(self)),
+            64 => @truncate(u6, (@enumToInt(self) - 32) * 2),
+            128 => @truncate(u6, (@enumToInt(self) - 64) * 4),
+            else => unreachable,
+        };
+    }
+
+    pub fn enc(self: FloatingPointRegister) u5 {
+        // Floating point registers use an encoding scheme to map from the 6-bit
+        // ID to 5-bit encoded value.
+        // (See section 5.1.4.1 of SPARCv9 ISA specification)
+
+        const reg_id = self.id();
+        return @truncate(u5, reg_id | (reg_id >> 5));
+    }
+
+    /// Returns the bit-width of the register.
+    pub fn size(self: FloatingPointRegister) u8 {
+        return switch (@enumToInt(self)) {
+            0...31 => 32,
+            32...63 => 64,
+            64...79 => 128,
+            else => unreachable,
+        };
+    }
+};
+
+test "FloatingPointRegister.id" {
+    // Low region
+    try testing.expectEqual(@as(u6, 0), FloatingPointRegister.q0.id());
+    try testing.expectEqual(FloatingPointRegister.q0.id(), FloatingPointRegister.d0.id());
+    try testing.expectEqual(FloatingPointRegister.d0.id(), FloatingPointRegister.@"f0".id());
+
+    try testing.expectEqual(@as(u6, 28), FloatingPointRegister.q28.id());
+    try testing.expectEqual(FloatingPointRegister.q28.id(), FloatingPointRegister.d28.id());
+    try testing.expectEqual(FloatingPointRegister.d28.id(), FloatingPointRegister.@"f28".id());
+
+    // High region
+    try testing.expectEqual(@as(u6, 32), FloatingPointRegister.q32.id());
+    try testing.expectEqual(FloatingPointRegister.q32.id(), FloatingPointRegister.d32.id());
+
+    try testing.expectEqual(@as(u6, 60), FloatingPointRegister.q60.id());
+    try testing.expectEqual(FloatingPointRegister.q60.id(), FloatingPointRegister.d60.id());
+}
+
+test "FloatingPointRegister.enc" {
+    // f registers
+    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.@"f0".enc());
+    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.@"f1".enc());
+    try testing.expectEqual(@as(u5, 31), FloatingPointRegister.@"f31".enc());
+
+    // d registers
+    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.enc());
+    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.d32.enc());
+    try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d62.enc());
+
+    // q registers
+    try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.enc());
+    try testing.expectEqual(@as(u5, 1), FloatingPointRegister.q32.enc());
+    try testing.expectEqual(@as(u5, 29), FloatingPointRegister.q60.enc());
+}
+
+/// Represents an instruction in the SPARCv9 instruction set
+pub const Instruction = union(enum) {
+    // Some of the instruction formats have several minor formats, here I
+    // name them with letters since there's no official naming scheme.
+    // TODO: need to rename the minor formats to a more descriptive name.
+
+    // Format 1 (op = 1): CALL
+    format_1: packed struct {
+        op: u2 = 0b01,
+        disp30: u30,
+    },
+
+    // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
+    format_2a: packed struct {
+        op: u2 = 0b00,
+        rd: u5,
+        op2: u3,
+        imm22: u22,
+    },
+    format_2b: packed struct {
+        op: u2 = 0b00,
+        a: u1,
+        cond: u4,
+        op2: u3,
+        disp22: u22,
+    },
+    format_2c: packed struct {
+        op: u2 = 0b00,
+        a: u1,
+        cond: u4,
+        op2: u3,
+        cc1: u1,
+        cc0: u1,
+        p: u1,
+        disp19: u19,
+    },
+    format_2d: packed struct {
+        op: u2 = 0b00,
+        a: u1,
+        fixed: u1 = 0b0,
+        rcond: u3,
+        op2: u3,
+        d16hi: u2,
+        p: u1,
+        rs1: u5,
+        d16lo: u14,
+    },
+
+    // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
+    format_3a: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        reserved: u8 = 0b00000000,
+        rs2: u5,
+    },
+    format_3b: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        simm13: u13,
+    },
+    format_3c: packed struct {
+        op: u2,
+        reserved1: u5 = 0b00000,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        reserved2: u8 = 0b00000000,
+        rs2: u5,
+    },
+    format_3d: packed struct {
+        op: u2,
+        reserved: u5 = 0b00000,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        simm13: u13,
+    },
+    format_3e: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        rcond: u3,
+        reserved: u5 = 0b00000,
+        rs2: u5,
+    },
+    format_3f: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        rcond: u3,
+        simm10: u10,
+    },
+    format_3g: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        reserved: u8 = 0b00000000,
+        rs2: u5,
+    },
+    format_3h: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        reserved: u6,
+        cmask: u3,
+        mmask: u4,
+    },
+    format_3i: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        imm_asi: u8,
+        rs2: u5,
+    },
+    format_3j: packed struct {
+        op: u2,
+        impl_dep1: u5,
+        op3: u6,
+        impl_dep2: u19,
+    },
+    format_3k: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        x: u1,
+        reserved: u7 = 0b0000000,
+        rs2: u5,
+    },
+    format_3l: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        x: u1 = 0b0,
+        reserved: u7 = 0b0000000,
+        shcnt32: u5,
+    },
+    format_3m: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        x: u1 = 0b1,
+        reserved: u6 = 0b000000,
+        shcnt64: u6,
+    },
+    format_3n: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        reserved: u5 = 0b00000,
+        opf: u9,
+        rs2: u5,
+    },
+    format_3o: packed struct {
+        op: u2,
+        fixed: u3 = 0b000,
+        cc1: u1,
+        cc0: i1,
+        op3: u6,
+        opf: u9,
+        rs2: u5,
+    },
+    format_3p: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        opf: u9,
+        rs2: u5,
+    },
+    format_3q: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        reserved: u14 = 0b00000000000000,
+    },
+    format_3r: packed struct {
+        op: u2,
+        fcn: u5,
+        op3: u6,
+        reserved: u19 = 0b0000000000000000000,
+    },
+    format_3s: packed struct {
+        op: u2,
+        rd: u5,
+        op3: u6,
+        reserved: u19 = 0b0000000000000000000,
+    },
+
+    //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
+    format_4a: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b0,
+        cc1: u1,
+        cc0: u1,
+        reserved: u6 = 0b000000,
+        rs2: u5,
+    },
+    format_4b: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        cc1: u1,
+        cc0: u1,
+        simm11: u11,
+    },
+    format_4c: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        cc2: u1,
+        cond: u4,
+        i: u1 = 0b0,
+        cc1: u1,
+        cc0: u1,
+        reserved: u6 = 0b000000,
+        rs2: u5,
+    },
+    format_4d: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        cc2: u1,
+        cond: u4,
+        i: u1 = 0b1,
+        cc1: u1,
+        cc0: u1,
+        simm11: u11,
+    },
+    format_4e: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        i: u1 = 0b1,
+        cc1: u1,
+        cc0: u1,
+        reserved: u4 = 0b0000,
+        sw_trap: u7,
+    },
+    format_4f: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        rs1: u5,
+        fixed: u1 = 0b0,
+        rcond: u3,
+        opf_low: u5,
+        rs2: u5,
+    },
+    format_4g: packed struct {
+        op: u2 = 0b10,
+        rd: u5,
+        op3: u6,
+        fixed: u1 = 0b0,
+        cond: u4,
+        opf_cc: u3,
+        opf_low: u6,
+        rs2: u5,
+    },
+};