From ac50ac699f675b581dc374762310ea2dfb3f7427 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 17 Mar 2022 01:47:17 +0700 Subject: [PATCH] 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); + } +}