From a212d5931d99653de28933499a2a0bded1b8d2db Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Mar 2022 00:40:19 +0700 Subject: [PATCH 01/20] 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. --- src/arch/sparcv9/bits.zig | 447 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 src/arch/sparcv9/bits.zig diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig new file mode 100644 index 0000000000..71c13482b9 --- /dev/null +++ b/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, + }, +}; From 92c262aa9361589dbe6176dbbb8c32a172bdc96c Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Mar 2022 20:25:25 +0700 Subject: [PATCH 02/20] stage2 sparcv9: Add initial toU32 function for serialization --- src/arch/sparcv9/bits.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 71c13482b9..adf8ab1810 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -444,4 +444,8 @@ pub const Instruction = union(enum) { opf_low: u6, rs2: u5, }, + + pub fn toU32(self: Instruction) u32 { + return @bitCast(u32, self); + } }; From 048035ea555864ff994cee872d5be050d53be38f Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Mar 2022 21:00:16 +0700 Subject: [PATCH 03/20] stage2 sparcv9: Add Format 1 encoder --- src/arch/sparcv9/bits.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index adf8ab1810..00739ad2f6 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -1,5 +1,6 @@ const std = @import("std"); const DW = std.dwarf; +const assert = std.debug.assert; const testing = std.testing; /// General purpose registers in the SPARCv9 instruction set @@ -448,4 +449,15 @@ pub const Instruction = union(enum) { pub fn toU32(self: Instruction) u32 { return @bitCast(u32, self); } + + fn format1(disp: i32) Instruction { + // In SPARC, branch target needs to be aligned to 4 bytes. + assert(disp % 4 == 0); + + // Discard the last two bits since those are implicitly zero. + const udisp = @truncate(u30, @bitCast(u32, disp) >> 2); + return Instruction{ .format_1 = .{ + .disp30 = udisp, + } }; + } }; From fbcea863334bebdd6bb465c84b97122e78f19d5d Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Mar 2022 21:54:44 +0700 Subject: [PATCH 04/20] stage2 sparcv9: Add Format 2 encoder --- src/arch/sparcv9/bits.zig | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 00739ad2f6..a1e9973f91 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -460,4 +460,72 @@ pub const Instruction = union(enum) { .disp30 = udisp, } }; } + + fn format2a(rd: Register, op2: u3, imm: i22) Instruction { + const umm = @bitCast(u22, imm); + return Instruction{ + .format_2a = .{ + .rd = rd.enc(), + .op2 = op2, + .imm22 = umm, + }, + }; + } + + fn format2b(a: u1, cond: u4, op2: u3, disp: i24) Instruction { + // In SPARC, branch target needs to be aligned to 4 bytes. + assert(disp % 4 == 0); + + // Discard the last two bits since those are implicitly zero. + const udisp = @truncate(u22, @bitCast(u24, disp) >> 2); + return Instruction{ + .format_2b = .{ + .a = a, + .cond = cond, + .op2 = op2, + .disp22 = udisp, + }, + }; + } + + fn format2c(a: u1, cond: u4, op2: u3, cc1: u1, cc0: u1, p: u1, disp: i21) Instruction { + // In SPARC, branch target needs to be aligned to 4 bytes. + assert(disp % 4 == 0); + + // Discard the last two bits since those are implicitly zero. + const udisp = @truncate(u19, @bitCast(u21, disp) >> 2); + return Instruction{ + .format_2c = .{ + .a = a, + .cond = cond, + .op2 = op2, + .cc1 = cc1, + .cc0 = cc0, + .p = p, + .disp19 = udisp, + }, + }; + } + + fn format2d(a: u1, rcond: u3, op2: u3, p: u1, rs1: Register, disp: i18) Instruction { + // In SPARC, branch target needs to be aligned to 4 bytes. + assert(disp % 4 == 0); + + // Discard the last two bits since those are implicitly zero, + // and split it into low and high parts. + const udisp = @truncate(u16, @bitCast(u18, disp) >> 2); + const udisp_hi = @truncate(u2, (udisp & 0b1100_0000_0000_0000) >> 14); + const udisp_lo = @truncate(u14, udisp & 0b0011_1111_1111_1111); + return Instruction{ + .format_2a = .{ + .a = a, + .rcond = rcond, + .op2 = op2, + .p = p, + .rs1 = rs1.enc(), + .d16hi = udisp_hi, + .d16lo = udisp_lo, + }, + }; + } }; From 672da9c613939c5c76e68cb3acae9f65845f6e56 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Mar 2022 22:29:50 +0700 Subject: [PATCH 05/20] stage2 sparcv9: Add CCR and RCondition enums This adds the list of CCRs and `rcond` constants as specified by the ISA, and changes the template functions to use them. --- src/arch/sparcv9/bits.zig | 54 +++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index a1e9973f91..e96a4555eb 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -446,6 +446,32 @@ pub const Instruction = union(enum) { rs2: u5, }, + pub const CCR = enum(u3) { + fcc0, + fcc1, + fcc2, + fcc3, + icc, + reserved1, + xcc, + reserved2, + }; + + pub const RCondition = enum(u3) { + reserved1, + eq_zero, + le_zero, + lt_zero, + reserved, + ne_zero, + gt_zero, + ge_zero, + }; + + // TODO: Need to define an enum for `cond` values + // This is kinda challenging since the cond values have different meanings + // depending on whether it's operating on integer or FP CCR. + pub fn toU32(self: Instruction) u32 { return @bitCast(u32, self); } @@ -462,17 +488,16 @@ pub const Instruction = union(enum) { } fn format2a(rd: Register, op2: u3, imm: i22) Instruction { - const umm = @bitCast(u22, imm); return Instruction{ .format_2a = .{ .rd = rd.enc(), .op2 = op2, - .imm22 = umm, + .imm22 = @bitCast(u22, imm), }, }; } - fn format2b(a: u1, cond: u4, op2: u3, disp: i24) Instruction { + fn format2b(annul: bool, cond: u4, op2: u3, disp: i24) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -480,7 +505,7 @@ pub const Instruction = union(enum) { const udisp = @truncate(u22, @bitCast(u24, disp) >> 2); return Instruction{ .format_2b = .{ - .a = a, + .a = @boolToInt(annul), .cond = cond, .op2 = op2, .disp22 = udisp, @@ -488,26 +513,29 @@ pub const Instruction = union(enum) { }; } - fn format2c(a: u1, cond: u4, op2: u3, cc1: u1, cc0: u1, p: u1, disp: i21) Instruction { + fn format2c(annul: bool, cond: u4, op2: u3, ccr: CCR, pt: bool, disp: i21) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); // Discard the last two bits since those are implicitly zero. const udisp = @truncate(u19, @bitCast(u21, disp) >> 2); + + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) > 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format_2c = .{ - .a = a, + .a = @boolToInt(annul), .cond = cond, .op2 = op2, - .cc1 = cc1, - .cc0 = cc0, - .p = p, + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .p = @boolToInt(pt), .disp19 = udisp, }, }; } - fn format2d(a: u1, rcond: u3, op2: u3, p: u1, rs1: Register, disp: i18) Instruction { + fn format2d(annul: bool, rcond: RCondition, op2: u3, pt: bool, rs1: Register, disp: i18) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -518,10 +546,10 @@ pub const Instruction = union(enum) { const udisp_lo = @truncate(u14, udisp & 0b0011_1111_1111_1111); return Instruction{ .format_2a = .{ - .a = a, - .rcond = rcond, + .a = @boolToInt(annul), + .rcond = @enumToInt(rcond), .op2 = op2, - .p = p, + .p = @boolToInt(pt), .rs1 = rs1.enc(), .d16hi = udisp_hi, .d16lo = udisp_lo, From f64ce3abaf4cad2ab158c754d1d818cd8c8ad1de Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 00:29:24 +0700 Subject: [PATCH 06/20] stage2 sparcv9: Fix typo in `format2c` --- src/arch/sparcv9/bits.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index e96a4555eb..fe240ca190 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -520,7 +520,7 @@ pub const Instruction = union(enum) { // Discard the last two bits since those are implicitly zero. const udisp = @truncate(u19, @bitCast(u21, disp) >> 2); - const ccr_cc1 = @truncate(u1, @enumToInt(ccr) > 1); + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format_2c = .{ From f5a4d24cc0ddb65911a9ede1d364577afde696b4 Mon Sep 17 00:00:00 2001 From: Flandre Scarlet Date: Mon, 14 Mar 2022 06:43:33 +0700 Subject: [PATCH 07/20] stage2 sparcv9: Add Format 4 encoder --- src/arch/sparcv9/bits.zig | 106 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index fe240ca190..816965cbb9 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -471,6 +471,7 @@ pub const Instruction = union(enum) { // TODO: Need to define an enum for `cond` values // This is kinda challenging since the cond values have different meanings // depending on whether it's operating on integer or FP CCR. + pub const Condition = u4; pub fn toU32(self: Instruction) u32 { return @bitCast(u32, self); @@ -556,4 +557,109 @@ pub const Instruction = union(enum) { }, }; } + + fn format4a(rd: Register, op3: u6, rs1: Register, cc: CCR, rs2: Register) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format4a = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .rs2 = rs2.enc(), + }, + }; + } + + fn format4b(rd: Register, op3: u6, rs1: Register, cc: CCR, simm11: u11) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format4b = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .simm11 = simm11, + }, + }; + } + + fn format4c(rd: Register, op3: u6, cc: CCR, cond: Condition, rs2: Register) Instruction { + const ccr_cc2 = @truncate(u1, @enumToInt(cc) >> 2); + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format4c = .{ + .rd = rd.enc(), + .op3 = op3, + .cc2 = ccr_cc2, + .cond = cond, + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .rs2 = rs2.enc(), + }, + }; + } + + fn format4d(rd: Register, op3: u6, cc: CCR, cond: Condition, simm11: u11) Instruction { + const ccr_cc2 = @truncate(u1, @enumToInt(cc) >> 2); + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format4d = .{ + .rd = rd.enc(), + .op3 = op3, + .cc2 = ccr_cc2, + .cond = cond, + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .simm11 = simm11, + }, + }; + } + + fn format4e(rd: Register, op3: u6, rs1: Register, cc: CCR, sw_trap: u7) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format4e = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .sw_trap = sw_trap, + }, + }; + } + + fn format4f(rd: Register, op3: u6, rs1: Register, rcond: RCondition, opf_low: u5, rs2: Register) Instruction { + return Instruction{ + .format4f = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .rcond = @enumToInt(rcond), + .opf_low = opf_low, + .rs2 = rs2.enc(), + }, + }; + } + + fn format4g(rd: Register, op3: u6, cond: Condition, opf_cc: u3, opf_low: u6, rs2: Register) Instruction { + return Instruction{ + .format4g = .{ + .rd = rd.enc(), + .op3 = op3, + .cond = cond, + .opf_cc = opf_cc, + .opf_low = opf_low, + .rs2 = rs2.enc(), + }, + }; + } }; From a8dde7f0ae0776bc3ba5ad45fd0dd6578171425a Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 07:05:06 +0700 Subject: [PATCH 08/20] stage2 sparcv9: Minor parameter type changes Use the `Condition` type for 2b/2c and signed integer for 4b/4d. --- src/arch/sparcv9/bits.zig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 816965cbb9..7b164a39aa 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -498,7 +498,7 @@ pub const Instruction = union(enum) { }; } - fn format2b(annul: bool, cond: u4, op2: u3, disp: i24) Instruction { + fn format2b(annul: bool, cond: Condition, op2: u3, disp: i24) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -514,7 +514,7 @@ pub const Instruction = union(enum) { }; } - fn format2c(annul: bool, cond: u4, op2: u3, ccr: CCR, pt: bool, disp: i21) Instruction { + fn format2c(annul: bool, cond: Condition, op2: u3, ccr: CCR, pt: bool, disp: i21) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -573,7 +573,7 @@ pub const Instruction = union(enum) { }; } - fn format4b(rd: Register, op3: u6, rs1: Register, cc: CCR, simm11: u11) Instruction { + fn format4b(rd: Register, op3: u6, rs1: Register, cc: CCR, imm: i11) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(cc)); return Instruction{ @@ -583,7 +583,7 @@ pub const Instruction = union(enum) { .rs1 = rs1.enc(), .cc1 = ccr_cc1, .cc0 = ccr_cc0, - .simm11 = simm11, + .simm11 = @bitCast(i11, imm), }, }; } @@ -605,7 +605,7 @@ pub const Instruction = union(enum) { }; } - fn format4d(rd: Register, op3: u6, cc: CCR, cond: Condition, simm11: u11) Instruction { + fn format4d(rd: Register, op3: u6, cc: CCR, cond: Condition, imm: i11) Instruction { const ccr_cc2 = @truncate(u1, @enumToInt(cc) >> 2); const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(cc)); @@ -617,7 +617,7 @@ pub const Instruction = union(enum) { .cond = cond, .cc1 = ccr_cc1, .cc0 = ccr_cc0, - .simm11 = simm11, + .simm11 = @bitCast(i11, imm), }, }; } From bfe92f7d8cc9ceb76f194f8092cced081d8e5c84 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 20:09:56 +0700 Subject: [PATCH 09/20] stage2 sparcv9: Fix bitcast typos --- src/arch/sparcv9/bits.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 7b164a39aa..b57809671f 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -583,7 +583,7 @@ pub const Instruction = union(enum) { .rs1 = rs1.enc(), .cc1 = ccr_cc1, .cc0 = ccr_cc0, - .simm11 = @bitCast(i11, imm), + .simm11 = @bitCast(u11, imm), }, }; } @@ -617,7 +617,7 @@ pub const Instruction = union(enum) { .cond = cond, .cc1 = ccr_cc1, .cc0 = ccr_cc0, - .simm11 = @bitCast(i11, imm), + .simm11 = @bitCast(u11, imm), }, }; } From 17075bdb0c8c14271f87aebf9b8fa80c9accf7bb Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 21:56:15 +0700 Subject: [PATCH 10/20] stage2 sparcv9: Add Format 3 encoder --- src/arch/sparcv9/bits.zig | 243 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 8 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index b57809671f..621870b5e5 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -271,11 +271,11 @@ pub const Instruction = union(enum) { }, format_3h: packed struct { op: u2, - rd: u5, - op3: u6, - rs1: u5, + fixed1: u5 = 0b00000, + op3: u6 = 0b101000, + fixed2: u5 = 0b01111, i: u1 = 0b1, - reserved: u6, + reserved: u6 = 0b000000, cmask: u3, mmask: u4, }, @@ -462,12 +462,47 @@ pub const Instruction = union(enum) { eq_zero, le_zero, lt_zero, - reserved, + reserved2, ne_zero, gt_zero, ge_zero, }; + pub const ASI = enum(u8) { + asi_nucleus = 0x04, + asi_nucleus_little = 0x0c, + asi_as_if_user_primary = 0x10, + asi_as_if_user_secondary = 0x11, + asi_as_if_user_primary_little = 0x18, + asi_as_if_user_secondary_little = 0x19, + asi_primary = 0x80, + asi_secondary = 0x81, + asi_primary_nofault = 0x82, + asi_secondary_nofault = 0x83, + asi_primary_little = 0x88, + asi_secondary_little = 0x89, + asi_primary_nofault_little = 0x8a, + asi_secondary_nofault_little = 0x8b, + }; + + pub const ShiftWidth = enum(u1) { + Shift32, + Shift64, + }; + + pub const MemOrderingConstraint = packed struct { + store_store: bool = false, + load_store: bool = false, + store_load: bool = false, + load_load: bool = false, + }; + + pub const MemCompletionConstraint = packed struct { + sync: bool = false, + mem_issue: bool = false, + lookaside: bool = false, + }; + // TODO: Need to define an enum for `cond` values // This is kinda challenging since the cond values have different meanings // depending on whether it's operating on integer or FP CCR. @@ -483,9 +518,11 @@ pub const Instruction = union(enum) { // Discard the last two bits since those are implicitly zero. const udisp = @truncate(u30, @bitCast(u32, disp) >> 2); - return Instruction{ .format_1 = .{ - .disp30 = udisp, - } }; + return Instruction{ + .format_1 = .{ + .disp30 = udisp, + }, + }; } fn format2a(rd: Register, op2: u3, imm: i22) Instruction { @@ -558,6 +595,196 @@ pub const Instruction = union(enum) { }; } + fn format3a(rd: Register, op3: u6, rs1: Register, rs2: Register) Instruction { + return Instruction{ + .format_3a = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .rs2 = rs2.enc(), + }, + }; + } + fn format3b(rd: Register, op3: u6, rs1: Register, imm: i13) Instruction { + return Instruction{ + .format_3b = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .simm13 = @bitCast(u13, imm), + }, + }; + } + fn format3c(op3: u6, rs1: Register, rs2: Register) Instruction { + return Instruction{ + .format_3c = .{ + .op3 = op3, + .rs1 = rs1.enc(), + .rs2 = rs2.enc(), + }, + }; + } + fn format3d(op3: u6, rs1: Register, imm: i13) Instruction { + return Instruction{ + .format_3d = .{ + .op3 = op3, + .rs1 = rs1.enc(), + .simm13 = @bitCast(u13, imm), + }, + }; + } + fn format3e(rd: Register, op3: u6, rcond: RCondition, rs1: Register, rs2: Register) Instruction { + return Instruction{ + .format_3e = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .rcond = @enumToInt(rcond), + .rs2 = rs2.enc(), + }, + }; + } + fn format3f(rd: Register, op3: u6, rs1: Register, rcond: RCondition, imm: i10) Instruction { + return Instruction{ + .format_3f = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .rcond = @enumToInt(rcond), + .simm10 = @bitCast(u10, imm), + }, + }; + } + fn format3g(rd: Register, op3: u6, rs1: Register, rs2: Register) Instruction { + return Instruction{ + .format_3g = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .rs2 = rs2.enc(), + }, + }; + } + fn format3h(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction { + return Instruction{ + .format_3h = .{ + .cmask = @bitCast(u3, cmask), + .mmask = @bitCast(u4, mmask), + }, + }; + } + fn format3i(rd: Register, op3: u6, rs1: Register, rs2: Register, asi: ASI) Instruction { + return Instruction{ + .format_3i = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .imm_asi = @enumToInt(asi), + .rs2 = rs2.enc(), + }, + }; + } + fn format3j(op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction { + return Instruction{ + .format_3j = .{ + .impl_dep1 = impl_dep1, + .op3 = op3, + .impl_dep2 = impl_dep2, + }, + }; + } + fn format3k(rd: Register, op3: u6, rs1: Register, rs2: Register, sw: ShiftWidth) Instruction { + return Instruction{ + .format_3k = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .x = @enumToInt(sw), + .rs2 = rs2.enc(), + }, + }; + } + fn format3l(rd: Register, op3: u6, rs1: Register, shift_count: u5) Instruction { + return Instruction{ + .format_3l = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .shift_count = shift_count, + }, + }; + } + fn format3m(rd: Register, op3: u6, rs1: Register, shift_count: u6) Instruction { + return Instruction{ + .format_3m = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .shift_count = shift_count, + }, + }; + } + fn format3n(rd: Register, op3: u6, opf: u9, rs2: Register) Instruction { + return Instruction{ + .format_3n = .{ + .rd = rd.enc(), + .op3 = op3, + .opf = opf, + .rs2 = rs2.enc(), + }, + }; + } + fn format3o(cc: CCR, op3: u6, rs1: Register, opf: u9, rs2: Register) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + return Instruction{ + .format_3o = .{ + .cc1 = ccr_cc1, + .cc0 = ccr_cc0, + .op3 = op3, + .rs1 = rs1.enc(), + .opf = opf, + .rs2 = rs2.enc(), + }, + }; + } + fn format3p(rd: Register, op3: u6, rs1: Register, opf: u9, rs2: Register) Instruction { + return Instruction{ + .format_3p = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + .opf = opf, + .rs2 = rs2.enc(), + }, + }; + } + fn format3q(rd: Register, op3: u6, rs1: Register) Instruction { + return Instruction{ + .format_3q = .{ + .rd = rd.enc(), + .op3 = op3, + .rs1 = rs1.enc(), + }, + }; + } + fn format3r(fcn: u5, op3: u6) Instruction { + return Instruction{ + .format_3r = .{ + .fcn = fcn, + .op3 = op3, + }, + }; + } + fn format3s(rd: Register, op3: u6) Instruction { + return Instruction{ + .format_3s = .{ + .rd = rd.enc(), + .op3 = op3, + }, + }; + } + fn format4a(rd: Register, op3: u6, rs1: Register, cc: CCR, rs2: Register) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(cc)); From 56413360a1a853b612c115f898a746a02573198c Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 22:33:22 +0700 Subject: [PATCH 11/20] stage2 sparcv9: Reorder wrapper parameters to textual assembly order --- src/arch/sparcv9/bits.zig | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 621870b5e5..2c386ad694 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -525,7 +525,7 @@ pub const Instruction = union(enum) { }; } - fn format2a(rd: Register, op2: u3, imm: i22) Instruction { + fn format2a(op2: u3, rd: Register, imm: i22) Instruction { return Instruction{ .format_2a = .{ .rd = rd.enc(), @@ -535,7 +535,7 @@ pub const Instruction = union(enum) { }; } - fn format2b(annul: bool, cond: Condition, op2: u3, disp: i24) Instruction { + fn format2b(op2: u3, cond: Condition, annul: bool, disp: i24) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -551,7 +551,7 @@ pub const Instruction = union(enum) { }; } - fn format2c(annul: bool, cond: Condition, op2: u3, ccr: CCR, pt: bool, disp: i21) Instruction { + fn format2c(op2: u3, cond: Condition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -573,7 +573,7 @@ pub const Instruction = union(enum) { }; } - fn format2d(annul: bool, rcond: RCondition, op2: u3, pt: bool, rs1: Register, disp: i18) Instruction { + fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction { // In SPARC, branch target needs to be aligned to 4 bytes. assert(disp % 4 == 0); @@ -595,7 +595,7 @@ pub const Instruction = union(enum) { }; } - fn format3a(rd: Register, op3: u6, rs1: Register, rs2: Register) Instruction { + fn format3a(op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3a = .{ .rd = rd.enc(), @@ -605,7 +605,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3b(rd: Register, op3: u6, rs1: Register, imm: i13) Instruction { + fn format3b(op3: u6, rs1: Register, imm: i13, rd: Register) Instruction { return Instruction{ .format_3b = .{ .rd = rd.enc(), @@ -633,7 +633,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3e(rd: Register, op3: u6, rcond: RCondition, rs1: Register, rs2: Register) Instruction { + fn format3e(op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3e = .{ .rd = rd.enc(), @@ -644,7 +644,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3f(rd: Register, op3: u6, rs1: Register, rcond: RCondition, imm: i10) Instruction { + fn format3f(op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction { return Instruction{ .format_3f = .{ .rd = rd.enc(), @@ -655,7 +655,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3g(rd: Register, op3: u6, rs1: Register, rs2: Register) Instruction { + fn format3g(op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3g = .{ .rd = rd.enc(), @@ -673,7 +673,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3i(rd: Register, op3: u6, rs1: Register, rs2: Register, asi: ASI) Instruction { + fn format3i(op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction { return Instruction{ .format_3i = .{ .rd = rd.enc(), @@ -693,7 +693,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3k(rd: Register, op3: u6, rs1: Register, rs2: Register, sw: ShiftWidth) Instruction { + fn format3k(op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3k = .{ .rd = rd.enc(), @@ -704,7 +704,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3l(rd: Register, op3: u6, rs1: Register, shift_count: u5) Instruction { + fn format3l(op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction { return Instruction{ .format_3l = .{ .rd = rd.enc(), @@ -714,7 +714,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3m(rd: Register, op3: u6, rs1: Register, shift_count: u6) Instruction { + fn format3m(op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction { return Instruction{ .format_3m = .{ .rd = rd.enc(), @@ -724,7 +724,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3n(rd: Register, op3: u6, opf: u9, rs2: Register) Instruction { + fn format3n(op3: u6, opf: u9, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3n = .{ .rd = rd.enc(), @@ -734,7 +734,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3o(cc: CCR, op3: u6, rs1: Register, opf: u9, rs2: Register) Instruction { + fn format3o(op3: u6, opf: u9, cc: CCR, rs1: Register, rs2: Register) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(cc)); return Instruction{ @@ -748,7 +748,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3p(rd: Register, op3: u6, rs1: Register, opf: u9, rs2: Register) Instruction { + fn format3p(op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3p = .{ .rd = rd.enc(), @@ -759,7 +759,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3q(rd: Register, op3: u6, rs1: Register) Instruction { + fn format3q(op3: u6, rs1: Register, rd: Register) Instruction { return Instruction{ .format_3q = .{ .rd = rd.enc(), @@ -768,7 +768,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3r(fcn: u5, op3: u6) Instruction { + fn format3r(op3: u6, fcn: u5) Instruction { return Instruction{ .format_3r = .{ .fcn = fcn, @@ -776,7 +776,7 @@ pub const Instruction = union(enum) { }, }; } - fn format3s(rd: Register, op3: u6) Instruction { + fn format3s(op3: u6, rd: Register) Instruction { return Instruction{ .format_3s = .{ .rd = rd.enc(), From 1d4b9f44ed4bc2a7e30cee74372cb19b545a0aa4 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 22:35:06 +0700 Subject: [PATCH 12/20] stage2 sparcv9: cc -> ccr --- src/arch/sparcv9/bits.zig | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 2c386ad694..df3519dd20 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -734,9 +734,9 @@ pub const Instruction = union(enum) { }, }; } - fn format3o(op3: u6, opf: u9, cc: CCR, rs1: Register, rs2: Register) Instruction { - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format3o(op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format_3o = .{ .cc1 = ccr_cc1, @@ -785,9 +785,9 @@ pub const Instruction = union(enum) { }; } - fn format4a(rd: Register, op3: u6, rs1: Register, cc: CCR, rs2: Register) Instruction { - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format4a(rd: Register, op3: u6, rs1: Register, ccr: CCR, rs2: Register) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format4a = .{ .rd = rd.enc(), @@ -800,9 +800,9 @@ pub const Instruction = union(enum) { }; } - fn format4b(rd: Register, op3: u6, rs1: Register, cc: CCR, imm: i11) Instruction { - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format4b(rd: Register, op3: u6, rs1: Register, ccr: CCR, imm: i11) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format4b = .{ .rd = rd.enc(), @@ -815,10 +815,10 @@ pub const Instruction = union(enum) { }; } - fn format4c(rd: Register, op3: u6, cc: CCR, cond: Condition, rs2: Register) Instruction { - const ccr_cc2 = @truncate(u1, @enumToInt(cc) >> 2); - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format4c(rd: Register, op3: u6, ccr: CCR, cond: Condition, rs2: Register) Instruction { + const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format4c = .{ .rd = rd.enc(), @@ -832,10 +832,10 @@ pub const Instruction = union(enum) { }; } - fn format4d(rd: Register, op3: u6, cc: CCR, cond: Condition, imm: i11) Instruction { - const ccr_cc2 = @truncate(u1, @enumToInt(cc) >> 2); - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format4d(rd: Register, op3: u6, ccr: CCR, cond: Condition, imm: i11) Instruction { + const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format4d = .{ .rd = rd.enc(), @@ -849,9 +849,9 @@ pub const Instruction = union(enum) { }; } - fn format4e(rd: Register, op3: u6, rs1: Register, cc: CCR, sw_trap: u7) Instruction { - const ccr_cc1 = @truncate(u1, @enumToInt(cc) >> 1); - const ccr_cc0 = @truncate(u1, @enumToInt(cc)); + fn format4e(rd: Register, op3: u6, rs1: Register, ccr: CCR, sw_trap: u7) Instruction { + const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); + const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format4e = .{ .rd = rd.enc(), From d6a35500e5afdbd26c8af4263f2167eb27c1b7e9 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 14 Mar 2022 22:45:15 +0700 Subject: [PATCH 13/20] stage2 sparcv9: Reorder Format 4 wrappers too --- src/arch/sparcv9/bits.zig | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index df3519dd20..d43e2a540c 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -785,7 +785,7 @@ pub const Instruction = union(enum) { }; } - fn format4a(rd: Register, op3: u6, rs1: Register, ccr: CCR, rs2: Register) Instruction { + fn format4a(op3: u6, ccr: CCR, rs1: Register, rs2: Register, rd: Register) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ @@ -800,7 +800,7 @@ pub const Instruction = union(enum) { }; } - fn format4b(rd: Register, op3: u6, rs1: Register, ccr: CCR, imm: i11) Instruction { + fn format4b(op3: u6, ccr: CCR, rs1: Register, imm: i11, rd: Register) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ @@ -815,7 +815,7 @@ pub const Instruction = union(enum) { }; } - fn format4c(rd: Register, op3: u6, ccr: CCR, cond: Condition, rs2: Register) Instruction { + fn format4c(op3: u6, cond: Condition, ccr: CCR, rs2: Register, rd: Register) Instruction { const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); @@ -832,7 +832,7 @@ pub const Instruction = union(enum) { }; } - fn format4d(rd: Register, op3: u6, ccr: CCR, cond: Condition, imm: i11) Instruction { + fn format4d(op3: u6, cond: Condition, ccr: CCR, imm: i11, rd: Register) Instruction { const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2); const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); @@ -849,7 +849,7 @@ pub const Instruction = union(enum) { }; } - fn format4e(rd: Register, op3: u6, rs1: Register, ccr: CCR, sw_trap: u7) Instruction { + fn format4e(op3: u6, ccr: CCR, rs1: Register, rd: Register, sw_trap: u7) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ @@ -864,7 +864,14 @@ pub const Instruction = union(enum) { }; } - fn format4f(rd: Register, op3: u6, rs1: Register, rcond: RCondition, opf_low: u5, rs2: Register) Instruction { + fn format4f( + op3: u6, + opf_low: u5, + rcond: RCondition, + rs1: Register, + rs2: Register, + rd: Register, + ) Instruction { return Instruction{ .format4f = .{ .rd = rd.enc(), @@ -877,7 +884,7 @@ pub const Instruction = union(enum) { }; } - fn format4g(rd: Register, op3: u6, cond: Condition, opf_cc: u3, opf_low: u6, rs2: Register) Instruction { + fn format4g(op3: u6, opf_low: u6, opf_cc: u3, cond: Condition, rs2: Register, rd: Register) Instruction { return Instruction{ .format4g = .{ .rd = rd.enc(), From 1cea8b271e8c1e7888dc6102014ee69bf2fcbe47 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 16 Mar 2022 21:40:59 +0700 Subject: [PATCH 14/20] stage2 sparcv9: Add list of preserved regs --- src/arch/sparcv9/abi.zig | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/arch/sparcv9/abi.zig diff --git a/src/arch/sparcv9/abi.zig b/src/arch/sparcv9/abi.zig new file mode 100644 index 0000000000..94f66f52f5 --- /dev/null +++ b/src/arch/sparcv9/abi.zig @@ -0,0 +1,9 @@ +const bits = @import("bits.zig"); +const Register = bits.Register; + +// Register windowing mechanism will take care of preserving registers +// so no need to do it manually +pub const callee_preserved_regs = [_]Register{}; + +// pub const c_abi_int_param_regs = [_]Register{}; +// pub const c_abi_int_return_regs = [_]Register{}; From d9c33a610e2f081b6e8d64bfe34f6cb8be61a5b4 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 16 Mar 2022 22:30:48 +0700 Subject: [PATCH 15/20] stage2 sparcv9: Fix branch format asserts --- src/arch/sparcv9/bits.zig | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index d43e2a540c..90128de071 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -513,14 +513,16 @@ pub const Instruction = union(enum) { } fn format1(disp: i32) Instruction { + const udisp = @bitCast(u32, disp); + // In SPARC, branch target needs to be aligned to 4 bytes. - assert(disp % 4 == 0); + assert(udisp % 4 == 0); // Discard the last two bits since those are implicitly zero. - const udisp = @truncate(u30, @bitCast(u32, disp) >> 2); + const udisp_truncated = @truncate(u30, udisp >> 2); return Instruction{ .format_1 = .{ - .disp30 = udisp, + .disp30 = udisp_truncated, }, }; } @@ -536,27 +538,31 @@ pub const Instruction = union(enum) { } fn format2b(op2: u3, cond: Condition, annul: bool, disp: i24) Instruction { + const udisp = @bitCast(u24, disp); + // In SPARC, branch target needs to be aligned to 4 bytes. - assert(disp % 4 == 0); + assert(udisp % 4 == 0); // Discard the last two bits since those are implicitly zero. - const udisp = @truncate(u22, @bitCast(u24, disp) >> 2); + const udisp_truncated = @truncate(u22, udisp >> 2); return Instruction{ .format_2b = .{ .a = @boolToInt(annul), .cond = cond, .op2 = op2, - .disp22 = udisp, + .disp22 = udisp_truncated, }, }; } fn format2c(op2: u3, cond: Condition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction { + const udisp = @bitCast(u21, disp); + // In SPARC, branch target needs to be aligned to 4 bytes. - assert(disp % 4 == 0); + assert(udisp % 4 == 0); // Discard the last two bits since those are implicitly zero. - const udisp = @truncate(u19, @bitCast(u21, disp) >> 2); + const udisp_truncated = @truncate(u19, udisp >> 2); const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); @@ -568,18 +574,19 @@ pub const Instruction = union(enum) { .cc1 = ccr_cc1, .cc0 = ccr_cc0, .p = @boolToInt(pt), - .disp19 = udisp, + .disp19 = udisp_truncated, }, }; } fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction { + const udisp = @truncate(u16, @bitCast(u18, disp) >> 2); + // In SPARC, branch target needs to be aligned to 4 bytes. - assert(disp % 4 == 0); + assert(udisp % 4 == 0); // Discard the last two bits since those are implicitly zero, // and split it into low and high parts. - const udisp = @truncate(u16, @bitCast(u18, disp) >> 2); const udisp_hi = @truncate(u2, (udisp & 0b1100_0000_0000_0000) >> 14); const udisp_lo = @truncate(u14, udisp & 0b0011_1111_1111_1111); return Instruction{ From ac50ac699f675b581dc374762310ea2dfb3f7427 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 17 Mar 2022 01:47:17 +0700 Subject: [PATCH 16/20] stage2 sparcv9: Add encoder test and packed struct workaround --- src/arch/sparcv9/bits.zig | 281 ++++++++++++++++++++++++++++++++------ 1 file changed, 238 insertions(+), 43 deletions(-) diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 90128de071..eb75e50583 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -216,7 +216,7 @@ pub const Instruction = union(enum) { reserved: u8 = 0b00000000, rs2: u5, }, - format_3b: packed struct { + format_3b: struct { op: u2, rd: u5, op3: u6, @@ -233,7 +233,7 @@ pub const Instruction = union(enum) { reserved2: u8 = 0b00000000, rs2: u5, }, - format_3d: packed struct { + format_3d: struct { op: u2, reserved: u5 = 0b00000, op3: u6, @@ -251,7 +251,7 @@ pub const Instruction = union(enum) { reserved: u5 = 0b00000, rs2: u5, }, - format_3f: packed struct { + format_3f: struct { op: u2, rd: u5, op3: u6, @@ -270,7 +270,7 @@ pub const Instruction = union(enum) { rs2: u5, }, format_3h: packed struct { - op: u2, + op: u2 = 0b10, fixed1: u5 = 0b00000, op3: u6 = 0b101000, fixed2: u5 = 0b01111, @@ -336,8 +336,9 @@ pub const Instruction = union(enum) { op: u2, fixed: u3 = 0b000, cc1: u1, - cc0: i1, + cc0: u1, op3: u6, + rs1: u5, opf: u9, rs2: u5, }, @@ -381,7 +382,7 @@ pub const Instruction = union(enum) { reserved: u6 = 0b000000, rs2: u5, }, - format_4b: packed struct { + format_4b: struct { op: u2 = 0b10, rd: u5, op3: u6, @@ -403,7 +404,7 @@ pub const Instruction = union(enum) { reserved: u6 = 0b000000, rs2: u5, }, - format_4d: packed struct { + format_4d: struct { op: u2 = 0b10, rd: u5, op3: u6, @@ -486,8 +487,8 @@ pub const Instruction = union(enum) { }; pub const ShiftWidth = enum(u1) { - Shift32, - Shift64, + shift32, + shift64, }; pub const MemOrderingConstraint = packed struct { @@ -509,7 +510,40 @@ pub const Instruction = union(enum) { pub const Condition = u4; pub fn toU32(self: Instruction) u32 { - return @bitCast(u32, self); + // TODO: Remove this once packed structs work. + return switch (self) { + .format_1 => |v| @bitCast(u32, v), + .format_2a => |v| @bitCast(u32, v), + .format_2b => |v| @bitCast(u32, v), + .format_2c => |v| @bitCast(u32, v), + .format_2d => |v| @bitCast(u32, v), + .format_3a => |v| @bitCast(u32, v), + .format_3b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13), + .format_3c => |v| @bitCast(u32, v), + .format_3d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13), + .format_3e => |v| @bitCast(u32, v), + .format_3f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | @as(u32, v.simm10), + .format_3g => |v| @bitCast(u32, v), + .format_3h => |v| @bitCast(u32, v), + .format_3i => |v| @bitCast(u32, v), + .format_3j => |v| @bitCast(u32, v), + .format_3k => |v| @bitCast(u32, v), + .format_3l => |v| @bitCast(u32, v), + .format_3m => |v| @bitCast(u32, v), + .format_3n => |v| @bitCast(u32, v), + .format_3o => |v| @bitCast(u32, v), + .format_3p => |v| @bitCast(u32, v), + .format_3q => |v| @bitCast(u32, v), + .format_3r => |v| @bitCast(u32, v), + .format_3s => |v| @bitCast(u32, v), + .format_4a => |v| @bitCast(u32, v), + .format_4b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11), + .format_4c => |v| @bitCast(u32, v), + .format_4d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11), + .format_4e => |v| @bitCast(u32, v), + .format_4f => |v| @bitCast(u32, v), + .format_4g => |v| @bitCast(u32, v), + }; } fn format1(disp: i32) Instruction { @@ -527,12 +561,12 @@ pub const Instruction = union(enum) { }; } - fn format2a(op2: u3, rd: Register, imm: i22) Instruction { + fn format2a(op2: u3, rd: Register, imm: u22) Instruction { return Instruction{ .format_2a = .{ .rd = rd.enc(), .op2 = op2, - .imm22 = @bitCast(u22, imm), + .imm22 = imm, }, }; } @@ -580,17 +614,18 @@ pub const Instruction = union(enum) { } fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction { - const udisp = @truncate(u16, @bitCast(u18, disp) >> 2); + const udisp = @bitCast(u18, disp); // In SPARC, branch target needs to be aligned to 4 bytes. assert(udisp % 4 == 0); // Discard the last two bits since those are implicitly zero, // and split it into low and high parts. - const udisp_hi = @truncate(u2, (udisp & 0b1100_0000_0000_0000) >> 14); - const udisp_lo = @truncate(u14, udisp & 0b0011_1111_1111_1111); + const udisp_truncated = @truncate(u16, udisp >> 2); + const udisp_hi = @truncate(u2, (udisp_truncated & 0b1100_0000_0000_0000) >> 14); + const udisp_lo = @truncate(u14, udisp_truncated & 0b0011_1111_1111_1111); return Instruction{ - .format_2a = .{ + .format_2d = .{ .a = @boolToInt(annul), .rcond = @enumToInt(rcond), .op2 = op2, @@ -602,9 +637,10 @@ pub const Instruction = union(enum) { }; } - fn format3a(op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { + fn format3a(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3a = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -612,9 +648,10 @@ pub const Instruction = union(enum) { }, }; } - fn format3b(op3: u6, rs1: Register, imm: i13, rd: Register) Instruction { + fn format3b(op: u2, op3: u6, rs1: Register, imm: i13, rd: Register) Instruction { return Instruction{ .format_3b = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -622,27 +659,30 @@ pub const Instruction = union(enum) { }, }; } - fn format3c(op3: u6, rs1: Register, rs2: Register) Instruction { + fn format3c(op: u2, op3: u6, rs1: Register, rs2: Register) Instruction { return Instruction{ .format_3c = .{ + .op = op, .op3 = op3, .rs1 = rs1.enc(), .rs2 = rs2.enc(), }, }; } - fn format3d(op3: u6, rs1: Register, imm: i13) Instruction { + fn format3d(op: u2, op3: u6, rs1: Register, imm: i13) Instruction { return Instruction{ .format_3d = .{ + .op = op, .op3 = op3, .rs1 = rs1.enc(), .simm13 = @bitCast(u13, imm), }, }; } - fn format3e(op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction { + fn format3e(op: u2, op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3e = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -651,9 +691,10 @@ pub const Instruction = union(enum) { }, }; } - fn format3f(op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction { + fn format3f(op: u2, op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction { return Instruction{ .format_3f = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -662,9 +703,10 @@ pub const Instruction = union(enum) { }, }; } - fn format3g(op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { + fn format3g(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3g = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -680,9 +722,10 @@ pub const Instruction = union(enum) { }, }; } - fn format3i(op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction { + fn format3i(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction { return Instruction{ .format_3i = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -691,18 +734,20 @@ pub const Instruction = union(enum) { }, }; } - fn format3j(op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction { + fn format3j(op: u2, op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction { return Instruction{ .format_3j = .{ + .op = op, .impl_dep1 = impl_dep1, .op3 = op3, .impl_dep2 = impl_dep2, }, }; } - fn format3k(op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction { + fn format3k(op: u2, op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3k = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -711,29 +756,32 @@ pub const Instruction = union(enum) { }, }; } - fn format3l(op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction { + fn format3l(op: u2, op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction { return Instruction{ .format_3l = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), - .shift_count = shift_count, + .shcnt32 = shift_count, }, }; } - fn format3m(op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction { + fn format3m(op: u2, op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction { return Instruction{ .format_3m = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), - .shift_count = shift_count, + .shcnt64 = shift_count, }, }; } - fn format3n(op3: u6, opf: u9, rs2: Register, rd: Register) Instruction { + fn format3n(op: u2, op3: u6, opf: u9, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3n = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .opf = opf, @@ -741,11 +789,12 @@ pub const Instruction = union(enum) { }, }; } - fn format3o(op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction { + fn format3o(op: u2, op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ .format_3o = .{ + .op = op, .cc1 = ccr_cc1, .cc0 = ccr_cc0, .op3 = op3, @@ -755,9 +804,10 @@ pub const Instruction = union(enum) { }, }; } - fn format3p(op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction { + fn format3p(op: u2, op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction { return Instruction{ .format_3p = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -766,26 +816,29 @@ pub const Instruction = union(enum) { }, }; } - fn format3q(op3: u6, rs1: Register, rd: Register) Instruction { + fn format3q(op: u2, op3: u6, rs1: Register, rd: Register) Instruction { return Instruction{ .format_3q = .{ + .op = op, .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), }, }; } - fn format3r(op3: u6, fcn: u5) Instruction { + fn format3r(op: u2, op3: u6, fcn: u5) Instruction { return Instruction{ .format_3r = .{ + .op = op, .fcn = fcn, .op3 = op3, }, }; } - fn format3s(op3: u6, rd: Register) Instruction { + fn format3s(op: u2, op3: u6, rd: Register) Instruction { return Instruction{ .format_3s = .{ + .op = op, .rd = rd.enc(), .op3 = op3, }, @@ -796,7 +849,7 @@ pub const Instruction = union(enum) { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ - .format4a = .{ + .format_4a = .{ .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -811,7 +864,7 @@ pub const Instruction = union(enum) { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ - .format4b = .{ + .format_4b = .{ .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -827,7 +880,7 @@ pub const Instruction = union(enum) { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ - .format4c = .{ + .format_4c = .{ .rd = rd.enc(), .op3 = op3, .cc2 = ccr_cc2, @@ -844,7 +897,7 @@ pub const Instruction = union(enum) { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ - .format4d = .{ + .format_4d = .{ .rd = rd.enc(), .op3 = op3, .cc2 = ccr_cc2, @@ -860,7 +913,7 @@ pub const Instruction = union(enum) { const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1); const ccr_cc0 = @truncate(u1, @enumToInt(ccr)); return Instruction{ - .format4e = .{ + .format_4e = .{ .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -880,7 +933,7 @@ pub const Instruction = union(enum) { rd: Register, ) Instruction { return Instruction{ - .format4f = .{ + .format_4f = .{ .rd = rd.enc(), .op3 = op3, .rs1 = rs1.enc(), @@ -893,7 +946,7 @@ pub const Instruction = union(enum) { fn format4g(op3: u6, opf_low: u6, opf_cc: u3, cond: Condition, rs2: Register, rd: Register) Instruction { return Instruction{ - .format4g = .{ + .format_4g = .{ .rd = rd.enc(), .op3 = op3, .cond = cond, @@ -904,3 +957,145 @@ pub const Instruction = union(enum) { }; } }; + +test "Serialize formats" { + const Testcase = struct { + inst: Instruction, + expected: u32, + }; + + // Note that the testcases might or might not be a valid instruction + // This is mostly just to check the behavior of the format packed structs + // since currently stage1 doesn't properly implement it in all cases + const testcases = [_]Testcase{ + .{ + .inst = Instruction.format1(4), + .expected = 0b01_000000000000000000000000000001, + }, + .{ + .inst = Instruction.format2a(4, .g0, 0), + .expected = 0b00_00000_100_0000000000000000000000, + }, + .{ + .inst = Instruction.format2b(6, 3, true, -4), + .expected = 0b00_1_0011_110_1111111111111111111111, + }, + .{ + .inst = Instruction.format2c(3, 0, false, true, .xcc, 8), + .expected = 0b00_0_0000_011_1_0_1_0000000000000000010, + }, + .{ + .inst = Instruction.format2d(7, .eq_zero, false, true, .o0, 20), + .expected = 0b00_0_0_001_111_00_1_01000_00000000000101, + }, + .{ + .inst = Instruction.format3a(3, 5, .g0, .o1, .l2), + .expected = 0b11_10010_000101_00000_0_00000000_01001, + }, + .{ + .inst = Instruction.format3b(3, 5, .g0, -1, .l2), + .expected = 0b11_10010_000101_00000_1_1111111111111, + }, + .{ + .inst = Instruction.format3c(3, 5, .g0, .o1), + .expected = 0b11_00000_000101_00000_0_00000000_01001, + }, + .{ + .inst = Instruction.format3d(3, 5, .g0, 0), + .expected = 0b11_00000_000101_00000_1_0000000000000, + }, + .{ + .inst = Instruction.format3e(3, 5, .ne_zero, .g0, .o1, .l2), + .expected = 0b11_10010_000101_00000_0_101_00000_01001, + }, + .{ + .inst = Instruction.format3f(3, 5, .ne_zero, .g0, -1, .l2), + .expected = 0b11_10010_000101_00000_1_101_1111111111, + }, + .{ + .inst = Instruction.format3g(3, 5, .g0, .o1, .l2), + .expected = 0b11_10010_000101_00000_1_00000000_01001, + }, + .{ + .inst = Instruction.format3h(.{}, .{}), + .expected = 0b10_00000_101000_01111_1_000000_000_0000, + }, + .{ + .inst = Instruction.format3i(3, 5, .g0, .o1, .l2, .asi_primary_little), + .expected = 0b11_10010_000101_00000_0_10001000_01001, + }, + .{ + .inst = Instruction.format3j(3, 5, 31, 0), + .expected = 0b11_11111_000101_0000000000000000000, + }, + .{ + .inst = Instruction.format3k(3, 5, .shift32, .g0, .o1, .l2), + .expected = 0b11_10010_000101_00000_0_0_0000000_01001, + }, + .{ + .inst = Instruction.format3l(3, 5, .g0, 31, .l2), + .expected = 0b11_10010_000101_00000_1_0_0000000_11111, + }, + .{ + .inst = Instruction.format3m(3, 5, .g0, 63, .l2), + .expected = 0b11_10010_000101_00000_1_1_000000_111111, + }, + .{ + .inst = Instruction.format3n(3, 5, 0, .o1, .l2), + .expected = 0b11_10010_000101_00000_000000000_01001, + }, + .{ + .inst = Instruction.format3o(3, 5, 0, .xcc, .o1, .l2), + .expected = 0b11_000_1_0_000101_01001_000000000_10010, + }, + .{ + .inst = Instruction.format3p(3, 5, 0, .g0, .o1, .l2), + .expected = 0b11_10010_000101_00000_000000000_01001, + }, + .{ + .inst = Instruction.format3q(3, 5, .g0, .o1), + .expected = 0b11_01001_000101_00000_00000000000000, + }, + .{ + .inst = Instruction.format3r(3, 5, 4), + .expected = 0b11_00100_000101_0000000000000000000, + }, + .{ + .inst = Instruction.format3s(3, 5, .g0), + .expected = 0b11_00000_000101_0000000000000000000, + }, + .{ + .inst = Instruction.format4a(8, .xcc, .g0, .o1, .l2), + .expected = 0b10_10010_001000_00000_0_1_0_000000_01001, + }, + .{ + .inst = Instruction.format4b(8, .xcc, .g0, -1, .l2), + .expected = 0b10_10010_001000_00000_1_1_0_11111111111, + }, + .{ + .inst = Instruction.format4c(8, 0, .xcc, .g0, .o1), + .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000, + }, + .{ + .inst = Instruction.format4d(8, 0, .xcc, 0, .l2), + .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000 + }, + .{ + .inst = Instruction.format4e(8, .xcc, .g0, .o1, 0), + .expected = 0b10_01001_001000_00000_1_1_0_0000_0000000, + }, + .{ + .inst = Instruction.format4f(8, 4, .eq_zero, .g0, .o1, .l2), + .expected = 0b10_10010_001000_00000_0_001_00100_01001, + }, + .{ + .inst = Instruction.format4g(8, 4, 2, 0, .o1, .l2), + .expected = 0b10_10010_001000_0_0000_010_000100_01001, + }, + }; + + for (testcases) |case| { + const actual = case.inst.toU32(); + try testing.expectEqual(case.expected, actual); + } +} From 7579f14e0fff29e6486aef1f5c34d2fcd61cc108 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 17 Mar 2022 02:24:21 +0700 Subject: [PATCH 17/20] stage2 sparcv9: Add param/return regs list --- src/arch/sparcv9/abi.zig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/arch/sparcv9/abi.zig b/src/arch/sparcv9/abi.zig index 94f66f52f5..90b565adc1 100644 --- a/src/arch/sparcv9/abi.zig +++ b/src/arch/sparcv9/abi.zig @@ -5,5 +5,8 @@ const Register = bits.Register; // so no need to do it manually pub const callee_preserved_regs = [_]Register{}; -// pub const c_abi_int_param_regs = [_]Register{}; -// pub const c_abi_int_return_regs = [_]Register{}; +pub const c_abi_int_param_regs_caller_view = [_]Register{.o0, .o1, .o2, .o3, .o4, .o5}; +pub const c_abi_int_param_regs_callee_view = [_]Register{.@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5"}; + +pub const c_abi_int_return_regs_caller_view = [_]Register{.o0, .o1, .o2, .o3, .o4, .o5}; +pub const c_abi_int_return_regs_callee_view = [_]Register{.@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5"}; From 93b16de4b4dc25a9e2fe076a5a992a85afc51ade Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 19 Mar 2022 06:09:46 +0700 Subject: [PATCH 18/20] stage2 sparcv9: Add placeholder files and generate() function Add placeholder files for Codegen, Emit, and Mir stages, complete with a placeholder implementation of generate() to make it able to be plugged in to the frontend. At the moment the implementation just panics, it'll be worked on incrementally later. Also, this registers the sparcv9 backend files into CMakeLists.txt. --- CMakeLists.txt | 5 +++++ src/arch/sparcv9/CodeGen.zig | 31 +++++++++++++++++++++++++++++++ src/arch/sparcv9/Emit.zig | 6 ++++++ src/arch/sparcv9/Mir.zig | 11 +++++++++++ src/codegen.zig | 2 +- 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/arch/sparcv9/CodeGen.zig create mode 100644 src/arch/sparcv9/Emit.zig create mode 100644 src/arch/sparcv9/Mir.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 457c5297cb..646893b533 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -609,6 +609,11 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig" "${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig" "${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig" + "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/CodeGen.zig" + "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/Emit.zig" + "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/Mir.zig" + "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/bits.zig" + "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/abi.zig" "${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig" "${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig" "${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig" diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig new file mode 100644 index 0000000000..aa594d9f54 --- /dev/null +++ b/src/arch/sparcv9/CodeGen.zig @@ -0,0 +1,31 @@ +//! SPARCv9 codegen. +//! This lowers AIR into MIR. +const std = @import("std"); +const builtin = @import("builtin"); +const link = @import("../../link.zig"); +const Module = @import("../../Module.zig"); +const Air = @import("../../Air.zig"); +const Mir = @import("Mir.zig"); +const Emit = @import("Emit.zig"); +const Liveness = @import("../../Liveness.zig"); + +const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; +const FnResult = @import("../../codegen.zig").FnResult; +const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; + +const bits = @import("bits.zig"); +const abi = @import("abi.zig"); + +const Self = @This(); + +pub fn generate( + bin_file: *link.File, + src_loc: Module.SrcLoc, + module_fn: *Module.Fn, + air: Air, + liveness: Liveness, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) GenerateSymbolError!FnResult { + @panic("TODO implement SPARCv9 codegen"); +} diff --git a/src/arch/sparcv9/Emit.zig b/src/arch/sparcv9/Emit.zig new file mode 100644 index 0000000000..ba644ede7e --- /dev/null +++ b/src/arch/sparcv9/Emit.zig @@ -0,0 +1,6 @@ +//! This file contains the functionality for lowering SPARCv9 MIR into +//! machine code + +const Emit = @This(); +const Mir = @import("Mir.zig"); +const bits = @import("bits.zig"); diff --git a/src/arch/sparcv9/Mir.zig b/src/arch/sparcv9/Mir.zig new file mode 100644 index 0000000000..f0d3b1dfbd --- /dev/null +++ b/src/arch/sparcv9/Mir.zig @@ -0,0 +1,11 @@ +//! Machine Intermediate Representation. +//! This data is produced by SPARCv9 Codegen or SPARCv9 assembly parsing +//! These instructions have a 1:1 correspondence with machine code instructions +//! for the target. MIR can be lowered to source-annotated textual assembly code +//! instructions, or it can be lowered to machine code. +//! The main purpose of MIR is to postpone the assignment of offsets until Isel, +//! so that, for example, the smaller encodings of jump instructions can be used. + +const Mir = @This(); +const bits = @import("bits.zig"); +const Register = bits.Register; diff --git a/src/codegen.zig b/src/codegen.zig index 6d5e140dca..0558c9c4f4 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -108,7 +108,7 @@ pub fn generateFunction( //.riscv32 => return Function(.riscv32).generate(bin_file, src_loc, func, air, liveness, code, debug_output), .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), //.sparc => return Function(.sparc).generate(bin_file, src_loc, func, air, liveness, code, debug_output), - //.sparcv9 => return Function(.sparcv9).generate(bin_file, src_loc, func, air, liveness, code, debug_output), + .sparcv9 => return @import("arch/sparcv9/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), //.sparcel => return Function(.sparcel).generate(bin_file, src_loc, func, air, liveness, code, debug_output), //.s390x => return Function(.s390x).generate(bin_file, src_loc, func, air, liveness, code, debug_output), //.tce => return Function(.tce).generate(bin_file, src_loc, func, air, liveness, code, debug_output), From 59680b40a123472428db75410ec6d9c375313b45 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 19 Mar 2022 06:58:50 +0700 Subject: [PATCH 19/20] stage2 sparcv9: Fix unused parameter errors in Codegen --- src/arch/sparcv9/CodeGen.zig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig index aa594d9f54..db5811dfda 100644 --- a/src/arch/sparcv9/CodeGen.zig +++ b/src/arch/sparcv9/CodeGen.zig @@ -27,5 +27,13 @@ pub fn generate( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, ) GenerateSymbolError!FnResult { + _ = bin_file; + _ = src_loc; + _ = module_fn; + _ = air; + _ = liveness; + _ = code; + _ = debug_output; + @panic("TODO implement SPARCv9 codegen"); } From 731dda18dde439631ed93afb0c0a199dc8842726 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 19 Mar 2022 09:06:58 +0700 Subject: [PATCH 20/20] stage2 sparcv9: zig fmt --- src/arch/sparcv9/abi.zig | 8 ++++---- src/arch/sparcv9/bits.zig | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/arch/sparcv9/abi.zig b/src/arch/sparcv9/abi.zig index 90b565adc1..5c9ea979fc 100644 --- a/src/arch/sparcv9/abi.zig +++ b/src/arch/sparcv9/abi.zig @@ -5,8 +5,8 @@ const Register = bits.Register; // so no need to do it manually pub const callee_preserved_regs = [_]Register{}; -pub const c_abi_int_param_regs_caller_view = [_]Register{.o0, .o1, .o2, .o3, .o4, .o5}; -pub const c_abi_int_param_regs_callee_view = [_]Register{.@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5"}; +pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 }; +pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" }; -pub const c_abi_int_return_regs_caller_view = [_]Register{.o0, .o1, .o2, .o3, .o4, .o5}; -pub const c_abi_int_return_regs_callee_view = [_]Register{.@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5"}; +pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 }; +pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" }; diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index eb75e50583..07cbf7fc91 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -1078,7 +1078,7 @@ test "Serialize formats" { }, .{ .inst = Instruction.format4d(8, 0, .xcc, 0, .l2), - .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000 + .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000, }, .{ .inst = Instruction.format4e(8, .xcc, .g0, .o1, 0),