Cmod A7ボード(FPGA)を使って開発しているオリジナル16ビットCPUコアMoscoviumに於いて、ここ1ヶ月ほどスーパスケイラ版の移植に悪戦苦闘していました。ようやく安定して動作できるようになったので、リリースします。
Moscoviumマイコンの16ビット版Moscoviumコアと、32ビット版Nihoniumコアには、それぞれスーパスケイラ版が存在します。
スーパスケイラと言うのは、CPUの命令を実行する回路(これをスロットと呼びます)が2系統あって、1つのCPUで、連続する2つの命令を同時に実行することができるタイプの構造を指します(下図)。
実際に演算を実行するデータパス(ALU;Arithmetic Logic Unit)と、それを制御する制御回路(CTL、有限状態機械)が、それぞれ2個づつ搭載されています。これら2種類のブロックは、全く同じ物を丸々2組搭載すれば良いのであって、回路的にも設計的にも何ら苦労せずに実装することができます。
ただ、簡単なのはここまで。スーパスケイラ版の肝となる回路は何と言っても、フェッチ制御(FCH)ブロックです。
FCHブロックは、連続する2個の命令を同時にフェッチしてきて、2個のスロットに並列発行できるかどうか判断(=デーコード)します。その結果、2個の命令が同時にスロット0,1へ発行されるか、最初の命令だけがスロット0に発行されて次の命令は待たされるかが、決まります。
どのような命令が同時に発行できて、どんな命令は同時発行できないのか?など、スーパスケイラの詳細な解説は、以下記事をご確認ください。
「#20-8 スーパスケイラ」
以下の記事にて説明した様に、VivadoのSTA(Static Timing Analysis)によって明らかになったクリティカルパスを緩和するため、それまでフェッチレイテンシ0という特殊なROMを使っていた回路を、フェッチレイテンシ1という一般的なROMを使用できる様に改定しました。
「#27-5 フェッチレイテンシの設計変更」
上記事で変更したのは、正にスーパスケイラの肝ともいうべき、FCHブロックだったわけです。
フェッチレイテンシ1への変更(上左図 → 上右図)は、IF,IDステージの実行タイミングを1サイクル後ろに倒す変更となるため、FCHブロックに対しては、すこぶる影響大です。通常版(シングルスケイラ)の改定は比較的簡単だったのですが、スーパスケイラ版の改定難易度は×2倍や×3倍では収まらず、×10数倍程に思えました。
全く、「こちら」を修正すると「あちら」が立たず、「あちら」を修正すると「こちら」が立たない、モグラ叩きの様相を呈していました。
フェッチレイテンシが1になったことで、起こしたアクションの結果を刈り取るタイミングが次のサイクルに後ろ倒しとなります。ひっくり返すと、今のサイクルで必要なデータを読み出すアクションを前のサイクルで実行開始しなくてはならないのです。このタイムラグもまた、修正を困難にする大きな要因でした。
通常版の各CPU(Tennessine,Moscovium,Nihonium)が、フェッチレイテンシ1のインターフェイスに変更済みである以上、後戻りすることもできず、泣きそうになりながら改定・デバッグ作業をしていました。
甚く、しんどかった……😱。迂闊に、こんな大掛かりな設計変更をすべきではなかった、です……。
と言う事で、「漸く動いた」時には、初めてスーパスケイラ版が動いた時ほどの達成感が有りました。お疲れさまでした ⇒ 自分m(1−−)m。
シミュレーション検証と言っても、スーパスケイラのシミュレーション云々ではなくて、検証中、命令RAM(I-RAM)の挙動で気が付いたことです。
I-RAMからフェッチして実行中、フェッチアドレスとオペランド書き込みのアドレスが重なると、フェッチの読み出し値が不確定値xとなってしまいました(下図)。
Vivadoが持っている、デュアルポートRAMマクロのビヘイビア記述(動作記述)が、そういう動作になっています。
ここで、上図シミュレーション波形の着眼点について解説しておきます。
確かに、メモリセルの構造から鑑みて、同一アドレスに書き込んでいる、その瞬間に読み出しを実行したら、読み出しデータがどうなるか?は、良く解りませんね……。
デュアルポートRAM引数について検索する(別ウインドウが開きます)
上のリンクで、Xilinxのドキュメントが見つかるはずです。
「先」とか「後」とか言っても、同じクロックサイクル内の先・後なので、サイクルベースの見かけ上は同時に読み/書きしており、かつ、サイクル毎の動作タイミングは、どのモードでも変わりありません。
今まで、デフォルトのNO_CHANGEに設定していたのですが、Xilinxのドキュメントによると、NO_CHANGEモードでは、同時に同一アドレスへ読み/書きした場合、不確定値xが読み出されるらしいです。
同ドキュメントによると、WRITE_FIRSTモードでも不確定値xが読み出されてしまうみたいです。
変な値(不確定値x)を読み出さないようにするには、READ_FIRSTモードを選択するのが正解だと判りました。
書き込みモードは、RAMマクロをインスタンスする時の引数で指定可能です(以下抜粋、実際のコードはmcoc_comn.vを確認してください)。
xpm_memory_tdpram #(
:
: (中略)
:
.WRITE_MODE_A("read_first"), // String
.WRITE_MODE_B("read_first") // String
) iramhm (
:
: (後略)
:
これ、シミュレーションだけの話ではなくて、実物のFPGAに書き込んで動作させた場合にも、同様な動作となるはずですので、用途に合った動作モードを選択して指定しなくてはなりません。
3種類のモードが選択できるようになっている、と言う事は、それぞれに長所・短所があるはずなのですが、Xilinxのドキュメントからは、そこまで読み取れませんでした。ただ、以下の特徴については記述がありました。
デュアルポートRAMマクロに於いて、同一アドレスへの同時アクセス(読み/書き)を処置しなければならないユニットは、Moscoviumマイコンでは命令RAMだけですので、命令RAMの消費電力が多少増加しても許容可能と判断し、READ_FIRSTモードに変更することとしました。
以上の通り、不確定値xが読み出されることが無い様に処置したのですが、以下の仕様制限も設けておいて、二重にガードしておこうと思います。
この制限は十分回避可能(※)な制限なので問題ありません。
※今々フェッチしながら実行中の、正にそのアドレスにデータを書き込むなんて使い方は普通しないし、そんなことをしたら、実行中のソフトウェアの方が破綻するから。
今回までに移植完了したI/Oユニットは以下の通りです。
Cmod A7ボード用Moscoviumマイコンの設計データ(Vivadoプロジェクト)は、GitHubにて配布しております。以下バナーよりアクセスしてください。
今回リリースしたI/Oユニットによって、以下の型名が解禁されました。
デザイン(回路)をCmod A7ボードに書き込む手順については、こちらをご確認ください。
Vivadoでのコンパイル(論理合成・配置配線)結果を以下にまとめます。
コンパイル結果:
スーパスケイラ版では、同時にフェッチした2命令を並列実行できるかどうか、IDステージで復号しているパスが通常版に対して追加となるため、スーパスケイラ×フェッチレイテンシ1への改定でクリティカルパスは強化されているはずです。しかし、コンパイル結果を見る限りタイミング制約はメットしているので、ひとまず安心しました。
通常版Moscoviumコアでのコンパイル結果と見比べてみると、明らかにスラックが低下しています。
一般的に、配置配線ツールはSTAがメットした時点で処理を打ち切ってしまい、それ以上努力しません。つまり、スラックの大小ではクリティカルパスの程度(または余裕度)を測ることはできません。ただ、スラックが10nsもあって、明らかに余裕でメットしていたMoscoviumコアと比べて、スラックが1ns未満まで低下して、やっとメットした感のあるNihonium-SSコアのクリティカルパスが、かなり強化されている(=遅くなっている)ことは想像に難いです。
それでも、特殊なレイテンシ0のROMや、逆相クロックを排除できた利点の方が大きいし(こちらを参照)、何とかメットできているので良しとします。
さて、ここからは実際にCmod A7ボード(FPGA)に回路を書き込んで、実機で動作確認して行きます。
Nihonium-SSコアの動作確認も勿論ですが、前回リリースしたSTWSERユニット(I2C)の動作確認も、一気に実施したいと思います。よって、Cmod A7ボードに書き込むデザイン(回路)は、今回解禁したNSOC113MD0816が適切です。
デザインNSOC113MD0816をCmod A7ボードに書き込んだら、先へ進みましょう。
Nihonium-SSコアの動作確認として、以前作成した円周率の計算プログラムを使います。以下にリンクしておきます。
プログラム:calc_pi_ss.asm
早速、円周率を計算させてみましょう。
実験サンプル:
【pi,5116】
OK+ start calculation
OK+ Klingenstierna's formula
OK+ pi=3.
1415
9265
3589
:
: (中略)
:
0141
6314
9648
OK+ digits=5116 (size=1280)
OK: pi time[us]=0x01a5bf65
Nihonium-SSコアに計算させた円周率5,000桁が、こちらの期待値と一致しました。
この規模のプログラムと、円周率5,000桁分の演算が正しいことが確認できたので、ひとまず、スーパスケイラ版Nihonium-SSコアが正常動作している、と考えて良いでしょう。
実験に際して、Nihonium-SSコアによるブートローダの動作も確認しました。問題なく動作します。
ここから先は、完全なる抱き合わせ動作確認となります。Nihonium-SSコアの動作確認も兼ねながら、前回リリースしてあった、STWSERユニット(I2C)を実機(FPGA)で動作確認しておきます。
I2C接続のセンサモジュールとして、9軸加速度・ジャイロ・磁気センサ(MPU9250モジュール)を接続し、以下プログラムでアクセスできるか?確認して行きます。
プログラム:test_mpu9250.asm
※アセンブルに必要なインクルードファイルなどは、こちらからダウンロードできます。
アセンブルしてブートモードなどで転送すると、シリアルモニタから、こちらのコマンドを受け付けています。
コマンドを実行する前に、以下の接続表に従ってCmod A7ボードとMPU9250モジュールを接続してください。
Cmod A7ボード | 接続 | MPU9250モジュール |
VCC3V3 | → | VCC |
GND | ⇔ | GND |
stws_scl | ⇔ | SCL |
stws_sda | ⇔ | SDA |
× | EDA | |
× | ECL | |
GND | → | ADO |
× | INT | |
VCC3V3 | → | NCS |
GND | → | FSYNC |
Cmod A7ボードのピン配置表は、こちらをご確認ください。
MPU9250は3.3V定格のセンサですので、Cmod A7ボードから3.3V電源を接続して使います。Cmod A7ボードの3.3V電源(VCC3V3)は、PMODコネクタに引き出されています。
以下図に実験中の様子を示します。
※VCC3V3,GNDへ固定する端子(ADO,NCS,FSYNC)は、MPU9250を実装したブレッドボード上で結線しておくと、Cmod A7ボードとの結線は4本(VCC,GND,SCL,SDA)だけで済みます。
実験を進めましょう。
実験サンプル:
【mrd1,75】
OK: rd1[0x75]=0x71
MPU9250のI/Oレジスタ0x75(WHO_AM_I)を読み出しました。読み出したデータ0x71は、MPU9250のIDコードと一致しています。……読み出し成功。
【mwr1,37,02】
OK: wr1[0x37]=0x02
MPU9250内に集積されたAK8963にアクセスするため、MPU9250のI/Oレジスタ0x37(INT_PIN_CFG)のBYPASS_ENビットに1を立てました。
【ard1,00】
OK: rd1[0x00]=0x48
MPU9250内AK8963のI/Oレジスタ0x00(WIA)を読み出しました。読み出したデータ0x48は、AK8963のIDコードと一致しています。……読み出し成功。
OKです。実機(FPGA+MPU9250モジュール)を使って実際のI2Cアクセスが確認できました。単に「シミュレーションで動作確認済み」に比べて、ど〜んと、安心感が増しますでしょう?
今回のお買い物は、以下の通りです。
秋月電子通商でCmod A7ボードと一緒に購入しておいた、400タイポイントのブレッドボードです。
実験の写真に示した様に、センサなど外部回路を接続して使う場合、ブレッドボードにCmod A7ボードを挿して使うのが便利です。そこで、Cmod A7ボード専用のブレッドボードとして購入しておきました。
Cmod A7ボードは48ピンDIPサイズのボードなので、400タイポイントくらいの大きさが無いと挿さりません。それどころかCmod A7ボードを挿してしまうと、ブレッドボードには、ほとんど空きスペースがないため、ジャンパ線で信号線を引き出すくらいにしか使えません……。
端子数が多くてユーザ端子数が多く使える事は良いことだけれど、こんなことなら、ピンヘッダよりもピンソケットをはんだ付けしておいてもらった方が使い易かったな、と思ってしまいました。
何にせよ、スーパスケイラ版CPUコアの移植も完了して、一山越えました。あと、デュアルコア版の移植を完了させたら、Cmod A7ボード特有の機能についての開発に移ることができます。