// ported from: https://gitlab.com/leogx9r/ryzen_smu // and: https://github.com/irusanov/SMUDebugTool using System; using System.Collections.Generic; using System.Text; using System.Threading; // ReSharper disable InconsistentNaming namespace LibreHardwareMonitor.Hardware; internal class RyzenSMU { private const byte SMU_PCI_ADDR_REG = 0xC4; private const byte SMU_PCI_DATA_REG = 0xC8; private const uint SMU_REQ_MAX_ARGS = 6; private const uint SMU_RETRIES_MAX = 8096; private readonly CpuCodeName _cpuCodeName; private readonly bool _supportedCPU; private readonly Dictionary> _supportedPmTableVersions = new() { { // Zen Raven Ridge APU. 0x001E0004, new Dictionary { { 7, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, { 11, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, //{ 61, new SmuSensorType { Name = "Core", Type = SensorType.Voltage } }, //{ 62, new SmuSensorType { Name = "Core", Type = SensorType.Current, Scale = 1} }, //{ 63, new SmuSensorType { Name = "Core", Type = SensorType.Power, Scale = 1 } }, //{ 65, new SmuSensorType { Name = "SoC", Type = SensorType.Voltage } }, { 66, new SmuSensorType { Name = "SoC", Type = SensorType.Current, Scale = 1 } }, { 67, new SmuSensorType { Name = "SoC", Type = SensorType.Power, Scale = 1 } }, //{ 96, new SmuSensorType { Name = "Core #1", Type = SensorType.Power } }, //{ 97, new SmuSensorType { Name = "Core #2", Type = SensorType.Power } }, //{ 98, new SmuSensorType { Name = "Core #3", Type = SensorType.Power } }, //{ 99, new SmuSensorType { Name = "Core #4", Type = SensorType.Power } }, { 108, new SmuSensorType { Name = "Core #1", Type = SensorType.Temperature, Scale = 1 } }, { 109, new SmuSensorType { Name = "Core #2", Type = SensorType.Temperature, Scale = 1 } }, { 110, new SmuSensorType { Name = "Core #3", Type = SensorType.Temperature, Scale = 1 } }, { 111, new SmuSensorType { Name = "Core #4", Type = SensorType.Temperature, Scale = 1 } }, { 150, new SmuSensorType { Name = "GFX", Type = SensorType.Voltage, Scale = 1 } }, { 151, new SmuSensorType { Name = "GFX", Type = SensorType.Temperature, Scale = 1 } }, { 154, new SmuSensorType { Name = "GFX", Type = SensorType.Clock, Scale = 1 } }, { 156, new SmuSensorType { Name = "GFX", Type = SensorType.Load, Scale = 1 } }, { 166, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, { 177, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, { 178, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, { 342, new SmuSensorType { Name = "Displays", Type = SensorType.Factor, Scale = 1 } } } }, { // Zen 2. 0x00240903, new Dictionary { { 15, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, { 21, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, { 115, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } } //{ 66, new SmuSensorType { Name = "Bus Speed", Type = SensorType.Clock, Scale = 1 } }, //{ 188, new SmuSensorType { Name = "Core #1", Type = SensorType.Clock, Scale = 1000 } }, //{ 189, new SmuSensorType { Name = "Core #2", Type = SensorType.Clock, Scale = 1000 } }, //{ 190, new SmuSensorType { Name = "Core #3", Type = SensorType.Clock, Scale = 1000 } }, //{ 191, new SmuSensorType { Name = "Core #4", Type = SensorType.Clock, Scale = 1000 } }, //{ 192, new SmuSensorType { Name = "Core #5", Type = SensorType.Clock, Scale = 1000 } }, //{ 193, new SmuSensorType { Name = "Core #6", Type = SensorType.Clock, Scale = 1000 } }, } }, { // Zen 3. 0x00380805, new Dictionary { { 3, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, // TODO: requires some post-processing // see: https://gitlab.com/leogx9r/ryzen_smu/-/blob/master/userspace/monitor_cpu.c#L577 // { 9, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, { 127, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } }, { 268, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 269, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 270, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 271, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 272, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 273, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 274, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 275, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 276, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 277, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 278, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 279, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 280, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 281, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 282, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, { 283, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } } } }, { // Zen 4. 0x00540004, new Dictionary { { 3, new SmuSensorType { Name = "CPU PPT", Type = SensorType.Power, Scale = 1 } }, { 11, new SmuSensorType { Name = "Package", Type = SensorType.Temperature, Scale = 1 } }, { 20, new SmuSensorType { Name = "Core Power", Type = SensorType.Power, Scale = 1 } }, { 21, new SmuSensorType { Name = "SOC Power", Type = SensorType.Power, Scale = 1 } }, { 22, new SmuSensorType { Name = "Misc Power", Type = SensorType.Power, Scale = 1 } }, { 26, new SmuSensorType { Name = "Total Power", Type = SensorType.Power, Scale = 1 } }, { 47, new SmuSensorType { Name = "VDDCR", Type = SensorType.Voltage, Scale = 1 } }, { 48, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, { 49, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, { 52, new SmuSensorType { Name = "VDDCR SoC", Type = SensorType.Voltage, Scale = 1 } }, { 57, new SmuSensorType { Name = "VDD Misc", Type = SensorType.Voltage, Scale = 1 } }, { 70, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, { 74, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, { 78, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, { 211, new SmuSensorType { Name = "IOD Hotspot", Type = SensorType.Temperature, Scale = 1 } }, { 539, new SmuSensorType { Name = "L3 (CCD1)", Type = SensorType.Temperature, Scale = 1 } }, { 540, new SmuSensorType { Name = "L3 (CCD2)", Type = SensorType.Temperature, Scale = 1 } }, { 268, new SmuSensorType { Name = "LDO VDD", Type = SensorType.Voltage, Scale = 1 } }, // This is not working, some cores can be deactivated with the core disabled map. // When Core 2 is disabled and Core 3 is enabled, the name of Core 3 == "Core 2". //{ 357, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 358, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 359, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 360, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 361, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 362, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 363, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 364, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 365, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 366, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 367, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 368, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 369, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 370, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 371, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, //{ 372, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } } } } }; private uint _argsAddr; private uint _cmdAddr; private uint _dramAddrHi; private uint _dramBaseAddr; private uint _pmTableSize; private uint _pmTableSizeAlt; private uint _pmTableVersion; private uint _rspAddr; public RyzenSMU(uint family, uint model, uint packageType) { _cpuCodeName = GetCpuCodeName(family, model, packageType); _supportedCPU = Environment.Is64BitOperatingSystem == Environment.Is64BitProcess && SetAddresses(_cpuCodeName); if (_supportedCPU && InpOut.Open()) SetupPmTableAddrAndSize(); } private static CpuCodeName GetCpuCodeName(uint family, uint model, uint packageType) { return family switch { 0x17 => model switch { 0x01 => packageType == 7 ? CpuCodeName.Threadripper : CpuCodeName.SummitRidge, 0x08 => packageType == 7 ? CpuCodeName.Colfax : CpuCodeName.PinnacleRidge, 0x11 => CpuCodeName.RavenRidge, 0x18 => packageType == 2 ? CpuCodeName.RavenRidge2 : CpuCodeName.Picasso, 0x20 => CpuCodeName.Dali, 0x31 => CpuCodeName.CastlePeak, 0x60 => CpuCodeName.Renoir, 0x71 => CpuCodeName.Matisse, 0x90 => CpuCodeName.Vangogh, _ => CpuCodeName.Undefined }, 0x19 => model switch { 0x00 => CpuCodeName.Milan, 0x20 or 0x21 => CpuCodeName.Vermeer, 0x40 => CpuCodeName.Rembrandt, 0x50 => CpuCodeName.Cezanne, 0x61 => CpuCodeName.Raphael, _ => CpuCodeName.Undefined }, 0x1A => model switch { 0x44 => CpuCodeName.GraniteRidge, _ => CpuCodeName.Undefined }, _ => CpuCodeName.Undefined }; } public string GetReport() { StringBuilder r = new(); r.AppendLine("Ryzen SMU"); r.AppendLine(); r.AppendLine($" PM table version: 0x{_pmTableVersion:X8}"); r.AppendLine($" PM table supported: {_supportedCPU}"); r.AppendLine($" PM table layout defined: {IsPmTableLayoutDefined()}"); if (_supportedCPU) { r.AppendLine($" PM table size: 0x{_pmTableSize:X3}"); r.AppendLine($" PM table start address: 0x{_dramBaseAddr:X8}"); r.AppendLine(); r.AppendLine(" PM table dump:"); r.AppendLine(" Idx Offset Value"); r.AppendLine(" ------------------------"); float[] pm_values = GetPmTable(); for (int i = 0; i < pm_values.Length; i++) { r.AppendLine($" {i,4} 0x{i * 4:X3} {pm_values[i]}"); } } return r.ToString(); } private bool SetAddresses(CpuCodeName codeName) { switch (codeName) { case CpuCodeName.CastlePeak: case CpuCodeName.Matisse: case CpuCodeName.Vermeer: case CpuCodeName.Raphael: case CpuCodeName.GraniteRidge: _cmdAddr = 0x3B10524; _rspAddr = 0x3B10570; _argsAddr = 0x3B10A40; return true; case CpuCodeName.Colfax: case CpuCodeName.SummitRidge: case CpuCodeName.Threadripper: case CpuCodeName.PinnacleRidge: _cmdAddr = 0x3B1051C; _rspAddr = 0x3B10568; _argsAddr = 0x3B10590; return true; case CpuCodeName.Renoir: case CpuCodeName.Picasso: case CpuCodeName.RavenRidge: case CpuCodeName.RavenRidge2: case CpuCodeName.Dali: _cmdAddr = 0x3B10A20; _rspAddr = 0x3B10A80; _argsAddr = 0x3B10A88; return true; default: return false; } } public uint GetSmuVersion() { uint[] args = [1]; return SendCommand(0x02, ref args) ? args[0] : 0; } public Dictionary GetPmTableStructure() { if (!IsPmTableLayoutDefined()) return new Dictionary(); return _supportedPmTableVersions[_pmTableVersion]; } public bool IsPmTableLayoutDefined() { return _supportedPmTableVersions.ContainsKey(_pmTableVersion); } public float[] GetPmTable() { if (!_supportedCPU || !TransferTableToDram()) return [0]; float[] table = ReadDramToArray(); // Fix for Zen+ empty values on first call. if (table.Length == 0 || table[0] == 0) { Thread.Sleep(10); TransferTableToDram(); table = ReadDramToArray(); } return table; } private float[] ReadDramToArray() { float[] table = new float[_pmTableSize / 4]; IntPtr pMemory = Environment.Is64BitProcess ? new IntPtr(_dramBaseAddr | (long)_dramAddrHi << 32) : new IntPtr(_dramBaseAddr); byte[] bytes = InpOut.ReadMemory(pMemory, _pmTableSize); if (bytes != null) Buffer.BlockCopy(bytes, 0, table, 0, bytes.Length); return table; } private bool SetupPmTableAddrAndSize() { if (_pmTableSize == 0) SetupPmTableSize(); if (_dramBaseAddr == 0) SetupDramBaseAddr(); return _dramBaseAddr != 0 && _pmTableSize != 0; } private void SetupPmTableSize() { if (!GetPmTableVersion(ref _pmTableVersion)) return; switch (_cpuCodeName) { case CpuCodeName.Matisse: switch (_pmTableVersion) { case 0x240902: _pmTableSize = 0x514; break; case 0x240903: _pmTableSize = 0x518; break; case 0x240802: _pmTableSize = 0x7E0; break; case 0x240803: _pmTableSize = 0x7E4; break; default: return; } break; case CpuCodeName.Vermeer: switch (_pmTableVersion) { case 0x2D0903: _pmTableSize = 0x594; break; case 0x380904: _pmTableSize = 0x5A4; break; case 0x380905: _pmTableSize = 0x5D0; break; case 0x2D0803: _pmTableSize = 0x894; break; case 0x380804: _pmTableSize = 0x8A4; break; case 0x380805: _pmTableSize = 0x8F0; break; default: return; } break; case CpuCodeName.Renoir: switch (_pmTableVersion) { case 0x370000: _pmTableSize = 0x794; break; case 0x370001: _pmTableSize = 0x884; break; case 0x370002: case 0x370003: _pmTableSize = 0x88C; break; case 0x370004: _pmTableSize = 0x8AC; break; case 0x370005: _pmTableSize = 0x8C8; break; default: return; } break; case CpuCodeName.Cezanne: switch (_pmTableVersion) { case 0x400005: _pmTableSize = 0x944; break; default: return; } break; case CpuCodeName.Picasso: case CpuCodeName.RavenRidge: case CpuCodeName.RavenRidge2: _pmTableSizeAlt = 0xA4; _pmTableSize = 0x608 + _pmTableSizeAlt; break; case CpuCodeName.Raphael: case CpuCodeName.GraniteRidge: switch (_pmTableVersion) { case 0x00540004: _pmTableSize = 0x948; break; case 0x00540104: _pmTableSize = 0x950; break; default: return; } break; default: return; } } private bool GetPmTableVersion(ref uint version) { uint[] args = [0]; uint fn; switch (_cpuCodeName) { case CpuCodeName.RavenRidge: case CpuCodeName.Picasso: fn = 0x0c; break; case CpuCodeName.Matisse: case CpuCodeName.Vermeer: fn = 0x08; break; case CpuCodeName.Renoir: fn = 0x06; break; case CpuCodeName.Raphael: case CpuCodeName.GraniteRidge: fn = 0x05; break; default: return false; } bool ret = SendCommand(fn, ref args); version = args[0]; return ret; } private void SetupAddrClass1(uint[] fn) { uint[] args = [1, 1]; bool command = SendCommand(fn[0], ref args); if (!command) return; _dramBaseAddr = args[0]; _dramAddrHi = args[1]; } private void SetupAddrClass2(uint[] fn) { uint[] args = [0, 0, 0, 0, 0, 0]; bool command = SendCommand(fn[0], ref args); if (!command) return; args = [0]; command = SendCommand(fn[1], ref args); if (!command) return; _dramBaseAddr = args[0]; } private void SetupAddrClass3(uint[] fn) { uint[] parts = [0, 0]; // == Part 1 == uint[] args = [3]; bool command = SendCommand(fn[0], ref args); if (!command) return; args = [3]; command = SendCommand(fn[2], ref args); if (!command) return; // 1st Base. parts[0] = args[0]; // == Part 1 End == // == Part 2 == args = [3]; command = SendCommand(fn[1], ref args); if (!command) return; args = [5]; command = SendCommand(fn[0], ref args); if (!command) return; args = [5]; command = SendCommand(fn[2], ref args); if (!command) return; // 2nd base. parts[1] = args[0]; // == Part 2 End == _dramBaseAddr = parts[0] & 0xFFFFFFFF; } private void SetupDramBaseAddr() { uint[] fn = [0, 0, 0]; switch (_cpuCodeName) { case CpuCodeName.Raphael: case CpuCodeName.GraniteRidge: fn[0] = 0x04; SetupAddrClass1(fn); return; case CpuCodeName.Vermeer: case CpuCodeName.Matisse: case CpuCodeName.CastlePeak: fn[0] = 0x06; SetupAddrClass1(fn); return; case CpuCodeName.Renoir: fn[0] = 0x66; SetupAddrClass1(fn); return; case CpuCodeName.Colfax: case CpuCodeName.PinnacleRidge: fn[0] = 0x0b; fn[1] = 0x0c; SetupAddrClass2(fn); return; case CpuCodeName.Dali: case CpuCodeName.Picasso: case CpuCodeName.RavenRidge: case CpuCodeName.RavenRidge2: fn[0] = 0x0a; fn[1] = 0x3d; fn[2] = 0x0b; SetupAddrClass3(fn); return; default: return; } } public bool TransferTableToDram() { uint[] args = [0]; uint fn; switch (_cpuCodeName) { case CpuCodeName.Raphael: case CpuCodeName.GraniteRidge: fn = 0x03; break; case CpuCodeName.Matisse: case CpuCodeName.Vermeer: fn = 0x05; break; case CpuCodeName.Renoir: args[0] = 3; fn = 0x65; break; case CpuCodeName.Picasso: case CpuCodeName.RavenRidge: case CpuCodeName.RavenRidge2: args[0] = 3; fn = 0x3d; break; default: return false; } return SendCommand(fn, ref args); } private bool SendCommand(uint msg, ref uint[] args) { uint[] cmdArgs = new uint[SMU_REQ_MAX_ARGS]; int argsLength = Math.Min(args.Length, cmdArgs.Length); for (int i = 0; i < argsLength; ++i) cmdArgs[i] = args[i]; uint tmp = 0; if (Mutexes.WaitPciBus(5000)) { // Step 1: Wait until the RSP register is non-zero. tmp = 0; uint retries = SMU_RETRIES_MAX; do { if (!ReadReg(_rspAddr, ref tmp)) { Mutexes.ReleasePciBus(); return false; } } while (tmp == 0 && retries-- != 0); // Step 1.b: A command is still being processed meaning a new command cannot be issued. if (retries == 0 && tmp == 0) { Mutexes.ReleasePciBus(); return false; } // Step 2: Write zero (0) to the RSP register WriteReg(_rspAddr, 0); // Step 3: Write the argument(s) into the argument register(s) for (int i = 0; i < cmdArgs.Length; ++i) WriteReg(_argsAddr + (uint)(i * 4), cmdArgs[i]); // Step 4: Write the message Id into the Message ID register WriteReg(_cmdAddr, msg); // Step 5: Wait until the Response register is non-zero. tmp = 0; retries = SMU_RETRIES_MAX; do { if (!ReadReg(_rspAddr, ref tmp)) { Mutexes.ReleasePciBus(); return false; } } while (tmp == 0 && retries-- != 0); if (retries == 0 && tmp != (uint)Status.OK) { Mutexes.ReleasePciBus(); return false; } // Step 6: If the Response register contains OK, then SMU has finished processing the message. args = new uint[SMU_REQ_MAX_ARGS]; for (byte i = 0; i < SMU_REQ_MAX_ARGS; i++) { if (!ReadReg(_argsAddr + (uint)(i * 4), ref args[i])) { Mutexes.ReleasePciBus(); return false; } } ReadReg(_rspAddr, ref tmp); Mutexes.ReleasePciBus(); } return tmp == (uint)Status.OK; } private static void WriteReg(uint addr, uint data) { if (Mutexes.WaitPciBus(10)) { if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) Ring0.WritePciConfig(0x00, SMU_PCI_DATA_REG, data); Mutexes.ReleasePciBus(); } } private static bool ReadReg(uint addr, ref uint data) { bool read = false; if (Mutexes.WaitPciBus(10)) { if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) read = Ring0.ReadPciConfig(0x00, SMU_PCI_DATA_REG, out data); Mutexes.ReleasePciBus(); } return read; } public struct SmuSensorType { public string Name; public SensorType Type; public float Scale; } private enum Status : uint { OK = 0x01, CmdRejectedBusy = 0xFC, CmdRejectedPrereq = 0xFD, UnknownCmd = 0xFE, Failed = 0xFF } private enum CpuCodeName { Undefined, Colfax, Renoir, Picasso, Matisse, Threadripper, CastlePeak, RavenRidge, RavenRidge2, SummitRidge, PinnacleRidge, Rembrandt, Vermeer, Vangogh, Cezanne, Milan, Dali, Raphael, GraniteRidge } }