Hardware/LPC/NCT677X.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 417 4865cf06a7fa
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
moel@245
     1
/*
moel@245
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@245
     6
 
moel@413
     7
  Copyright (C) 2010-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@245
     9
*/
moel@245
    10
moel@355
    11
using System;
moel@245
    12
using System.Globalization;
moel@245
    13
using System.Text;
moel@245
    14
moel@245
    15
namespace OpenHardwareMonitor.Hardware.LPC {
moel@245
    16
  internal class NCT677X : ISuperIO {
moel@245
    17
moel@245
    18
    private readonly ushort port;
moel@245
    19
    private readonly byte revision;
moel@245
    20
moel@245
    21
    private readonly Chip chip;
moel@245
    22
moel@419
    23
    private readonly bool isNuvotonVendor;
moel@419
    24
moel@415
    25
    private readonly float?[] voltages = new float?[0];
moel@415
    26
    private readonly float?[] temperatures = new float?[0];
moel@415
    27
    private readonly float?[] fans = new float?[0];
moel@415
    28
    private readonly float?[] controls = new float?[0];
moel@245
    29
moel@245
    30
    // Hardware Monitor
moel@245
    31
    private const uint ADDRESS_REGISTER_OFFSET = 0x05;
moel@245
    32
    private const uint DATA_REGISTER_OFFSET = 0x06;
moel@245
    33
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@245
    34
moel@245
    35
    private byte ReadByte(ushort address) {
moel@245
    36
      byte bank = (byte)(address >> 8);
moel@245
    37
      byte register = (byte)(address & 0xFF);
moel@245
    38
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER);
moel@245
    39
      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
moel@245
    40
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
moel@245
    41
      return Ring0.ReadIoPort(port + DATA_REGISTER_OFFSET);
moel@323
    42
    }
moel@323
    43
moel@323
    44
    private void WriteByte(ushort address, byte value) {
moel@323
    45
      byte bank = (byte)(address >> 8);
moel@323
    46
      byte register = (byte)(address & 0xFF);
moel@323
    47
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER);
moel@323
    48
      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
moel@323
    49
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
moel@323
    50
      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, value);
moel@356
    51
    }
moel@245
    52
moel@245
    53
    // Consts 
moel@245
    54
    private const ushort NUVOTON_VENDOR_ID = 0x5CA3;
moel@245
    55
moel@245
    56
    // Hardware Monitor Registers    
moel@245
    57
    private const ushort VENDOR_ID_HIGH_REGISTER = 0x804F;
moel@355
    58
    private const ushort VENDOR_ID_LOW_REGISTER = 0x004F;  
moel@355
    59
    
moel@355
    60
    private readonly ushort[] FAN_PWM_OUT_REG = 
moel@413
    61
      { 0x001, 0x003, 0x011, 0x013, 0x015, 0x017 };
moel@355
    62
    private readonly ushort[] FAN_PWM_COMMAND_REG = 
moel@413
    63
      { 0x109, 0x209, 0x309, 0x809, 0x909, 0xA09 };
moel@355
    64
    private readonly ushort[] FAN_CONTROL_MODE_REG = 
moel@413
    65
      { 0x102, 0x202, 0x302, 0x802, 0x902, 0xA02 };
moel@245
    66
moel@355
    67
    private readonly ushort fanRpmBaseRegister;
moel@265
    68
    private readonly int minFanRPM;
moel@245
    69
moel@414
    70
    private bool[] restoreDefaultFanControlRequired = new bool[6];       
moel@414
    71
    private byte[] initialFanControlMode = new byte[6];
moel@414
    72
    private byte[] initialFanPwmCommand = new byte[6];
moel@355
    73
moel@355
    74
    private readonly ushort[] voltageRegisters;
moel@355
    75
    private readonly ushort voltageVBatRegister;
moel@355
    76
moel@355
    77
    private readonly byte[] temperaturesSource;
moel@355
    78
moel@355
    79
    private readonly ushort[] temperatureRegister;
moel@355
    80
    private readonly ushort[] temperatureHalfRegister;
moel@355
    81
    private readonly int[] temperatureHalfBit;  
moel@355
    82
    private readonly ushort[] temperatureSourceRegister;        
moel@355
    83
moel@355
    84
    private readonly ushort?[] alternateTemperatureRegister;
moel@323
    85
moel@276
    86
    private enum SourceNCT6771F : byte {
moel@245
    87
      SYSTIN = 1,
moel@245
    88
      CPUTIN = 2,
moel@245
    89
      AUXTIN = 3,
moel@245
    90
      SMBUSMASTER = 4,
moel@276
    91
      PECI_0 = 5, 
moel@276
    92
      PECI_1 = 6, 
moel@276
    93
      PECI_2 = 7,
moel@276
    94
      PECI_3 = 8,
moel@276
    95
      PECI_4 = 9,
moel@276
    96
      PECI_5 = 10,
moel@276
    97
      PECI_6 = 11,
moel@276
    98
      PECI_7 = 12,
moel@245
    99
      PCH_CHIP_CPU_MAX_TEMP = 13,
moel@245
   100
      PCH_CHIP_TEMP = 14,
moel@245
   101
      PCH_CPU_TEMP = 15,
moel@245
   102
      PCH_MCH_TEMP = 16, 
moel@245
   103
      PCH_DIM0_TEMP = 17,
moel@245
   104
      PCH_DIM1_TEMP = 18,
moel@245
   105
      PCH_DIM2_TEMP = 19,
moel@245
   106
      PCH_DIM3_TEMP = 20
moel@245
   107
    }
moel@245
   108
moel@276
   109
    private enum SourceNCT6776F : byte {
moel@276
   110
      SYSTIN = 1,
moel@276
   111
      CPUTIN = 2,
moel@276
   112
      AUXTIN = 3,
moel@276
   113
      SMBUSMASTER_0 = 4,
moel@276
   114
      SMBUSMASTER_1 = 5,
moel@276
   115
      SMBUSMASTER_2 = 6,
moel@276
   116
      SMBUSMASTER_3 = 7,
moel@276
   117
      SMBUSMASTER_4 = 8,
moel@276
   118
      SMBUSMASTER_5 = 9,
moel@276
   119
      SMBUSMASTER_6 = 10,
moel@276
   120
      SMBUSMASTER_7 = 11,
moel@276
   121
      PECI_0 = 12,
moel@276
   122
      PECI_1 = 13,
moel@276
   123
      PCH_CHIP_CPU_MAX_TEMP = 14,
moel@276
   124
      PCH_CHIP_TEMP = 15,
moel@276
   125
      PCH_CPU_TEMP = 16,
moel@276
   126
      PCH_MCH_TEMP = 17,
moel@276
   127
      PCH_DIM0_TEMP = 18,
moel@276
   128
      PCH_DIM1_TEMP = 19,
moel@276
   129
      PCH_DIM2_TEMP = 20,
moel@276
   130
      PCH_DIM3_TEMP = 21,
moel@276
   131
      BYTE_TEMP = 22
moel@276
   132
    }
moel@276
   133
moel@413
   134
    private enum SourceNCT67XXD : byte {
moel@355
   135
      SYSTIN = 1,
moel@355
   136
      CPUTIN = 2,
moel@355
   137
      AUXTIN0 = 3,
moel@355
   138
      AUXTIN1 = 4,
moel@355
   139
      AUXTIN2 = 5,
moel@355
   140
      AUXTIN3 = 6,      
moel@355
   141
      SMBUSMASTER_0 = 8,
moel@355
   142
      SMBUSMASTER_1 = 9,
moel@355
   143
      SMBUSMASTER_2 = 10,
moel@355
   144
      SMBUSMASTER_3 = 11,
moel@355
   145
      SMBUSMASTER_4 = 12,
moel@355
   146
      SMBUSMASTER_5 = 13,
moel@355
   147
      SMBUSMASTER_6 = 14,
moel@355
   148
      SMBUSMASTER_7 = 15,
moel@355
   149
      PECI_0 = 16,
moel@355
   150
      PECI_1 = 17,
moel@355
   151
      PCH_CHIP_CPU_MAX_TEMP = 18,
moel@355
   152
      PCH_CHIP_TEMP = 19,
moel@355
   153
      PCH_CPU_TEMP = 20,
moel@355
   154
      PCH_MCH_TEMP = 21,
moel@355
   155
      PCH_DIM0_TEMP = 22,
moel@355
   156
      PCH_DIM1_TEMP = 23,
moel@355
   157
      PCH_DIM2_TEMP = 24,
moel@355
   158
      PCH_DIM3_TEMP = 25,
moel@355
   159
      BYTE_TEMP = 26
moel@355
   160
    }
moel@355
   161
moel@245
   162
    public NCT677X(Chip chip, byte revision, ushort port) {
moel@245
   163
      this.chip = chip;
moel@245
   164
      this.revision = revision;
moel@245
   165
      this.port = port;
moel@245
   166
moel@419
   167
moel@419
   168
      this.isNuvotonVendor = IsNuvotonVendor();
moel@419
   169
moel@419
   170
      if (!isNuvotonVendor)
moel@265
   171
        return;
moel@265
   172
moel@265
   173
      switch (chip) {
moel@355
   174
        case Chip.NCT6771F:
moel@355
   175
        case Chip.NCT6776F:          
moel@355
   176
          if (chip == Chip.NCT6771F) {
moel@355
   177
            fans = new float?[4];
moel@355
   178
moel@355
   179
            // min value RPM value with 16-bit fan counter
moel@355
   180
            minFanRPM = (int)(1.35e6 / 0xFFFF);
moel@355
   181
moel@355
   182
            temperaturesSource = new byte[] {
moel@355
   183
              (byte)SourceNCT6771F.PECI_0,
moel@355
   184
              (byte)SourceNCT6771F.CPUTIN,
moel@355
   185
              (byte)SourceNCT6771F.AUXTIN,
moel@355
   186
              (byte)SourceNCT6771F.SYSTIN
moel@355
   187
            };            
moel@355
   188
          } else {
moel@355
   189
            fans = new float?[5];
moel@355
   190
moel@355
   191
            // min value RPM value with 13-bit fan counter
moel@355
   192
            minFanRPM = (int)(1.35e6 / 0x1FFF);
moel@355
   193
moel@355
   194
            temperaturesSource = new byte[] {
moel@355
   195
              (byte)SourceNCT6776F.PECI_0,
moel@355
   196
              (byte)SourceNCT6776F.CPUTIN,
moel@355
   197
              (byte)SourceNCT6776F.AUXTIN,
moel@355
   198
              (byte)SourceNCT6776F.SYSTIN 
moel@355
   199
            };
moel@355
   200
          }
moel@355
   201
          fanRpmBaseRegister = 0x656;
moel@355
   202
moel@355
   203
          controls = new float?[3];
moel@355
   204
moel@355
   205
          voltages = new float?[9];
moel@355
   206
          voltageRegisters = new ushort[] 
moel@355
   207
            { 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x550, 0x551 };
moel@355
   208
          voltageVBatRegister = 0x551;
moel@355
   209
moel@355
   210
          temperatures = new float?[4];
moel@355
   211
          temperatureRegister = new ushort[]
moel@355
   212
            { 0x027, 0x073, 0x075, 0x077, 0x150, 0x250, 0x62B, 0x62C, 0x62D };
moel@355
   213
          temperatureHalfRegister = new ushort[]
moel@355
   214
            { 0, 0x074, 0x076, 0x078, 0x151, 0x251, 0x62E, 0x62E, 0x62E };
moel@355
   215
          temperatureHalfBit = new int[] 
moel@355
   216
            { -1, 7, 7, 7, 7, 7, 0, 1, 2 };
moel@355
   217
          temperatureSourceRegister = new ushort[]
moel@355
   218
            { 0x621, 0x100, 0x200, 0x300, 0x622, 0x623, 0x624, 0x625, 0x626 };
moel@355
   219
moel@355
   220
          alternateTemperatureRegister = new ushort?[] 
moel@355
   221
            { null, null, null, null };
moel@265
   222
          break;
moel@356
   223
moel@355
   224
        case Chip.NCT6779D:
moel@413
   225
        case Chip.NCT6791D:
moel@413
   226
          if (chip == Chip.NCT6779D) {
moel@413
   227
            fans = new float?[5];
moel@413
   228
            controls = new float?[5];
moel@413
   229
          } else {
moel@413
   230
            fans = new float?[6];
moel@413
   231
            controls = new float?[6];
moel@413
   232
          }
moel@413
   233
moel@355
   234
          fanRpmBaseRegister = 0x4C0;
moel@355
   235
moel@265
   236
          // min value RPM value with 13-bit fan counter
moel@265
   237
          minFanRPM = (int)(1.35e6 / 0x1FFF);
moel@355
   238
moel@355
   239
          voltages = new float?[15];
moel@355
   240
          voltageRegisters = new ushort[] 
moel@355
   241
            { 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 
moel@355
   242
              0x489, 0x48A, 0x48B, 0x48C, 0x48D, 0x48E };
moel@355
   243
          voltageVBatRegister = 0x488;
moel@355
   244
moel@355
   245
          temperatures = new float?[7];
moel@355
   246
          temperaturesSource = new byte[] {
moel@413
   247
            (byte)SourceNCT67XXD.PECI_0,
moel@413
   248
            (byte)SourceNCT67XXD.CPUTIN,
moel@413
   249
            (byte)SourceNCT67XXD.SYSTIN,
moel@413
   250
            (byte)SourceNCT67XXD.AUXTIN0,
moel@413
   251
            (byte)SourceNCT67XXD.AUXTIN1,
moel@413
   252
            (byte)SourceNCT67XXD.AUXTIN2,
moel@413
   253
            (byte)SourceNCT67XXD.AUXTIN3
moel@355
   254
          };
moel@355
   255
moel@355
   256
          temperatureRegister = new ushort[]
moel@355
   257
            { 0x027, 0x073, 0x075, 0x077, 0x079, 0x07B, 0x150 };
moel@355
   258
          temperatureHalfRegister = new ushort[]
moel@355
   259
            { 0, 0x074, 0x076, 0x078, 0x07A, 0x07C, 0x151 };              
moel@355
   260
          temperatureHalfBit = new int[]
moel@355
   261
            { -1, 7, 7, 7, 7, 7, 7 };
moel@355
   262
          temperatureSourceRegister = new ushort[] 
moel@355
   263
            { 0x621, 0x100, 0x200, 0x300, 0x800, 0x900, 0x622 };
moel@355
   264
moel@355
   265
          alternateTemperatureRegister = new ushort?[] 
moel@355
   266
            {null, 0x491, 0x490, 0x492, 0x493, 0x494, 0x495 };
moel@355
   267
moel@413
   268
          break;
moel@265
   269
      }
moel@245
   270
    }
moel@245
   271
moel@245
   272
    private bool IsNuvotonVendor() {
moel@245
   273
      return ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) |
moel@245
   274
        ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID;
moel@245
   275
    }
moel@245
   276
moel@245
   277
    public byte? ReadGPIO(int index) {
moel@245
   278
      return null;
moel@245
   279
    }
moel@245
   280
moel@245
   281
    public void WriteGPIO(int index, byte value) { }
moel@245
   282
moel@323
   283
moel@323
   284
    private void SaveDefaultFanControl(int index) {
moel@323
   285
      if (!restoreDefaultFanControlRequired[index]) {
moel@323
   286
        initialFanControlMode[index] = ReadByte(FAN_CONTROL_MODE_REG[index]);
moel@323
   287
        initialFanPwmCommand[index] = ReadByte(FAN_PWM_COMMAND_REG[index]);
moel@323
   288
        restoreDefaultFanControlRequired[index] = true;
moel@323
   289
      }
moel@323
   290
    }
moel@323
   291
moel@323
   292
    private void RestoreDefaultFanControl(int index) {
moel@323
   293
      if (restoreDefaultFanControlRequired[index]) {
moel@323
   294
        WriteByte(FAN_CONTROL_MODE_REG[index], initialFanControlMode[index]);
moel@323
   295
        WriteByte(FAN_PWM_COMMAND_REG[index], initialFanPwmCommand[index]);
moel@323
   296
        restoreDefaultFanControlRequired[index] = false;
moel@323
   297
      }
moel@323
   298
    }
moel@323
   299
moel@323
   300
    public void SetControl(int index, byte? value) {
moel@419
   301
      if (!isNuvotonVendor)
moel@419
   302
        return;
moel@419
   303
moel@355
   304
      if (index < 0 || index >= controls.Length)
moel@355
   305
        throw new ArgumentOutOfRangeException("index");
moel@355
   306
moel@323
   307
      if (!Ring0.WaitIsaBusMutex(10))
moel@323
   308
        return;
moel@323
   309
moel@323
   310
      if (value.HasValue) {
moel@323
   311
        SaveDefaultFanControl(index);
moel@323
   312
moel@323
   313
        // set manual mode
moel@323
   314
        WriteByte(FAN_CONTROL_MODE_REG[index], 0);
moel@323
   315
moel@323
   316
        // set output value
moel@323
   317
        WriteByte(FAN_PWM_COMMAND_REG[index], value.Value);  
moel@323
   318
      } else {
moel@323
   319
        RestoreDefaultFanControl(index);
moel@323
   320
      }
moel@323
   321
moel@323
   322
      Ring0.ReleaseIsaBusMutex();
moel@323
   323
    }   
moel@323
   324
moel@245
   325
    public Chip Chip { get { return chip; } }
moel@245
   326
    public float?[] Voltages { get { return voltages; } }
moel@245
   327
    public float?[] Temperatures { get { return temperatures; } }
moel@245
   328
    public float?[] Fans { get { return fans; } }
moel@323
   329
    public float?[] Controls { get { return controls; } }
moel@245
   330
moel@245
   331
    public void Update() {
moel@419
   332
      if (!isNuvotonVendor)
moel@419
   333
        return;
moel@419
   334
moel@245
   335
      if (!Ring0.WaitIsaBusMutex(10))
moel@245
   336
        return;
moel@245
   337
moel@245
   338
      for (int i = 0; i < voltages.Length; i++) {
moel@355
   339
        float value = 0.008f * ReadByte(voltageRegisters[i]);
moel@245
   340
        bool valid = value > 0;
moel@245
   341
moel@245
   342
        // check if battery voltage monitor is enabled
moel@355
   343
        if (valid && voltageRegisters[i] == voltageVBatRegister) 
moel@245
   344
          valid = (ReadByte(0x005D) & 0x01) > 0;
moel@245
   345
moel@245
   346
        voltages[i] = valid ? value : (float?)null;
moel@245
   347
      }
moel@245
   348
moel@355
   349
      int temperatureSourceMask = 0;
moel@355
   350
      for (int i = temperatureRegister.Length - 1; i >= 0 ; i--) {
moel@355
   351
        int value = ((sbyte)ReadByte(temperatureRegister[i])) << 1;
moel@355
   352
        if (temperatureHalfBit[i] > 0) {
moel@355
   353
          value |= ((ReadByte(temperatureHalfRegister[i]) >>
moel@355
   354
            temperatureHalfBit[i]) & 0x1);
moel@245
   355
        }
moel@245
   356
moel@355
   357
        byte source = ReadByte(temperatureSourceRegister[i]);
moel@355
   358
        temperatureSourceMask |= 1 << source;
moel@245
   359
moel@246
   360
        float? temperature = 0.5f * value;
moel@246
   361
        if (temperature > 125 || temperature < -55)
moel@246
   362
          temperature = null;
moel@246
   363
moel@355
   364
        for (int j = 0; j < temperatures.Length; j++) 
moel@355
   365
          if (temperaturesSource[j] == source)
moel@355
   366
            temperatures[j] = temperature; 
moel@355
   367
      }
moel@355
   368
      for (int i = 0; i < alternateTemperatureRegister.Length; i++) {
moel@355
   369
        if (!alternateTemperatureRegister[i].HasValue)
moel@355
   370
          continue;
moel@355
   371
moel@355
   372
        if ((temperatureSourceMask & (1 << temperaturesSource[i])) > 0)
moel@355
   373
          continue;
moel@355
   374
moel@356
   375
        float? temperature = (sbyte)
moel@356
   376
          ReadByte(alternateTemperatureRegister[i].Value);
moel@356
   377
moel@356
   378
        if (temperature > 125 || temperature < -55)
moel@356
   379
          temperature = null;
moel@356
   380
moel@356
   381
        temperatures[i] = temperature;
moel@245
   382
      }
moel@245
   383
moel@245
   384
      for (int i = 0; i < fans.Length; i++) {
moel@355
   385
        byte high = ReadByte((ushort)(fanRpmBaseRegister + (i << 1)));
moel@355
   386
        byte low = ReadByte((ushort)(fanRpmBaseRegister + (i << 1) + 1));
moel@265
   387
        int value = (high << 8) | low;
moel@265
   388
moel@265
   389
        fans[i] = value > minFanRPM ? value : 0;
moel@245
   390
      }
moel@245
   391
moel@323
   392
      for (int i = 0; i < controls.Length; i++) {
moel@323
   393
        int value = ReadByte(FAN_PWM_OUT_REG[i]);
moel@323
   394
        controls[i] = value / 2.55f;
moel@323
   395
      }
moel@323
   396
moel@245
   397
      Ring0.ReleaseIsaBusMutex();
moel@245
   398
    }
moel@245
   399
moel@245
   400
    public string GetReport() {
moel@245
   401
      StringBuilder r = new StringBuilder();
moel@245
   402
moel@245
   403
      r.AppendLine("LPC " + this.GetType().Name);
moel@245
   404
      r.AppendLine();
moel@245
   405
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@245
   406
      r.Append("Chip revision: 0x");
moel@245
   407
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@245
   408
      r.Append("Base Adress: 0x");
moel@245
   409
      r.AppendLine(port.ToString("X4", CultureInfo.InvariantCulture));
moel@245
   410
      r.AppendLine();
moel@245
   411
moel@245
   412
      if (!Ring0.WaitIsaBusMutex(100))
moel@245
   413
        return r.ToString();
moel@245
   414
moel@246
   415
      ushort[] addresses = new ushort[] { 
moel@246
   416
        0x000, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070,
moel@246
   417
        0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 
moel@413
   418
        0x200,        0x220, 0x230, 0x240, 0x250, 0x260,
moel@413
   419
        0x300,        0x320, 0x330, 0x340,        0x360,
moel@413
   420
        0x400, 0x410, 0x420,        0x440, 0x450, 0x460, 0x480, 0x490, 0x4B0, 
moel@413
   421
                                                                0x4C0, 0x4F0,
moel@413
   422
        0x500,                             0x550, 0x560,
moel@246
   423
        0x600, 0x610 ,0x620, 0x630, 0x640, 0x650, 0x660, 0x670, 
moel@413
   424
        0x700, 0x710, 0x720, 0x730,
moel@413
   425
        0x800,        0x820, 0x830, 0x840,
moel@413
   426
        0x900,        0x920, 0x930, 0x940,        0x960,
moel@413
   427
        0xA00, 0xA10, 0xA20, 0xA30, 0xA40, 0xA50, 0xA60, 0xA70, 
moel@246
   428
        0xB00, 0xB10, 0xB20, 0xB30,        0xB50, 0xB60, 0xB70, 
moel@246
   429
        0xC00, 0xC10, 0xC20, 0xC30,        0xC50, 0xC60, 0xC70,
moel@246
   430
        0xD00, 0xD10, 0xD20, 0xD30,        0xD50, 0xD60, 
moel@246
   431
        0xE00, 0xE10, 0xE20, 0xE30, 
moel@417
   432
        0xF00, 0xF10, 0xF20, 0xF30,
moel@417
   433
        0x8040};
moel@246
   434
moel@245
   435
      r.AppendLine("Hardware Monitor Registers");
moel@245
   436
      r.AppendLine();
moel@417
   437
      r.AppendLine("        00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@245
   438
      r.AppendLine();
moel@246
   439
      foreach (ushort address in addresses) {
moel@245
   440
          r.Append(" ");
moel@417
   441
          r.Append(address.ToString("X4", CultureInfo.InvariantCulture));
moel@245
   442
          r.Append("  ");
moel@246
   443
          for (ushort j = 0; j <= 0xF; j++) {
moel@245
   444
            r.Append(" ");
moel@246
   445
            r.Append(ReadByte((ushort)(address | j)).ToString(
moel@245
   446
              "X2", CultureInfo.InvariantCulture));
moel@245
   447
          }
moel@245
   448
          r.AppendLine();
moel@245
   449
      }
moel@245
   450
      r.AppendLine();
moel@245
   451
moel@245
   452
      Ring0.ReleaseIsaBusMutex();
moel@245
   453
moel@245
   454
      return r.ToString();
moel@245
   455
    }
moel@245
   456
  }
moel@245
   457
}