CPU実験室

誰も見向きもしない古いCPUをいじって動かしてみようというプロジェクトです

CPUID命令

CPUの識別情報を取り出すためのCPUID命令を実行してみました

・・・"CPUID"はちょっとタイプミスすると"CUPID"になってカワイイ。

当然Cでは記述できないのでインラインアセンブラレジスタから大域変数にコピーしてます

x86系インストラクションとしてのCPUID命令はi486プロセッサの後期から実装され、Pentiumプロセッサから正式アナウンスされたとあります。手元のIntel486DX2 MicroProcessor Data Book 1992Feb.preliminary版のインストラクションセットには記載がありません

インテル® プロセッサの識別とCPUID命令アプリケーションノート485 にフォーマットの説明があり

サポートされないはずですがEAX=0で呼び出してインテルのベンダID:”GenuineIntel”、EAX=1でプロセッサシグネチャを引き出せています

そういえばインテルPCIボードのベンダIDは”8086”だったような・・・

プロセッサシグネチャは”43x”487またはDX2またはDX2ODP。ステッピング5が認識されました

CPUIDは先代のi486ボードでも確認していて、ステッピング6だったので今回のCPUはちょっと古かったようです。さらにEAX=1でEDXに返される機能コードでページサイズ拡張機能PSEのフラグも変わってますがこんな重要な機能がステッピング違いで変わっていいのか謎です

LSI-C86プログラム

前項のLEDチカチカのCソースコードに全く手を加えずLSI-C86コンパイルしてみました。アセンブリ中間コードはこんな感じです。x86のリアルモードならどのCPUでも動くはずです

ループ構造はGCCと同じくこれ以上簡単にならない出来ですが重要なのはoutp()関数の処理です

LSI-Cではinp()outp()関数はマクロ定義されているのでインラインでそのままコード展開されて非常に高速です。最下位ビットでチカチカ280kHzになりました

 

 

GCCプログラム

電源配線を強化してから動作は安定するようになったようです。LEDチカチカで長時間ランニングテストをやってますが暴走したり勝手にリセットは起きていません。

たとえば簡単なCソースコード8255PAにインクリメントコードを出力

これをDJGPPコンパイルアセンブリ中間コードはこうなりました

アセンブル後にスタートアップ、ボードハード固有関数群のライブラリ、printf系サブセットモジュールをリンクして最終的に4096バイトのバイナリになります

スタートアップはここで作ったものと同じものでリアルモードからプロテクトモードに切り替えてmain関数を呼ぶものです。OSは無いのでプロテクトモード自体は重要ではないですがプリフィックス無しで32ビットレジスタが扱えるようになります

実行させるとPAの最下位ビットが約62.5kHzでトグルしました。思ったより遅いですが_outpモジュールの中で何か面倒なことをしてるのかもしれません

 

 

痛恨の・・

486CPUの動作とは全く関係のないファン制御に熱中してたのが一段落してその熱も冷め(ファンだけに)さて本筋に戻って486ボード上のアプリに取り組もう、としていたのですが最近どうもボードの動作が変なのです

モニタは起動してアプリもロードできるのに実行するといきなりリセットがかかる、モニタは起動するけどコマンドを打つとリセットする、果てはモニタすら起動しないという致命的な状態に落ち込むことがたびたび起きるようになりました。もともとロジックの設計が悪いとか、どこかが接触不良になってプログラムが暴走してるのかと思いこんだのですが、よくよく調べると実際ハードのリセットラインがドライブされてました

RESETを生成するのは電源監視リセットICのTL7705Aなわけでどうも減電圧検知が動作しているようです。

ボードのパタンを改めて見直してますがVCCラインをハイライト表示すると本当に貧弱です。

VCCネットは12mil(0.3mm)幅のデザインルールで引いていて特に上図のオレンジ矢印のラインはここ一か所にCPUの全電流が流れていることになります。そんなわけで右下の電源供給コネクタと左上のTL7705A付近のVCC電位差が0.3V位あり、さらに実行コードによるCPU電流の変化やファンを回したことによる電流の増加、スイッチングノイズの重畳によってTL7705Aのセンス電圧4.55Vtypを瞬間でも割ってしまったことは十分考えられます。そもそも0.3mm幅パタンに1A流すというのはプリント基板設計での一般的な許容電流とされる1A/mmを超えてしまってます。よく焼き切れなかったものです

GNDネットはペタパタンも併用してこちらは問題ありません。

 

これの対策ですが電源供給コネクタから最も遠いCPUの電源ピンまでバイパスを引くことにします。パタンミスは今までなかったのに、ここで痛恨のジャンパ飛ばし。しかも信号線のようにUEWという訳にはいかず、太めのビニル銅線でやっておきます

ロジックのミスはなかったとは言え電源の引き回しはパタン設計の基本中の基本でした。ただこれ以上太いラインでの引き回しは難しく今後は4層基板が視野に入ってきます

ボード完成

486CPUボードのハード、モニタ・ファンコントローラのファームもできたのでボード完成となります

LEDチカチカのみ実行させて約1A程度流れています

未知のCPUだとここからソフト開発の試行錯誤が始まるところですが、このボードに関してはリアルモードではLSIC-86、MSC/C++。プロテクトモードであればGCC(Djgpp)と開発環境もそろっているのであとはハードの固有部分に合わせたライブラリを作るくらいです

 

コントロールファームFIX

PI制御のオーバーシュートは、起動時してから温度が目標値に達してからはじめてファン制御を開始すれば回避できそうです。またゲインKpが大きいと温度入力のノイズをそのまま増幅してしまうのでこれは小さめに変更。

ということで電源ON後から目標値Sv=40℃の間はファンを停止して自然上昇に任せ2-3分後Svに達したところでKp=1,Ki=1,Kd=0のPI制御を開始した時の温度プロファイルはこうなりました

制御開始直後にハンチングを起こしていますがその後は安定します

ここまでPC上のツールでパラメータを制御していましたが、値が決定したのでこれらの作りをすべてPIC側ファームに組み込み自律的に動作できるようにします。といってもWindowsAPLのタイマイベント内でやったものをPICの1秒間隔のタイマ割込みの中へそっくり移植するだけで温度取得、そこから1スロット分のPID計算、制御量決定、PWM出力を一気にやってしまいます

486CPUからのリクエストで現在温度、現在制御量を返すコマレスI/Fは残しておきますが制御パラメータの変更、ファン強制停止のような自爆系コマンドは念のため操作禁止にしてあります。逆にサーミスタの断線検知(測定温度が超低温にみえる)の場合は強制的にファンを100%全開にして異常レスポンスを返すようにしました。

これらをPIC12F1822インプリメントしてプログラム領域1933word、94%使用。いい感じに収まりました

このうち半分以上の1200wordはAD値-摂氏温度変換テーブル int temp_tbl[]が占めています

温度プロファイル

制御パラメータを変えて温度変化をプロットしてみました

まずP(プロポーショナル)制御のみ、ゲインKp=1の場合です

このファンは不感帯があってDUTY=30%くらい与えないと自力起動できません。温度にオーバーシュートがあるのはそのためです。その後は46~47℃で安定状態になりますが6~7℃の偏差が残ります

このままゲインKp=5に上げてみました。安定状態では42℃程度になりますが偏差はどうしても残ります

 

さらに偏差をキャンセルするためにゲインKI=1として積分項を導入しPI制御にしてみます

これは安定まで時間がかかりました。特に低温状態からスタートすると積分値がキャンセルされるまで大きなオーバーシュートが発生します(制御値が負数になったらファンが逆回転してCPUを温めてくれるわけではないので)その後ハンチングしながら20分くらいかけて平衡状態に達しますが目標値Sv=40℃キッカリで安定します

微分制御についてはもともと温度入力にかなりノイズが乗っていて差分を見ると制御があらぬ方向に行きそうなのでやめておきます。

発熱源(CPU)の短時間変動や環境からくる外乱もあまりないと思われP制御のみで十分でしょう