Commit ac50ac699f

Koakuma <koachan@protonmail.com>
2022-03-16 19:47:17
stage2 sparcv9: Add encoder test and packed struct workaround
1 parent d9c33a6
Changed files (1)
src
arch
sparcv9
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);
+    }
+}