| ... | @@ -0,0 +1,120 @@ |
| 1 | const std = @import("std"); |
| 2 | const mem = std.mem; |
| 3 | const io = std.io; |
| 4 | const fs = std.fs; |
| 5 | const fmt = std.fmt; |
| 6 | const testing = std.testing; |
| 7 | |
| 8 | const Target = std.Target; |
| 9 | const CrossTarget = std.zig.CrossTarget; |
| 10 | |
| 11 | const assert = std.debug.assert; |
| 12 | |
| 13 | const SparcCpuinfoImpl = struct { |
| 14 | model: ?*const Target.Cpu.Model = null, |
| 15 | is_64bit: bool = false, |
| 16 | |
| 17 | const cpu_names = .{ |
| 18 | .{ "SuperSparc", &Target.sparc.cpu.supersparc }, |
| 19 | .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, |
| 20 | .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, |
| 21 | .{ "BlackBird", &Target.sparc.cpu.ultrasparc }, |
| 22 | .{ "Sabre", &Target.sparc.cpu.ultrasparc }, |
| 23 | .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, |
| 24 | .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 }, |
| 25 | .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, |
| 26 | .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 }, |
| 27 | .{ "Panther", &Target.sparc.cpu.ultrasparc3 }, |
| 28 | .{ "Serrano", &Target.sparc.cpu.ultrasparc3 }, |
| 29 | .{ "UltraSparc T1", &Target.sparc.cpu.niagara }, |
| 30 | .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 }, |
| 31 | .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 }, |
| 32 | .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 }, |
| 33 | .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 }, |
| 34 | .{ "LEON", &Target.sparc.cpu.leon3 }, |
| 35 | }; |
| 36 | |
| 37 | fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool { |
| 38 | if (mem.eql(u8, key, "cpu")) { |
| 39 | inline for (cpu_names) |pair| { |
| 40 | if (mem.indexOfPos(u8, value, 0, pair[0]) != null) { |
| 41 | self.model = pair[1]; |
| 42 | break; |
| 43 | } |
| 44 | } |
| 45 | } else if (mem.eql(u8, key, "type")) { |
| 46 | self.is_64bit = mem.eql(u8, value, "sun4u") or mem.eql(u8, value, "sun4v"); |
| 47 | } |
| 48 | |
| 49 | return true; |
| 50 | } |
| 51 | |
| 52 | fn finalize(self: *const SparcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { |
| 53 | // At the moment we only support 64bit SPARC systems. |
| 54 | assert(self.is_64bit); |
| 55 | |
| 56 | const model = self.model orelse Target.Cpu.Model.generic(arch); |
| 57 | return Target.Cpu{ |
| 58 | .arch = arch, |
| 59 | .model = model, |
| 60 | .features = model.features, |
| 61 | }; |
| 62 | } |
| 63 | }; |
| 64 | |
| 65 | const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl); |
| 66 | |
| 67 | test "cpuinfo: SPARC" { |
| 68 | const mock_cpuinfo = |
| 69 | \\cpu : UltraSparc T2 (Niagara2) |
| 70 | \\fpu : UltraSparc T2 integrated FPU |
| 71 | \\pmu : niagara2 |
| 72 | \\type : sun4v |
| 73 | ; |
| 74 | |
| 75 | var fbs = io.fixedBufferStream(mock_cpuinfo); |
| 76 | |
| 77 | const r = SparcCpuinfoParser.parse(.sparcv9, fbs.reader()) catch unreachable; |
| 78 | testing.expectEqual(&Target.sparc.cpu.niagara2, r.?.model); |
| 79 | testing.expect(Target.sparc.cpu.niagara2.features.eql(r.?.features)); |
| 80 | } |
| 81 | |
| 82 | // The generic implementation of a /proc/cpuinfo parser. |
| 83 | // For every line it invokes the line_hook method with the key and value strings |
| 84 | // as first and second parameters. Returning false from the hook function stops |
| 85 | // the iteration without raising an error. |
| 86 | // When all the lines have been analyzed the finalize method is called. |
| 87 | fn CpuinfoParser(comptime impl: anytype) type { |
| 88 | return struct { |
| 89 | fn parse(arch: Target.Cpu.Arch, reader: anytype) anyerror!?Target.Cpu { |
| 90 | var line_buf: [1024]u8 = undefined; |
| 91 | var obj: impl = .{}; |
| 92 | |
| 93 | while (true) { |
| 94 | const line = (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) orelse break; |
| 95 | const colon_pos = mem.indexOfScalar(u8, line, ':') orelse continue; |
| 96 | const key = mem.trimRight(u8, line[0..colon_pos], " \t"); |
| 97 | const value = mem.trimLeft(u8, line[colon_pos + 1 ..], " \t"); |
| 98 | |
| 99 | if (!try obj.line_hook(key, value)) |
| 100 | break; |
| 101 | } |
| 102 | |
| 103 | return obj.finalize(arch); |
| 104 | } |
| 105 | }; |
| 106 | } |
| 107 | |
| 108 | pub fn detectNativeCpuAndFeatures() ?Target.Cpu { |
| 109 | var f = fs.openFileAbsolute("/proc/cpuinfo", .{ .intended_io_mode = .blocking }) catch |err| switch (err) { |
| 110 | else => return null, |
| 111 | }; |
| 112 | defer f.close(); |
| 113 | |
| 114 | switch (std.Target.current.cpu.arch) { |
| 115 | .sparcv9 => return SparcCpuinfoParser.parse(.sparcv9, f.reader()) catch null, |
| 116 | else => {}, |
| 117 | } |
| 118 | |
| 119 | return null; |
| 120 | } |