This is an extern struct so that inline assembly in current can use field offsets.
const Sparc = extern struct
const Sparc = extern struct {
g: [8]Gpr,
o: [8]Gpr,
l: [8]Gpr,
i: [8]Gpr,
pc: Gpr,
pub const Gpr = if (native_arch == .sparc64) u64 else u32;
pub inline fn current() Sparc {
flushWindows();
var ctx: Sparc = undefined;
asm volatile (if (Gpr == u64)
\\ stx %g0, [%l0 + 0]
\\ stx %g1, [%l0 + 8]
\\ stx %g2, [%l0 + 16]
\\ stx %g3, [%l0 + 24]
\\ stx %g4, [%l0 + 32]
\\ stx %g5, [%l0 + 40]
\\ stx %g6, [%l0 + 48]
\\ stx %g7, [%l0 + 56]
\\ stx %o0, [%l0 + 64]
\\ stx %o1, [%l0 + 72]
\\ stx %o2, [%l0 + 80]
\\ stx %o3, [%l0 + 88]
\\ stx %o4, [%l0 + 96]
\\ stx %o5, [%l0 + 104]
\\ stx %o6, [%l0 + 112]
\\ stx %o7, [%l0 + 120]
\\ stx %l0, [%l0 + 128]
\\ stx %l1, [%l0 + 136]
\\ stx %l2, [%l0 + 144]
\\ stx %l3, [%l0 + 152]
\\ stx %l4, [%l0 + 160]
\\ stx %l5, [%l0 + 168]
\\ stx %l6, [%l0 + 176]
\\ stx %l7, [%l0 + 184]
\\ stx %i0, [%l0 + 192]
\\ stx %i1, [%l0 + 200]
\\ stx %i2, [%l0 + 208]
\\ stx %i3, [%l0 + 216]
\\ stx %i4, [%l0 + 224]
\\ stx %i5, [%l0 + 232]
\\ stx %i6, [%l0 + 240]
\\ stx %i7, [%l0 + 248]
\\ call 1f
\\1:
\\ stx %o7, [%l0 + 256]
else
\\ std %g0, [%l0 + 0]
\\ std %g2, [%l0 + 8]
\\ std %g4, [%l0 + 16]
\\ std %g6, [%l0 + 24]
\\ std %o0, [%l0 + 32]
\\ std %o2, [%l0 + 40]
\\ std %o4, [%l0 + 48]
\\ std %o6, [%l0 + 56]
\\ std %l0, [%l0 + 64]
\\ std %l2, [%l0 + 72]
\\ std %l4, [%l0 + 80]
\\ std %l6, [%l0 + 88]
\\ std %i0, [%l0 + 96]
\\ std %i2, [%l0 + 104]
\\ std %i4, [%l0 + 112]
\\ std %i6, [%l0 + 120]
\\ call 1f
\\1:
\\ st %o7, [%l0 + 128]
:
: [ctx] "{l0}" (&ctx),
: .{ .o7 = true, .memory = true });
return ctx;
}
noinline fn flushWindows() void {
// Flush all register windows except the current one (hence `noinline`). This ensures that
// we actually see meaningful data on the stack when we walk the frame chain.
if (comptime builtin.target.cpu.has(.sparc, .v9))
asm volatile ("flushw" ::: .{ .memory = true })
else
asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS
}
pub fn getFp(ctx: *const Sparc) usize {
return ctx.i[6];
}
pub fn getPc(ctx: *const Sparc) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...7 => return @ptrCast(&ctx.g[register_num]),
8...15 => return @ptrCast(&ctx.o[register_num - 8]),
16...23 => return @ptrCast(&ctx.l[register_num - 16]),
24...31 => return @ptrCast(&ctx.i[register_num - 24]),
32 => return @ptrCast(&ctx.pc),
else => return error.InvalidRegister,
}
}
}