CPU設計を行うにあたり、検証に必要なフレームワークを構築する。
RTLで記述されたCPUは、シミュレーション中にログを出力し、同じプログラムをISSでも実行する。 この2つのログを比較して、正しくRTLが動作しているかを検証する訳だが、この場合に何をどのように比較するかが問題になる。
何をどのように比較するか
CPUの場合、比較対象として、
- 実行命令のプログラムアドレス (正しくフェッチされているか、分岐命令は正しく処理されているか、飛び先は間違いないか)
- 実行命令の書き込みレジスタアドレス (正しく命令はデコードされているか)
- 実行命令の書き込みレジスタデータ (正しく計算はされているか、正しくメモリアクセスは実行されているか)
- 実行命令のメモリストアデータ (正しくメモリストアは実行されているか)
などが基本だと思う。さらに、今回はアウトオブオーダプロセッサを実装するということもあり、検証が面倒になりそうな
- 実行命令の書き込みレジスタのリネームID
- 実行命令が書き込んだことにより解放されるリネームID
を比較しようと思う。
比較対象
RTL側のログ
現在設計しているRISC-V対応CPUのRTLは、以下のようなログを出力する。
315000000 0 [00000200] 00008197 : AUIPC r 3,0x00008 ( 0,34) : R 3<=00008200 335000000 1 [00000204] e1018193 : ADDI r 3,r 3,0xe10 ( 1, 0) : R 3<=00008010 335000000 2 [00000208] 0000c117 : AUIPC r 2,0x0000c ( 2,33) : R 2<=0000c208 345000000 3 [0000020c] e0010113 : ADDI r 2,r 2,0xe00 ( 3, 2) : R 2<=0000c008 345000000 4 [00000210] 000000b3 : ADD r 1,r 0,r 0 ( 4,32) : R 1<=00000000 355000000 5 [00000214] 00000233 : ADD r 4,r 0,r 0 ( 5,35) : R 4<=00000000 355000000 6 [00000218] 000002b3 : ADD r 5,r 0,r 0 ( 6,36) : R 5<=00000000
左から順に、
- 命令コミットが発生したときの時間
- 実行命令番号
- プログラムアドレス
- 命令コード
- 命令ニーモニック
- 書き込み先レジスタのリネームID (レジスタ書き込みが発生する命令のみ)
- 書き込み先レジスタの解放リネームID (レジスタ書き込みが発生する命令のみ)
- 書き込みレジスタアドレス (レジスタ書き込みが発生する命令のみ)
- 書き込みレジスタデータ (レジスタ書き込みが発生する命令のみ)
の情報が表示されている。
ISS側のログ
現在開発しているRISC-V対応んCPUのISSは、以下のようなログを出力する。
0:M:MBar:[00000200][P00000200] 00008197 : auipc r03,0x00008 ( 0,34) r03<=00008200 1:M:MBar:[00000204][P00000204] e1018193 : addi r03,r03,0xe10 ( 1, 0) r03=>00008200 r03<=00008010 2:M:MBar:[00000208][P00000208] 0000c117 : auipc r02,0x0000c ( 2,33) r02<=0000c208 3:M:MBar:[0000020c][P0000020c] e0010113 : addi r02,r02,0xe00 ( 3, 2) r02=>0000c208 r02<=0000c008 4:M:MBar:[00000210][P00000210] 000000b3 : add r01,r00,r00 ( 4,32) r00=>00000000 r00=>00000000 r01<=00000000 5:M:MBar:[00000214][P00000214] 00000233 : add r04,r00,r00 ( 5,35) r00=>00000000 r00=>00000000 r04<=00000000 6:M:MBar:[00000218][P00000218] 000002b3 : add r05,r00,r00 ( 6,36) r00=>00000000 r00=>00000000 r05<=00000000 7:M:MBar:[0000021c][P0000021c] 00000333 : add r06,r00,r00 ( 7,37) r00=>00000000 r00=>00000000 r06<=00000000
左から順に、
- 命令実行番号
- マシンの実行レベル (M)
- MMUの変換方式
- プログラムアドレス
- 物理アドレス変換後のプログラムアドレス
- 命令コード
- 命令ニーモニック
- 書き込み先レジスタのリネームID (レジスタ書き込みが発生する命令のみ)
- 書き込み先レジスタの解放リネームID (レジスタ書き込みが発生する命令のみ)
- 命令実行にあたり、読み込まれるレジスタ情報
- 命令実行にあたり、書き込まれるレジスタ情報
比較スクリプト
これらの2つのトレースデータを読み込んで、正規表現にて情報抽出を行い、1行ずつ比較を行えば良い。
$ ../sim/rtl_iss_compare.rb coremark.normal.log sim_inst.log # coremark.normal.log:ISSの実行ログ, sim_inst.log:RTLの実行ログ
実行結果は、例えば以下のようになる。
132 : 000033ac reg[06] <= 00000001, reg[06] <= 00000001 133 : 000033b0 134 : 000033b4 135 : 000033b8 reg[11] <= 00000002, reg[11] <= 00000002 136 : 000033bc reg[10] <= 00000001, reg[10] <= 00000001 137 : 000033c0 138 : 000033c4 reg[10] <= 00000002, reg[10] <= 00000002 139 : 000033c8 reg[10] <= 00020000, reg[10] <= 00020000 -.-[COUNT]--[ PC ]---.-[ REG WRITE ]-.---.---.--- 140 : 000033cc reg[10] <= 00000002, reg[10] <= 00000002 141 : 000033d0 ERROR : release register is different C-MODEL(141) : reg[14] <= 00000004(55) || RTL-MODEL(141) : reg[14] <= 00000004(15) INSTRUCTION COUNT = 141
141行目で間違えた。解放レジスタのリネームIDが間違っている。デバッグしなきゃ。
このようにして、CPUの検証作業の手間を大幅に削減できる。こうやって、RTLの設計時間を短縮していこう。