序文
この記事は主に、C906 のシミュレーション処理中に Printf がターミナル上で正常に印刷できないバグを解決します。
(最近は C906 ベースの Linux システムにも取り組んでいます。興味があれば、星をクリックしてください)
https://github.com/sususjysjy/Linux-on-c906-with-litex.git)
1. オープン-C906
最近、Riscv 上で動作する Linux システムを構築する必要がありますが、オープンソースの Riscv コアは多くなく、MMU の要件も満たす必要があります。Rocket Chip、Vexriscv、Xiangshan も良いのですが、残念ながらどれも Spinal か Scala で使い方がよく分からず、Pingtou Ge のオープンソース CPU しか使えません。
MMU を搭載したオープンソースのものは C で始まるコアしかないため、リソースを比較検討した結果、最終的に C906 を選択しました。
2. C906シミュレーション環境
Pingtouge シミュレーション プラットフォームの構築についてはすでに他のブロガーが詳しく説明していますが、ここでは主に構築後の CASE ルーチンについて説明します。
1.スクリプト修正
まず MAKEFILE を見てみます C906 のデフォルトの sim ソフトウェアは iverilog ですが、コンパイル速度が遅すぎるため、iverilog を vcs に変更してコンパイルします。
################################################################################
# Simulation related
################################################################################
SIM = iverilog
DUMP = off
//修改后
################################################################################
# Simulation related
################################################################################
SIM = vcs
DUMP = on
2.CASEルーチン
まずはC906のCASEをご覧ください。
coremark を実行してみましょう。ターミナルの結果が表示されます。
シミュレーションは成功していることがわかりますが、ターミナルからは出力がありません。coremark ソース ファイルをチェックして、printf コンテンツがあるかどうかを確認してください。
#define FREQ 100000000
vtimer_end= get_vtimer();
vcycles = vtimer_end - vtimer_start;
vcycles = vcycles/iterations;
printf ("\nVCUNT_SIM: CoreMark has been run %d times, one times cost %d cycles !\n",iterations,vcycles);
float score;
// score = FREQ/(float)vcycles;
// printf ("\nVCUNT_SIM: CoreMark 1.0 : %f iterations/sec\n",score); //CoreMark = iterations of a sec
score = 1000000/(float)vcycles; //to relieve relations with FREQ
printf ("\nVCUNT_SIM: CoreMark 1.0 : %f (iterations/sec)/MHz\n",score); //CoreMark = iterations of a sec
sim_end();
コードは実行中のスコア結果を出力しますが、ターミナルはそれらを正しく出力しないため、printf の最下層で定義された印刷レジスタ アドレスをトレースする必要があります。0x6000fff8 であることがわかりますが、同時に tb で指定した印刷アドレスが同じであるかどうかも調べる必要があります。
int fputc(int ch, FILE *stream)
{
asm(
"li x13, 0x6000fff8 \n\t"
"sw %0, 0(x13) \n\t"
: :"r" (ch): "x13" );
}
else if((cpu_awlen[3:0] == 4'b0) &&
(cpu_awaddr[31:0] == 32'h10015000) &&
cpu_wvalid)
実際、ここで問題が見つかりました。基礎となるライブラリによって定義されたアドレスは 0x6000fff8 で、データの読み取りのために Axi バスによって監視されるアドレスは 0x10015000 です。この 2 つは対応できないため、printf を実行すると、正しいアドレスを持つレジスタは次のようになります。アドレスを読み取るための読み取りではありません。当然、ターミナルからの出力はありません。
3.バグ修正
そこで最初に思いつくのは、2 つのアドレスを同じになるように変更することで、両方を 0x10015000 に変更して、CASE を再度実行します。
それでも印刷されないのは不思議です。
理由を確認してください。出力されたアドレスは、tb 内のアドレスや、c910 コアで使用されるアドレスであってはなりません。関数の書き込みはfputc
キャッシュで停止することなく先頭に到達する必要があります (したがって、キャッシュできない領域になければなりません)。マニュアルには、仮想メモリを使用しない場合は PMA 設定が存在できると記載されておりC906_RTL_FACTORY/gen_rtl/mmu/rtl/sysmap.h
、今まで0x8fffffff
その領域はキャッシュ可能であることがわかりました (c910 の設定は異なります)。その後、 まで0xbfffffff
キャッシュできなくなります。
印刷したアドレスはキャッシュ不可領域に定義する必要があるため、アドレスが大きくなってしまいました。0x8fffffff,我们将打印地址设置为0x90000000,重新运行CASE。
OK、ターミナルに正常に出力できます。!