mirror of
https://github.com/ziglang/zig.git
synced 2026-01-18 13:25:15 +00:00
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.
This commit is contained in:
parent
8a43d67c3b
commit
a212d5931d
447
src/arch/sparcv9/bits.zig
Normal file
447
src/arch/sparcv9/bits.zig
Normal file
@ -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,
|
||||
},
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user