mirror of
https://github.com/openhardwaremonitor/openhardwaremonitor
synced 2025-08-30 05:47:38 +00:00
Improved the implementation for the AMD 10h family CPU clock speeds.
This commit is contained in:
parent
7232dcc55f
commit
cc719ae7e8
@ -92,7 +92,7 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
|
||||
this, settings);
|
||||
if (hasTSC)
|
||||
if (HasTimeStampCounter)
|
||||
ActivateSensor(coreClocks[i]);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTSC) {
|
||||
if (HasTimeStampCounter) {
|
||||
double newBusClock = 0;
|
||||
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
@ -151,11 +151,12 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
// 8-13 hold StartFID, we don't use that here.
|
||||
double curMP = 0.5 * ((eax & 0x3F) + 8);
|
||||
double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8);
|
||||
coreClocks[i].Value = (float)(curMP * MaxClock / maxMP);
|
||||
newBusClock = (float)(MaxClock / maxMP);
|
||||
coreClocks[i].Value =
|
||||
(float)(curMP * TimeStampCounterFrequency / maxMP);
|
||||
newBusClock = (float)(TimeStampCounterFrequency / maxMP);
|
||||
} else {
|
||||
// Fail-safe value - if the code above fails, we'll use this instead
|
||||
coreClocks[i].Value = (float)MaxClock;
|
||||
coreClocks[i].Value = (float)TimeStampCounterFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,10 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
@ -47,16 +50,22 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
private readonly Sensor coreTemperature;
|
||||
private readonly Sensor[] coreClocks;
|
||||
private readonly Sensor busClock;
|
||||
|
||||
private const uint COFVID_STATUS = 0xC0010071;
|
||||
|
||||
private const uint PERF_CTL_0 = 0xC0010000;
|
||||
private const uint PERF_CTR_0 = 0xC0010004;
|
||||
private const uint P_STATE_0 = 0xC0010064;
|
||||
private const uint COFVID_STATUS = 0xC0010071;
|
||||
|
||||
private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
|
||||
private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
|
||||
private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
|
||||
|
||||
|
||||
private readonly uint miscellaneousControlAddress;
|
||||
|
||||
private double timeStampCounterMultiplier;
|
||||
|
||||
private StringBuilder debug = new StringBuilder();
|
||||
|
||||
public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
|
||||
: base(processorIndex, cpuid, settings)
|
||||
{
|
||||
@ -76,15 +85,87 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
|
||||
this, settings);
|
||||
if (hasTSC)
|
||||
if (HasTimeStampCounter)
|
||||
ActivateSensor(coreClocks[i]);
|
||||
}
|
||||
|
||||
// set affinity to the first thread for all frequency estimations
|
||||
IntPtr thread = NativeMethods.GetCurrentThread();
|
||||
UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread,
|
||||
(UIntPtr)(1L << cpuid[0][0].Thread));
|
||||
|
||||
uint ctlEax, ctlEdx;
|
||||
WinRing0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
|
||||
uint ctrEax, ctrEdx;
|
||||
WinRing0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
|
||||
|
||||
timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
|
||||
|
||||
// restore the performance counter registers
|
||||
WinRing0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
|
||||
WinRing0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
|
||||
|
||||
// restore the thread affinity.
|
||||
NativeMethods.SetThreadAffinityMask(thread, mask);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private double estimateTimeStampCounterMultiplier() {
|
||||
// preload the function
|
||||
estimateTimeStampCounterMultiplier(0);
|
||||
estimateTimeStampCounterMultiplier(0);
|
||||
|
||||
// estimate the multiplier
|
||||
List<double> estimate = new List<double>(3);
|
||||
for (int i = 0; i < 3; i++)
|
||||
estimate.Add(estimateTimeStampCounterMultiplier(0.025));
|
||||
estimate.Sort();
|
||||
return estimate[1];
|
||||
}
|
||||
|
||||
private double estimateTimeStampCounterMultiplier(double timeWindow) {
|
||||
uint eax, edx;
|
||||
|
||||
// select event "076h CPU Clocks not Halted" and enable the counter
|
||||
WinRing0.Wrmsr(PERF_CTL_0,
|
||||
(1 << 22) | // enable performance counter
|
||||
(1 << 17) | // count events in user mode
|
||||
(1 << 16) | // count events in operating-system mode
|
||||
0x76, 0x00000000);
|
||||
|
||||
// set the counter to 0
|
||||
WinRing0.Wrmsr(PERF_CTR_0, 0, 0);
|
||||
|
||||
long ticks = (long)(timeWindow * Stopwatch.Frequency);
|
||||
uint lsbBegin, msbBegin, lsbEnd, msbEnd;
|
||||
|
||||
long timeBegin = Stopwatch.GetTimestamp() +
|
||||
(long)Math.Ceiling(0.001 * ticks);
|
||||
long timeEnd = timeBegin + ticks;
|
||||
while (Stopwatch.GetTimestamp() < timeBegin) { }
|
||||
WinRing0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
|
||||
while (Stopwatch.GetTimestamp() < timeEnd) { }
|
||||
WinRing0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
|
||||
|
||||
WinRing0.Rdmsr(COFVID_STATUS, out eax, out edx);
|
||||
uint cpuDid = (eax >> 6) & 7;
|
||||
uint cpuFid = eax & 0x1F;
|
||||
double coreMultiplier = MultiplierFromIDs(cpuDid, cpuFid);
|
||||
|
||||
ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
|
||||
ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
|
||||
|
||||
double coreFrequency = 1e-6 *
|
||||
(((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
|
||||
(timeEnd - timeBegin);
|
||||
|
||||
double busFrequency = coreFrequency / coreMultiplier;
|
||||
return 0.5 * Math.Round(2 * TimeStampCounterFrequency / busFrequency);
|
||||
}
|
||||
|
||||
protected override uint[] GetMSRs() {
|
||||
return new uint[] { P_STATE_0, COFVID_STATUS };
|
||||
return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS };
|
||||
}
|
||||
|
||||
public override string GetReport() {
|
||||
@ -94,12 +175,18 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
r.Append("Miscellaneous Control Address: 0x");
|
||||
r.AppendLine((miscellaneousControlAddress).ToString("X",
|
||||
CultureInfo.InvariantCulture));
|
||||
r.Append("Time Stamp Counter Multiplier: ");
|
||||
r.AppendLine(timeStampCounterMultiplier.ToString(
|
||||
CultureInfo.InvariantCulture));
|
||||
r.AppendLine();
|
||||
|
||||
r.Append(debug);
|
||||
r.AppendLine();
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
private double MultiplierFromIDs(uint divisorID, uint frequencyID) {
|
||||
private static double MultiplierFromIDs(uint divisorID, uint frequencyID) {
|
||||
return 0.5 * (frequencyID + 0x10) / (1 << (int)divisorID);
|
||||
}
|
||||
|
||||
@ -118,35 +205,29 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTSC) {
|
||||
if (HasTimeStampCounter) {
|
||||
double newBusClock = 0;
|
||||
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
Thread.Sleep(1);
|
||||
|
||||
uint curEax, curEdx;
|
||||
uint maxEax, maxEdx;
|
||||
if (WinRing0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
|
||||
(UIntPtr)(1L << cpuid[i][0].Thread)) &&
|
||||
WinRing0.RdmsrTx(P_STATE_0, out maxEax, out maxEdx,
|
||||
(UIntPtr)(1L << cpuid[i][0].Thread)))
|
||||
{
|
||||
// 8:6 CpuDid: current core divisor ID
|
||||
// 5:0 CpuFid: current core frequency ID
|
||||
uint curCpuDid = (curEax >> 6) & 7;
|
||||
uint curCpuFid = curEax & 0x1F;
|
||||
double multiplier = MultiplierFromIDs(curCpuDid, curCpuFid);
|
||||
uint cpuDid = (curEax >> 6) & 7;
|
||||
uint cpuFid = curEax & 0x1F;
|
||||
double multiplier = MultiplierFromIDs(cpuDid, cpuFid);
|
||||
|
||||
// we assume that the max multiplier (used for the TSC)
|
||||
// can be found in the P_STATE_0 MSR
|
||||
uint maxCpuDid = (maxEax >> 6) & 7;
|
||||
uint maxCpuFid = maxEax & 0x1F;
|
||||
double maxMultiplier = MultiplierFromIDs(maxCpuDid, maxCpuFid);
|
||||
|
||||
coreClocks[i].Value = (float)(multiplier * MaxClock / maxMultiplier);
|
||||
newBusClock = (float)(MaxClock / maxMultiplier);
|
||||
coreClocks[i].Value =
|
||||
(float)(multiplier * TimeStampCounterFrequency /
|
||||
timeStampCounterMultiplier);
|
||||
newBusClock =
|
||||
(float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
|
||||
} else {
|
||||
coreClocks[i].Value = (float)MaxClock;
|
||||
coreClocks[i].Value = (float)TimeStampCounterFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +236,17 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
ActivateSensor(this.busClock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class NativeMethods {
|
||||
private const string KERNEL = "kernel32.dll";
|
||||
|
||||
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
||||
public static extern UIntPtr
|
||||
SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
|
||||
|
||||
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
||||
public static extern IntPtr GetCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
protected readonly int coreCount;
|
||||
protected readonly string name;
|
||||
|
||||
protected readonly bool hasTSC;
|
||||
protected readonly bool invariantTSC;
|
||||
private readonly double estimatedMaxClock;
|
||||
private readonly bool hasTimeStampCounter;
|
||||
private readonly bool isInvariantTimeStampCounter;
|
||||
private readonly double estimatedTimeStampCounterFrequency;
|
||||
|
||||
private ulong lastTimeStampCount;
|
||||
private long lastTime;
|
||||
private double maxClock;
|
||||
private double timeStampCounterFrequency;
|
||||
|
||||
private readonly Vendor vendor;
|
||||
|
||||
@ -89,19 +89,19 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
this.coreCount = cpuid.Length;
|
||||
this.name = cpuid[0][0].Name;
|
||||
|
||||
// check if processor has TSC
|
||||
// check if processor has a TSC
|
||||
if (cpuid[0][0].Data.GetLength(0) > 1
|
||||
&& (cpuid[0][0].Data[1, 3] & 0x10) != 0)
|
||||
hasTSC = true;
|
||||
hasTimeStampCounter = true;
|
||||
else
|
||||
hasTSC = false;
|
||||
hasTimeStampCounter = false;
|
||||
|
||||
// check if processor supports invariant TSC
|
||||
// check if processor supports an invariant TSC
|
||||
if (cpuid[0][0].ExtData.GetLength(0) > 7
|
||||
&& (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
|
||||
invariantTSC = true;
|
||||
isInvariantTimeStampCounter = true;
|
||||
else
|
||||
invariantTSC = false;
|
||||
isInvariantTimeStampCounter = false;
|
||||
|
||||
if (coreCount > 1)
|
||||
totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
|
||||
@ -119,30 +119,30 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
ActivateSensor(totalLoad);
|
||||
}
|
||||
|
||||
if (hasTSC)
|
||||
estimatedMaxClock = EstimateMaxClock();
|
||||
if (hasTimeStampCounter)
|
||||
estimatedTimeStampCounterFrequency = EstimateTimeStampCounterFrequency();
|
||||
else
|
||||
estimatedMaxClock = 0;
|
||||
maxClock = estimatedMaxClock;
|
||||
estimatedTimeStampCounterFrequency = 0;
|
||||
timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
|
||||
|
||||
lastTimeStampCount = 0;
|
||||
lastTime = 0;
|
||||
}
|
||||
|
||||
private static double EstimateMaxClock() {
|
||||
private static double EstimateTimeStampCounterFrequency() {
|
||||
// preload the function
|
||||
EstimateMaxClock(0);
|
||||
EstimateMaxClock(0);
|
||||
EstimateTimeStampCounterFrequency(0);
|
||||
EstimateTimeStampCounterFrequency(0);
|
||||
|
||||
// estimate the max clock in MHz
|
||||
List<double> estimatedMaxClocks = new List<double>(3);
|
||||
// estimate the frequency in MHz
|
||||
List<double> estimatedFrequency = new List<double>(3);
|
||||
for (int i = 0; i < 3; i++)
|
||||
estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
|
||||
estimatedMaxClocks.Sort();
|
||||
return estimatedMaxClocks[1];
|
||||
estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
|
||||
estimatedFrequency.Sort();
|
||||
return estimatedFrequency[1];
|
||||
}
|
||||
|
||||
private static double EstimateMaxClock(double timeWindow) {
|
||||
private static double EstimateTimeStampCounterFrequency(double timeWindow) {
|
||||
long ticks = (long)(timeWindow * Stopwatch.Frequency);
|
||||
uint lsbBegin, msbBegin, lsbEnd, msbEnd;
|
||||
|
||||
@ -195,12 +195,13 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
Environment.NewLine);
|
||||
r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
|
||||
Environment.NewLine);
|
||||
r.AppendLine("TSC: " +
|
||||
(hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
|
||||
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
|
||||
"Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
|
||||
r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
|
||||
isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
|
||||
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
|
||||
"Max Clock: {0} MHz", Math.Round(maxClock * 100) * 0.01));
|
||||
"Time Stamp Counter Frequency: {0} MHz",
|
||||
Math.Round(timeStampCounterFrequency * 100) * 0.01));
|
||||
r.AppendLine();
|
||||
|
||||
uint[] msrArray = GetMSRs();
|
||||
@ -239,22 +240,27 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
get { return HardwareType.CPU; }
|
||||
}
|
||||
|
||||
protected double MaxClock {
|
||||
get { return maxClock; }
|
||||
public bool HasTimeStampCounter {
|
||||
get { return hasTimeStampCounter; }
|
||||
}
|
||||
|
||||
public double TimeStampCounterFrequency {
|
||||
get { return timeStampCounterFrequency; }
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
if (hasTSC) {
|
||||
if (hasTimeStampCounter) {
|
||||
uint lsb, msb;
|
||||
WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
|
||||
long time = Stopwatch.GetTimestamp();
|
||||
ulong timeStampCount = ((ulong)msb << 32) | lsb;
|
||||
double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
|
||||
if (delta > 0.5) {
|
||||
if (invariantTSC)
|
||||
maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
|
||||
if (isInvariantTimeStampCounter)
|
||||
timeStampCounterFrequency =
|
||||
(timeStampCount - lastTimeStampCount) / (1e6 * delta);
|
||||
else
|
||||
maxClock = estimatedMaxClock;
|
||||
timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
|
||||
|
||||
lastTimeStampCount = timeStampCount;
|
||||
lastTime = time;
|
||||
|
@ -145,7 +145,7 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
coreClocks[i] =
|
||||
new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
|
||||
if (hasTSC)
|
||||
if (HasTimeStampCounter)
|
||||
ActivateSensor(coreClocks[i]);
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTSC) {
|
||||
if (HasTimeStampCounter) {
|
||||
double newBusClock = 0;
|
||||
uint eax, edx;
|
||||
for (int i = 0; i < coreClocks.Length; i++) {
|
||||
@ -191,9 +191,10 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
(UIntPtr)(1L << cpuid[i][0].Thread))) {
|
||||
if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
|
||||
uint nehalemMultiplier = eax & 0xff;
|
||||
coreClocks[i].Value =
|
||||
(float)(nehalemMultiplier * MaxClock / maxNehalemMultiplier);
|
||||
newBusClock = (float)(MaxClock / maxNehalemMultiplier);
|
||||
coreClocks[i].Value =(float)(nehalemMultiplier *
|
||||
TimeStampCounterFrequency / maxNehalemMultiplier);
|
||||
newBusClock =
|
||||
(float)(TimeStampCounterFrequency / maxNehalemMultiplier);
|
||||
} else { // Core 2
|
||||
uint multiplier = (eax >> 8) & 0x1f;
|
||||
uint maxMultiplier = (edx >> 8) & 0x1f;
|
||||
@ -201,13 +202,15 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
uint factor = (multiplier << 1) | ((eax >> 14) & 1);
|
||||
uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
|
||||
if (maxFactor > 0) {
|
||||
coreClocks[i].Value = (float)(factor * MaxClock / maxFactor);
|
||||
newBusClock = (float)(2 * MaxClock / maxFactor);
|
||||
coreClocks[i].Value =
|
||||
(float)(factor * TimeStampCounterFrequency / maxFactor);
|
||||
newBusClock =
|
||||
(float)(2 * TimeStampCounterFrequency / maxFactor);
|
||||
}
|
||||
}
|
||||
} else { // Intel Pentium 4
|
||||
// if IA32_PERF_STATUS is not available, assume maxClock
|
||||
coreClocks[i].Value = (float)MaxClock;
|
||||
// if IA32_PERF_STATUS is not available, assume TSC frequency
|
||||
coreClocks[i].Value = (float)TimeStampCounterFrequency;
|
||||
}
|
||||
}
|
||||
if (newBusClock > 0) {
|
||||
|
@ -90,10 +90,13 @@ namespace OpenHardwareMonitor.Hardware {
|
||||
public delegate bool ReadPciConfigDwordExDelegate(uint pciAddress,
|
||||
uint regAddress, out uint value);
|
||||
public delegate bool WritePciConfigDwordExDelegate(uint pciAddress,
|
||||
uint regAddress, uint value);
|
||||
public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
|
||||
UIntPtr threadAffinityMask);
|
||||
uint regAddress, uint value);
|
||||
public delegate bool RdtscDelegate(out uint eax, out uint edx);
|
||||
public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
|
||||
UIntPtr threadAffinityMask);
|
||||
public delegate bool WrmsrDelegate(uint index, uint eax, uint edx);
|
||||
public delegate bool WrmsrTxDelegate(uint index, uint eax, uint edx,
|
||||
UIntPtr threadAffinityMask);
|
||||
|
||||
private static readonly InitializeOlsDelegate InitializeOls =
|
||||
CreateDelegate<InitializeOlsDelegate>("InitializeOls");
|
||||
@ -116,10 +119,14 @@ namespace OpenHardwareMonitor.Hardware {
|
||||
CreateDelegate<ReadPciConfigDwordExDelegate>("ReadPciConfigDwordEx");
|
||||
public static readonly WritePciConfigDwordExDelegate WritePciConfigDwordEx =
|
||||
CreateDelegate<WritePciConfigDwordExDelegate>("WritePciConfigDwordEx");
|
||||
public static readonly RdtscTxDelegate RdtscTx =
|
||||
CreateDelegate<RdtscTxDelegate>("RdtscTx");
|
||||
public static readonly RdtscDelegate Rdtsc =
|
||||
CreateDelegate<RdtscDelegate>("Rdtsc");
|
||||
public static readonly RdtscTxDelegate RdtscTx =
|
||||
CreateDelegate<RdtscTxDelegate>("RdtscTx");
|
||||
public static readonly WrmsrDelegate Wrmsr =
|
||||
CreateDelegate<WrmsrDelegate>("Wrmsr");
|
||||
public static readonly WrmsrTxDelegate WrmsrTx =
|
||||
CreateDelegate<WrmsrTxDelegate>("WrmsrTx");
|
||||
|
||||
private static T CreateDelegate<T>(string entryPoint) where T : class {
|
||||
DllImportAttribute attribute = new DllImportAttribute(GetDllName());
|
||||
|
@ -37,5 +37,5 @@
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("0.1.37.17")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.37.17 Alpha")]
|
||||
[assembly: AssemblyVersion("0.1.37.23")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.37.23 Alpha")]
|
Loading…
x
Reference in New Issue
Block a user