Commit a212d5931d
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,
+ },
+};