・
・
・
・
・
・
・
・
・
・
・
・
・
・
GoldenFingers | A19 | A18 | B18 | B19 |
SlotA | A116 | A117 | A118 | A119 |
FID0 | FID1 | FID2 | FID3 | |
5 | 0 | 1 | 0 | 0 |
5.5 | 0 | 1 | 0 | 1 |
6 | 0 | 1 | 1 | 0 |
6.5 | 0 | 1 | 1 | 1 |
0にする | R4=1 R123=0 R155=1 | R5=1 R122=0 R156=1 | R6=1 R121=0 R157=1 | R3=0 R124=1 R158=1 |
1にする | R4=0 R123=1 R155=0 | R5=0 R122=1 R156=0 | R6=0 R121=1 R157=0 | R3=1 R124=0 R158=0 |
|
|
・
ようやく安くなってきたのでEDOメモリ16M×2を買う。計64Mになる。やっとスワップアウトしない環境になった。ちなみに会社ではP6の64MマシンにNT40WSを入れているが、立ち上げた時点でメモリはぎりぎりであり、何かAPPを動かすとスワップの嵐である。気づくと使用メモリが90Mを超えていたりする。
都合により、I2Cのブロックリードを試す。本当はクロックジェネレータをいじりたかっただけなのだが、どうやら今使っているマザーボードにのっているクロックジェネレータはバイトリードを受け付けてくれなかったのだ。やり方はわかっていて、
0x5004にデバイスの番号を2倍+1を書く。(クロックジェネレータは0xd3)
0x5003にダミーデータを書く。
0x5002に0x54を書く。
0x5005にデータのサイズが出てくる。
0x5002をとりあえず読む。
0x5007を読むたびにデータが順に出てくる。
とりあえずものを作ってみた。 Windows95のDOS窓だけで動作確認している。読むだけなので、システムへの影響はほとんどない。
I2CBLK.EXE
やはり、再配布は禁止しておく。
おっと、プログラムソース(ブロックリードの主要部分)は次の通り。ああ、やっぱり簡単。
#define SMBAdd 0x5000 _outp( SMBAdd+4, ( dva<<1) + 1); _outp( SMBAdd+3, 0); _outp( SMBAdd+2, 0x54); while( 1) { tmp = _inp( SMBAdd); if( tmp & 0x06) break; } if( tmp == 0x04) goto next; size = _inp( SMBAdd+5); tmp = _inp( SMBAdd+2); for( i=0;i<size;i++){ data[ i] = _inp( SMBAdd+7); } printf("DVA = %02X\n", dva); printf("SIZE = %02X\n", size); dump( data, size); next:;
_outp( SMBAdd+4, ( dva<<1)); _outp( SMBAdd+3, Regadd); _outp( SMBAdd+5, count); tmp = _inp( SMBAdd+2); for( i=0;i<count;i++){ _outp( SMBAdd+7, data[i]); } _outp( SMBAdd+2, 0x54); while( 1) { tmp = _inp( SMBAdd); if( tmp & 0x06) break; }
になる。みたい。
ちなみにLM78では1.0℃単位で、LM75は0.5℃単位で温度がわかる。
である。なぜこんな簡単なのに出回っているツールが使えないのかはわからない。そのうち適当なツールを作ろうかと思ったが、私のマシンではCPU温度が正確に測れていない。というのはセンサーがCPUから離れているため。私の場合は特にヒートシンクからも外れてしまっている。これを改善しないと温度センサーの絶対値の意味がない。
#include <conio.h> #include <winbase.h> #define LM78ISAAddr 0x295 #define PIIX4SMBAddr 0x5000 #define LM75No 0x4C //更新処理 void CSMBUSDlg::OnQuery() { // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください int vol1,vol2,vol3,vol4,vol5,vol6,vol7; int fan1,fan2,fan3; int temp; //新しい値を得る _outp( LM78ISAAddr, 0x60); Sleep(100); vol1 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol2 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol3 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol4 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol5 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol6 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); vol7 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); temp = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); fan1 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); fan2 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); fan3 = (unsigned char )(_inp( LM78ISAAddr+1) & 0xFF); m_vol1 = vol1*16; m_vol2 = vol2*16; m_vol3 = vol3*16; m_vol4 = vol4 *16*5000/3000; m_vol5 = vol5 *16*12000/3175; m_vol6 = -vol6 *16*12000/3446; m_vol7 = -vol7 *16*5000/3283; /* m_vol1 = vol1; m_vol2 = vol2; m_vol3 = vol3; m_vol4 = vol4; m_vol5 = vol5; m_vol6 = vol6; m_vol7 = vol7; */ m_lm78_temp = temp; m_fan1 = (fan1 != 255) ? (1350000/fan1/2) : 0; m_fan2 = (fan2 != 255) ? (1350000/fan2/2) : 0; m_fan3 = (fan3 != 255) ? (1350000/fan3/2) : 0; _outp( PIIX4SMBAddr+4, (LM75No<<1)|0x01); _outp( PIIX4SMBAddr+3, 00); _outp( PIIX4SMBAddr+2, 0x4c); Sleep( 100); if( _inp( PIIX4SMBAddr) & 2){ m_lm75_temp1 = _inp( PIIX4SMBAddr+5)*10 + _inp( PIIX4SMBAddr+6)/128*5; _outp( PIIX4SMBAddr, 2); }else if( _inp( PIIX4SMBAddr) & 4){ m_lm75_temp1 = 0; _outp( PIIX4SMBAddr, 4); } //新しい値で描画 UpdateData( FALSE); }
といった手続きで行うことになっている。MSRRing0.TXTに出ていたControlCodeとInBuff、OutBuffというものはDeviceIoControl()で使うものである。
そこで次のようなMSRの読み出しプログラムをさらっと書いてみた。(動くようになるまで結構かかっているのだが...)
これはVariable MTRRを8セット読むプログラムである(Intel P6Family用)。
#include <windows.h> #include <winbase.h> #include <stdio.h> main() { int i; HANDLE hVxD; int InBuff[0x10]; int OutBuff[0x10]; ULONG BytesReturn; hVxD = CreateFile("\\\\.\\msrring0.VXD", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); if( hVxD == INVALID_HANDLE_VALUE){ printf("VxD Open Error%d\n",GetLastError()); exit(1); } for(i=0x200;i<=0x20f;i++){ InBuff[0] = i; DeviceIoControl( hVxD, 2, // control code:Read InBuff, 0x4, OutBuff, 0x40, &BytesReturn, 0); printf("%04X %08X:%08X\n", i, OutBuff[2], OutBuff[1]); } CloseHandle(hVxD); }
ちなみにライト系は
InBuff[0] = iMSRAdd; InBuff[2] = iMSRHigh; InBuff[1] = iMSRLow; DeviceIoControl( hVxD, 3, // control code:Write InBuff, 0xC, OutBuff, 0x0, &BytesReturn, 0);
のようになる。
ここまでで動くことを確認できたので、ちゃんとした読み書きプログラムを書いてみたのが、これ。MSRを連続して読みこんで表示する、またはレジスタを指定して値を書きこむことができます。どこのアドレスにどのようなレジスタがあるかはIntel
Architecture Software Developer's Manual Volume3のAppendix B(Intel CPUの場合)などをお調べください。今のところWindows95/98のMS-DOSプロンプトでしか動きません。NTに関しては研究中。
またMSR自体はPentium以降のCPUにあり、このツールが使えますが、CPUのモデルにより内容が違います。PentiumやK6-2/3にどのようなMSRがあるかは調べてみてください。
MSRrw98.exe(34K)
フリーウェアとして使用料は無料としますが、配布不可にしておきます。
このプログラムを使った結果がどうなろうと製作者は一切責任を負いません。すべての責任は使用者で負っていただきます。CPUIDもなにも見ていないし、MSRアドレスの範囲チェックも行っていないので、なにも知らずに使うと青画面連発となることでしょう。
使い方(Windows95/98編):
MSR read/write Ver.1.00 MSRrw R Add1 Add2 : Read MSR Add1 to Add2 MSRrw W Add RegHigh RegLow : Write MSR Add RegHigh:RegLow
ここからは本来の目的であった「P6family」のMTRRに関して書いておく。
MTRRはMSRの0x200から0x20Fに設定する。まずはそこを読み出してみる。うちでは
MSRRW98 R 200 20F MSR read/write Ver.1.00 0200 00000000:00000006 メインメモリ(00000000-07FFFFFF) 0201 0000000F:F8000800 0202 00000000:E2000000 82443BX Processor to PCI Bridge(with GART support)(E2000000-E27FFFFF) 0203 0000000F:FF800800 0204 00000000:E2800001 同上(E2800000-E2FFFFFF) 0205 0000000F:FF800800 0206 00000000:E3000001 82443BX AGP controllerとRAGE PRO(E3000000-E37FFFFF) 0207 0000000F:FF800800 0208 00000000:E6000001 Voodoo Graphics 3D Accelerator(E6000000-E6FFFFFF) 0209 0000000F:FF000800 020A 00000000:E6000000 同上(E6000000-E6000FFF) 020B 0000000F:FFFFF800 020C 00000000:00000000 未使用 020D 00000000:00000000 020E 00000000:00000000 未使用 020F 00000000:00000000
と出た。隣には使っているデバイスを書き加えてある。レジスタは2つ1組で、1つ目の0000000X:XXXXX000がベースアドレス、00000000:000000XXがメモリのタイプを表す。メモリのタイプは
0 Uncacheable(UC)
1 Write Combining(WC)
4 Write Through(WT)
5 Write Protected(WP)
6 WriteBack(WB)
2,3,7-255 Reserved
となっている。
2つ目は0000000X:XXXXX000がマスク、00000000:00000800のビットが有効=1/無効=0を示している。
例えば上の例で、
0206 00000000:E3000001 0207 0000000F:FF800800とあるが、これはメモリのE3000000からE37FFFFFをWriteCombiningにするという意味である。上ではE6000000からE6000FFFが他と重なっているが、このようにWCとUCが重なったときはUCになる、とDeveloper's Manualには出ている。
MSRRW98 W 200 0 0とする。とたんにめちゃくちゃ遅くなるだろう。なんせL1キャッシュが効いていないのだから。戻すには
MSRRW98 W 200 0 6だ。(ライトバックである)
と、ここまでやっておきながら、私の場合は新たに設定してもさっぱり効果が見られなかった。元々必要そうなところ(RagePROとVoodoo)にはWCの設定が入っちゃってるので仕方がないか。
#include <windows.h> #include <winbase.h> #include <stdio.h> main() { DWORD i; HANDLE hVxD; DWORD InBuff[0x10]; DWORD OutBuff[0x10]; DWORD BytesReturn; //ドライバの名前とオープンのパラメータが違う hVxD = CreateFile("\\\\.\\msrtouch", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hVxD == INVALID_HANDLE_VALUE){ printf("device Open Error %d\n",GetLastError()); exit(1); } for(i=0x200;i<=0x20f;i++){ //InBuffの順番が違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ InBuff[1] = i; DeviceIoControl( hVxD, 0x85002000, //コントロールコードが違う(Read) InBuff, 0x10, OutBuff, 0x10, &BytesReturn, 0); //OutBuffの順番も違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ printf("%04X %08X:%08X\n", i, OutBuff[2], OutBuff[0]); } CloseHandle(hVxD); exit(0); }
ちなみにライト系は
//InBuffの順番が違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ InBuff[1] = iMSRAdd; InBuff[2] = iMSRHigh; InBuff[0] = iMSRLow; printf("%04X %08X:%08X\n", InBuff[1], InBuff[2], InBuff[0]); DeviceIoControl( hVxD, 0x85002004, //コントロールコードが違う(Write) InBuff, 0x10, OutBuff, 0x10, &BytesReturn, 0);
のようになる。
これを動かすにはドライバを組み込んで再起動する必要がある。この点については下の配布版を参照。
ちゃんと動くことを確認できたので、簡単な読み書きプログラムを書いてみたのが、これ(WindowsNT用)。MSRを連続して読みこんで表示する、またはレジスタを指定して値を書きこむことができます。どこのアドレスにどのようなレジスタがあるかはIntel
Architecture Software Developer's Manual Volume3のAppendix B(Intel CPUの場合)などをお調べください。
MSRrwNT.exe(35.5K)
※公開当時のものとは変更してVer.1.01になっています。
フリーウェアとして使用料は無料としますが、配布不可にしておきます。
このプログラムを使った結果がどうなろうと製作者は一切責任を負いません。すべての責任は使用者で負っていただきます。CPUIDもなにも見ていないし、MSRアドレスの範囲チェックも行っていないので、なにも知らずに使うと青画面連発(=再起動)となることでしょう。
使い方(WindowsNT編):
MSR read/write for NT Ver.1.01 MSRrwNT R Add1 Add2 : Read MSR Add1 to Add2 MSRrwNT W Add RegHigh RegLow : Write MSR Add RegHigh:RegLow
ここからは私の会社マシン(WindowsNT,PentiumPRO)に入れてみたときの話を書いておく。グラフィックボードはMillennium4Mである。
MTRRはMSRの0x200から0x20Fに設定する。まずはそこを読み出してみる。
MSRRWNT R 200 20F MSR read/write Ver.1.00 0200 00000000:00000006 メインメモリ(00000000-03FFFFFF) 0201 0000000F:FC000800 0202 00000000:00000000 未使用 0203 00000000:00000000 0204 00000000:00000000 未使用 0205 00000000:00000000 0206 00000000:00000000 未使用 0207 00000000:00000000 0208 00000000:00000000 未使用 0209 00000000:00000000 020A 00000000:00000000 未使用 020B 00000000:00000000 020C 00000000:00000000 未使用 020D 00000000:00000000 020E 00000000:00000000 未使用 020F 00000000:00000000
と出た。単にメインメモリ(64Mバイト)をライトバックにしてるだけ。レジスタは2つ1組で、1つ目の0000000X:XXXXX000がベースアドレス、00000000:000000XXがメモリのタイプを表す。メモリのタイプは
0 Uncacheable(UC)
1 Write Combining(WC)
4 Write Through(WT)
5 Write Protected(WP)
6 WriteBack(WB)
2,3,7-255 Reserved
となっている。
2つ目は0000000X:XXXXX000がマスク、00000000:00000800のビットが有効=1/無効=0を示している。
例えば上の例で、
0200 00000000:00000006 0201 0000000F:FC000800とあるが、これはメモリの00000000から03FFFFFFをWriteBackにするという意味である。
MSRRWNT W 202 0 40000001 MSRRWNT W 203 F FFC00800としてみる。なんとなく速くなった気分。なんかわかりやすい違いはないかと探してみると、ウインドウの内容を表示したままドラッグが明らかに速い。今まではウインドウの跡の書き換えがもたついて白く残像が残っていたのが、ほとんどなくなってごく普通に使えるようになった。明らかな改善である。
250 06060606:06060606 258 06060606:06060606 259 01010101:00000000 268 05050505:05050505 269 00000000:00000000 26a 00000000:00000000 26b 00000000:00000000 26c 00000000:00000000 26d 00000000:00000000 26e 00000000:00000000 26f 00000000:00000000だった。頭の640K空間はライトバック、VRAMはWC、VIDEO BIOSとSCSI BIOSはライトプロテクト、他はキャッシュしないになっている。まあ効果はわからないが、
259 01010101:01010101 269 06060606:06060606 26a 06060606:06060606 26b 06060606:06060606 26c 06060606:06060606 26d 06060606:06060606 26e 06060606:06060606 26f 06060606:06060606としてみた。
0FE 00000000:00000508 MTRRcap 2FF 00000000:00000C00 MTRRdefTypeMTRRcapの0400ビットはWCをサポートしている、0100ビットはFIXED MTRRをサポートしている、08はVariable MTRRの使える数を示している。
msrrw98 W 202 00000000 E6000000 Intel 82443BX Pentium(r)II Processor to PCI bridge(with GART support) msrrw98 W 203 0000000F FFE00800 msrrw98 W 204 00000000 E6200001 同上 msrrw98 W 205 0000000F FFE00800 msrrw98 W 206 00000000 E2000001 Intel 82443BX Pentium(r)II Processor to AGP controllerと msrrw98 W 207 0000000F FF800800 RAGE PRO TURBO AGP 2X(English)(DirectX) msrrw98 W 208 00000000 E5000001 Voodoo Graphics 3D Accelerator msrrw98 W 209 0000000F FF000800 msrrw98 W 20a 00000000 E5000000 同上 msrrw98 W 20b 0000000F FFFFF800 msrrw98 W 20c 00000000 E6400001 Monster Sound II Multifunction Parentと msrrw98 W 20d 0000000F FFF80800 Monster Sound II PCI Audioと Adaptec AHA-2040/AHA-2040W PCI SCSI Controllerと TVチューナー&ビデオキャプチャボードGV-BCTVシリーズと PCI Fast Ethernet DEC 21143 Based Adapter
ようやくやる気になってきたので試してみた。アドレスは0x50から0x57だ。LM75と似たような感じで、バイトアクセスするとよい。それが本当のやり方かどうかはわからないが。つまり、
0x5004にデバイスの番号を2倍+1を書く。(例えば0xa1)
0x5003に読みたいSPDレジスタの番号を書く。
0x5002に0x48を書く。
0x5005にデータが出てくる。
実のところ0x5002に書くアクセス方法を何にするべきなのかがよくわかっていない。というか、それぞれのアクセス方法の違いがわかっていない(PIIX4の仕様書にも詳しくは出ていない)。まあこれで読めるのでいいだろう。
これを128バイト分、手で入れるのはさすがにつらいのでプログラムを作ってみた。コンソールアプリで、実行するとSPDデータ128バイトを8つ読み取る。エラーになった場合は飛ばしている。たぶん出てくるのは実装メモリのスロット数分だけで、他はエラーになると思われる。Windows95のDOS窓だけで動作確認している。読むだけなので、システムへの影響はほとんどない。
SPDREAD.EXE
やはり、再配布は禁止しておく。
DVA = 50 0000 : 80 08 04 0C 09 02 40 00 01 A0 80 00 80 08 00 01 0010 : 0F 04 06 01 01 00 06 F0 90 00 00 1E 14 1E 3C 10 0020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0030 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 CB 0040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 06
使えそうなデータは
0x02 Fundamental memory type (FPM, EDO, SDRAM..)
0x0B DIMM Configuration type (non-parity, ECC)
0x11 # of Banks on Each SDRAM Device
0x12 CAS# Latencies Supported
0x09 SDRAM Cycle time , CL=X (highest CAS latency)
0x0A SDRAM Access from Clock (highest CAS latency)
0x17 Min SDRAM Cycle time at CL X-1 (2nd highest CAS latency)
0x18 SDRAM Access from Clock at CL X-1 (2nd highest CAS latency)
0x19 Min SDRAM Cycle time at CL X-2 (3rd highest CAS latency)
0x1A Max SDRAM Access from Clock at CL X-2 (3nd highest CAS latency)
0x13 CS# Latency
0x14 Write Latency
0x1B Min Row Precharge Time (Trp)
0x1C Min Row Active to Row Active (Trrd)
0x1D Min RAS to CAS Delay (Trcd)
0x24-0x29 Access Time from Clock for CAS# Latency 1 through 7
0x7E Intel specification frequency
0x7F Intel Specification CAS# Latency support
辺りか。
詳しくはSPDの仕様書P.11からとか、440BXの仕様書のP.106あたりを見て欲しい。
これはSPD(というROM)にそう書かれているというだけで、実際のメモリの仕様を必ずしも示しているわけではないし、今のBIOSの設定などには全く関係していないことに注意。まあBIOSもこれだけを頼りにメモリ設定しているわけではないので、そんなに気にするようなものではないのかもしれない。
おっと、プログラムソースは次の通り。ああ、とっても簡単。
#include <conio.h> #include <stdio.h> #define SMBAdd 0x5000 void dump( char *, int); void main() { char data[ 256]; int Regadd; int tmp; int dva; for( dva=0x50; dva<0x58; dva++) { for( Regadd=0; Regadd < 128; Regadd++) { _outp( SMBAdd, 0x01); _outp( SMBAdd, 0x01); _outp( SMBAdd, 0x02); _outp( SMBAdd, 0x02); _outp( SMBAdd, 0x04); _outp( SMBAdd, 0x04); _outp( SMBAdd+4, ( dva<<1) + 1); _outp( SMBAdd+3, Regadd); _outp( SMBAdd+2, 0x48); while( 1) { tmp = _inp( SMBAdd); if( tmp & 0x06) break; } if( tmp == 0x04) goto next; data[ Regadd] = _inp( SMBAdd+5); } printf("DVA = %02X\n", dva); dump( data, 128); next:; } } void dump( char *memadd, int size) { int i,j; for( i=0; i<(size/16); i++) { printf("%04X : ", i*16); for( j=0; j<16; j++) { printf("%02X ", memadd[ i*16+j] & 0x00FF); } printf("\n"); } }
・
https://p205tb16.ninja-x.jp/pc/all3.html
坂井瑞穂