CPU実験 メモ 思いつくままに書いてみました。なので、順番は考慮していません。 これを読んで、35秒をきってください。 ・初期バージョンのパイプライン仕様は、 IF,ID,EX,WB/MEM,LD1,LD2,LD3,LOADWB メモリアクセス命令以外は、4ステージで実行が完了。メモリアクセス命令は、 LDパイプライン(MEMステージ以降)に送られる。遅延ロード採用、ディレイドスロット3段。 これをベースに改良を行っていった。この時点での動作速度は300秒。 インストラクションキャッシュは搭載していた。 ・分岐をIDステージに持っていくことにより、ディレイドスロットを1段に。 20秒ぐらい縮まる。また、ロードの遅延を減らしていった。これにより、260秒程度で動作するように。 ・データキャッシュの効果は絶大。16KBのデータキャッシュを搭載したところ、 260秒が120秒で動作するようになった。データキャッシュは、インプリメントを容易にするため、 IDステージでアドレス計算、EXステージでキャッシュからロードという形にした。 ・ディレイドスロットを、パイプラインを IF/ID,EX,WB という三段構成にすることにより、消去。これにより100秒をきった。 ディレイドスロットをなくすためには、Branch Predictionの方が有効である (クロックを速くすることができる。) アドレス計算はIF/IDステージ、ブランチもIF/IDステージ。 ・複数ステージでレジスタ読み込みを行うと、フォワーディングが複雑に。 当然重くなる。なので、IDステージで生成したフォワーディング情報をEXステージでも 使えるようにした。 ・インストラクションキャッシュがない構成では、遅延ロードや ディレイドスロットの採用は有効であろう。しかしながら、インストラクションキャッシュが ある構成では、遅延ロードなどは、キャッシュ効率を悪くする。インタロック機構を採用し、 キャッシュ効率をよくしたほうが動作速度が速くなるかもしれない。ミスペナルティは絶大。 ・コンパイラが優れていれば、インストラクションはだいたいキャッシュに載ってしまうので、 インストラクションのブロックサイズはあまり重要でない。ウェイ数も同様。 ・データキャッシュは、連続番地のアクセスが多いので、ブロックサイズを増やすことは有効。 シミュレーション結果により、ミスペナルティの問題などを考えると、ブロックサイズは4が最適。 データアクセスのパターンをシミュレータ上で観察してもらったところ、ウェイ数はそれほど影響を与えない。 ならば、インプリメントが容易でパスが短いダイレクトマップ方式が有効か。 ・ハザードは何も考えないと、3億回は生じる。即値の扱いを工夫したり、データキャッシュを工夫することにより、 ハザードは3000万回程度まで減らすことができる。ただしハザードを消すのはクロックとのトレードオフ。 ・外部基板には、7segmentの発光ダイオードをたくさん乗せると便利かもしれない。それがなかったので、 アドレスはCPU基板の8個のLEDを眺めながらデバッグ。最後のほうは、それで十分だった。 要するに、CPUと心が通じ合うように・・・ ・USBとの通信は要注意。USBからは非同期な信号がやってくるから、メタステーブル現象には十分な対策を。 ・fdiv、fsqrtは重くてもよいから(10レイテンシ程度でもよい)ハードウェアで実装した方がよい。 なぜならば、関数呼び出しのコストがなくなるし、キャッシュ効率がよくなる。 ・0レジスタは、レジスタ番号が0のときは、そのレジスタのWriteEnableをアサートしないようにすればよい。 ・実験用基板は、CLKFXの出力を使うとなぜか不安定(今原因調査中) なので、動作周波数は、50MHz以下、50MHz、100MHzのどれかしか使えないと思って設計した方がよい。 Multicycleで低速クロック、 Scalar,Superscalarで50MHz、 Superpipelineで100MHz。 これのいづれかになると思う。100MHzでSuperscalarができればすごい。 VLIWはかなり有効だと思われる。予想では、Superpipelineで100MHzを出せれば、27秒から30秒程度の速度がでると 思う。根拠は、もしウルトラヒエラルキーをSuperpipeline化したら、フォワーディング不可能なものが増えて、 またfadd,fmulのレイテンシが1増えると予想されるので、それで54秒程度だからである。手動配置を極めれば、 今のウルトラヒエラルキーのアーキテクチャをそれほど崩さずに純粋に100MHzできるかもしれない。 ・SRAMは曲者。よくデータシートを読んでおく。また、ラッチをはさむ。ラッチをはさむ! SRAMへのクロックは、90度位相を前にずらしたクロックや、ピンをFAST指定することにより ちょっと速く出すようにすると問題が解決できるかもしれない。ただし、早くしすぎると たいへんなことに。 ・画面が真っ暗なら、分岐命令を疑う。演算もあやしい。 ・簡単なプログラムが動くのに、そもそも描画まで始まらない場合は、ジャンプ命令も疑った方がいいかもしれない。 ・オプコードが違っていたり、オペランドの並びが違っていたりすると当然うごかない。 ・キャッシュのストール機構についてはよく考えないと、バグの原因。 ・フォワーディングユニットがおかしいと、描画まで行かないかもしれない。 ・ストール信号をLEDに表示させてみると便利。 ・fsqrtは間違っていてもそれらしい画像はでる(月面着陸トロン) ・ftoiが間違っていると、画面にゴミなドットがでてしまうかもしれない。 ・fadd、fmulは、シミュレータにレイトレでの計算を一通り出力してもらって、それで検証するのがよい。 ・faddやfmulが違っていると、めちゃくちゃな画像がでることがある。あるいは真っ暗。 ・今回のCPUでは、デコーダにはROMを利用。しかし、デコードステージでいろいろ するなら、ROMは遅いかもしれない。オプコードをよく考える必要があるかも。 ・いきなり大きな仕様のプロセッサを作ると、原因の特定がしにくい。 最初に簡単なパイプラインの仕様で作って、USB周りの実装はしたCPUを作ることにより、 組み合わせ回路のデバッグをできるようにしておくのが吉。 ・描画の途中で、再現性がなくとまる場合は、SRAMやUSBとの通信があやしい。 この周りをチェックしてなおバグが出る場合は、制約で特定のパスに、1クロック分よりもおおい 長さを指定していないかチェック。TIMESPEC TPTHRUを使ってfaddなどのパスを 3クロック分に指定したとしても、なぜかうまく処理されないことがある。その場合は、 faddをパイプライン化して、すべてのパスが動作周波数を満たすようにすれば動くかもしれない。 ・シミュレータは、計測機能や拡張性を重視したものかつ動作がそれなりに高速なものを作ってもらうとよい。 平木班の場合は、シミュレータが高機能・高速だったので、すぐに機能を検証することができた。 シミュレータでないと、命令数をカウントしたりできない。シミュレータによって、どこを 改良すれば動作速度に直結するかわかる。汎用プログラムでは有効な手段も、レイトレでは 有効でないかもしれない。それを事前にチェックする。 ・データキャッシュは、16Kbと32Kbでは、1秒程度速度が変わった。ただし、32Kbつむと 回路がきつきつになる。 ・BlockRAM,Embedded Multを手動配置するだけでも、コンパイル速度が速くなる。 ・ISE6.1iだと、乗算器は、 C <= A * B; と記述すると合成される。 ・仕様書は特にオペランドの順序、オプコードに注意して作る。仕様は変更があることも多いと思うが、 そのときは、コンパイラ、シミュレータ、アセンブラを同時期に変更するようにすれば、 紛らわしくならない。掲示板などを活用して、情報が伝わるようにする。