comproc-project-evolution-ideas

ComProc プロジェクトの進化アイデア

ComProc プロジェクトは筆者が主導するコンパイラと CPU を両方作るプロジェクトです。

ComProc CPU は当初はシンプルでしたが、タイマや UART 通信などの周辺機能が追加されていき、この春に A/D コンバータも仲間入りしました。そのため、最近では ComProc マイコン(MCU)と呼ぶことも多くなってきました。この記事では、マイコンとしてさらに高性能化・高機能化するために欲しい機能を考えてみました。

進化アイデアのリスト

コンパイラ関連

  • 分割コンパイルのサポートとリンカの作成
  • コンパイラへの最適化機構の追加

CPU コア

  • メモリ領域の拡大
  • ベースアドレスレジスタの追加
  • SDRAM の読み書き

フラッシュメモリ

  • 初期プログラム読み出し
  • データの永続化
  • SD カードアクセス
  • FAT ファイルシステムの読み書き

周辺機能

  • VGA 出力
  • ADC 高速化
  • PWM 生成
  • I2C/SPI 通信
  • ロータリエンコーダ入力

各アイデアの詳細

いくつかのアイデアについて、詳細に説明します。

分割コンパイルのサポートとリンカの作成

現在、ComProc コンパイラは 1 つの .c ファイルのみを受け付けます。 そのため、複数のプログラムで共通に使うコードも毎回コピーしなければならず、面倒ですしバグの修正も難しくしています。 分割コンパイルをサポートすることで、ComProc マイコン向けのプログラム開発が効率化できます。

分割コンパイルをサポートするには、コンパイラの改良はもちろんですが、リンカを作る必要があります。 分割コンパイルといいつつ、複数の .c ファイルを結合して 1 つのファイルにしてコンパイルする、という簡易な手法ではリンカは不要ですが、学習目的のプロジェクトですから、リンカも作ってみたいなと思います。

コンパイラへの最適化機構の追加

現在はほとんど最適化をしていません。そのため、冗長なアセンブリが出力されることが多いです。

例えば if 文などの条件式の生成では、必ず push 0、neq、jz という命令列を出力します。 push 0、neq を出力するのは、jz 命令がスタックトップの最下位ビットだけを見てジャンプするか否かを判断するためです。 条件式に 0/1 以外の値が来るかもしれない場合、push 0、neq により 0/1 に変換するのです。 C 言語で書けば if (condition != 0) と書くようなものですね。 condition に 0/1 以外の値が来ても、!= 0 により 0/1 の値に強制されます。

ただ、condition が元々 0/1 に制限される場合には push 0、neq は不要です。 例えば a > b などの関係演算子は 0/1 を出力します。 条件式の部分で生成される命令列を見て push 0、neq を出力するかどうかを制御する最適化が考えられます。

その他にもたくさんの最適化がありますので、それらを実装していきたいというのが、このアイデアです。

メモリ領域の拡大

現状は 4KB のメモリ領域しか使えません。これを増やしたいというアイデアです。Tang Nano 9K には 468K ビット = 58.5KB の BRAM が搭載されていますので、これを活かしたいです。ただし、Tang Nano 9K の BRAM は 9 ビット幅で作られているため、8 ビット幅のメモリとして使うと 52KB しか使えませんが。まあでも、4KB に比べたらとても大きいです。

分岐命令の即値幅 12 ビットに合わせて 4KB にしているのですが、別にそこは合わせる必要はありません。スタックに分岐先アドレスを積んでから即値無し分岐命令を発行すれば任意の場所にジャンプ可能です。

データメモリとしての使用が問題です。現状では、データメモリは 0x100~0x2FF までを使っています。メモリの先頭付近にあるのは、即値幅 10 ビットのロードストア命令でアクセスできる範囲にしたかったからです。もし 1KB よりも後ろにあるメモリをデータ領域として使いたければ、現状、即値無しロードストア命令を使うしかありません。メモリ読み書きは多用されますので、即値無しロードストア命令ではかなり効率が悪いのです。

ベースアドレスレジスタの追加

これは上述の、メモリを増加させるとメモリ読み書きの多くが即値無しロードストア命令になってしまい、効率が低下する問題に対処するアイデアです。16 ビットのベースアドレスレジスタを用意し、即値付きロードストア命令の即値と加算して最終的なメモリアドレスを計算する仕組みです。ベースアドレスレジスタを用いたアドレス計算はロードストア命令のみ有効で、分岐命令では利用されません。

FPGA のリソースを節約するために、ベースアドレスレジスタのビット幅はもっと小さくするかもしれません。ロードストア命令の即値幅は 10 ビットですから、ベースアドレスレジスタを 6 ビットにまで小さくし、アドレスの上位 6 ビットを保持すれば十分です。この場合、ロードストア命令の即値を simm10(符号付き)から uimm10(符号無し)へと変更することも同時にやりたいです。原理的には base + simm10 でもアクセスできないメモリ範囲は発生しないのですが、それだとプログラマは混乱を招きます。例えばメモリ範囲の末尾付近のアクセスで困ります。base に最大値(3F)を設定しても末尾 512 バイトの範囲がアクセスできず、base=0 として負方向へのオーバーフローを利用する必要が生じます。uimm10 であれば素直にアドレッシング可能です。

見方を変えると、ベースアドレスレジスタはページングの仕組みとも考えられます。メモリ領域を 1KB のページに分け、base でページ番号を指定、ロードストア命令の即値でページ内オフセットを指定していると考えることができます。

SDRAM の読み書き

Tang Nano 9K には 64M ビット = 8MB の SDRAM が搭載されています。これを使うことができれば、ComProc マイコンにとって非常に広大なメモリ領域を手に入れることができます。大きなプログラムやデータのために使えるのはもちろん、VGA 出力用のフレームバッファを置く場所として今のところ最有力の候補です。ただし、16 ビットアーキテクチャでは素直には 64KB の範囲しかアドレッシングできないため、どのように 8MB を生かすかを考える必要があります。

初期プログラム読み出し

このアイデアはかなり優先度の高いものです。現状の ComProc マイコンは、電源を切ると走らせていたプログラムが消えてしまいます。そのため、再起動のたびに PC から UART 経由でプログラムを転送しなおす必要があります。永続化された領域にプログラムを格納しておき、リセット時に永続領域から RAM へとプログラムをロードするのが、このアイデアでやりたいことです。一般に、これは IPL(Initial Program Loader:初期プログラムローダー)と呼ばれるプログラムによって実行されます。

Tang Nano 9K にはオンボードで 32M ビットの PUYA P25Q32U フラッシュメモリが搭載されています。FPGA チップから見ると外側にあり、FPGA とは SPI で通信します。加えて、FPGA(GW1NR-9)内にも 608K ビットのフラッシュメモリが内蔵されていて、こちらも IPL の保存先として利用可能です。このどちらかに IPL を格納しておくという案が有力候補です。

IPL は CPU が実行する必要があるため、一般には CPU のアドレス空間に ROM を接続して実現します。CPU のアドレス空間に接続されていれば、CPU が直接実行することができるわけです。しかし、ComProc マイコンのアドレス空間にはもちろんそんな ROM は接続されていません。そのため、FPGA の回路としてフラッシュメモリから IPL を読み出す仕組みを作る必要があります。このフラッシュメモリ読み出し回路は、ユーザープログラムがフラッシュメモリを読み書きするときにも使うことができるため、製作価値は高いです。

IPL は永続領域の固定アドレスに書いておくのが普通のやり方です。古い PC であれば、これは MBR(マスターブートレコード)と呼ばれる、HDD や SSD の先頭 512 バイトの領域でした。これはシンプルで分かりやすいので、ComProc でも似た仕組みにしようかなと思っています。フラッシュメモリの先頭に IPL を書いておくのです。

データの永続化

ComProc マイコンで動くプログラムからフラッシュメモリの読み書きをするというのがこのアイデアです。これができれば、ComProc マイコンを搭載したロボットを動かす間にセンサーから読んだ値やプログラムの動作ログのようなデータを永続化しておき、後で PC に接続してデータを吸い出すようなことができます。

この機能を付けたら、次はファイルシステムを構築したくなります。ファイルシステム無しでは、フラッシュメモリのどこ(どのアドレス)に何のデータがあるか、プログラマが把握する必要があります。固定長のデータを置くだけならそれで十分かもしれませんが、データが伸長していくならファイルシステムが欲しくなります。それに、ユーザープログラムから openwrite が使えるということにロマンを感じますね。

また、この機能は「初期プログラム読み出し」アイデアを実現するのにも重要です。IPL 自身や IPL が読み出すためのプログラムをフラッシュメモリに書き込む必要があるからです。ComProc マイコン上で動くプログラムがフラッシュメモリを読み書きできれば、IPL(あるいは IPL が読み出すためのプログラム)をフラッシュメモリに書くためのプログラムを作れます。

SD カードアクセス

ComProc マイコンを実装している FPGA ボード Tang Nano 9K には SD カードスロットが実装されています。それを活用し、ComProc マイコンと PC 間でファイル受け渡しをしてみたいです。PC 側で SD カードにアプリケーションを書き込み、それを ComProc マイコンで実行し、実行結果を SD カードに書き、それを PC で開く、という流れが実現できたらとても楽しいと思います。

MMC/SDCの使いかた によれば、SD カードは SPI 通信で読み書きできるようです。転送速度は遅いでしょうが、小さなファイルの読み書きであれば気にならないと思いますし、何しろ自作マイコンでのアクセスですから、簡単であることは好ましいです。

ということで、SD カードアクセスは SPI 通信の周辺機能に依存しています。先に SPI 通信を作る必要があります。

FAT ファイルシステムの読み書き

SD カードと関連することとして、FAT ファイルシステムの読み書きを行うドライバ(ソフトウェア)を用意したいです。ファイルシステムを介さず、純粋に SD カードのブロックをアクセスするのでも SD カードの読み書きはできます。しかし、PC 側でそのまま認識してファイルをコピーできるような SD カードにするためには、FAT ファイルシステムにしたがった読み書きをしなければなりません。

自作 OS の MikanOS で FAT32 ドライバを実装したので、その経験が活きるでしょう。コードが再利用できるかは難しいところです。MikanOS は C++ での実装のため、そのままでは ComProc マイコンで動かせません。ComProc コンパイラは C のサブセットだからです。しかも構造体さえサポートされていません。ComProc コンパイラを先に改良するか、貧弱なコンパイラで FAT ファイルシステムのドライバを作るか、悩ましい…。

VGA 出力

ComProc マイコンから 640×480 ピクセルのグラフィックを出力するというアイデアです。VGA 端子を介してディスプレイに絵が表示できれば、ComProc アプリケーションの幅が広がります。また、テキスト表示に限ったとしても、PC 無しで多くの情報を表示できるようになり、デバッグに役立つかもしれません。

640×480 ピクセルのグラフィックを表示するためには、グラフィックデータを保持するメモリ領域(フレームバッファ)が必要です。1 ピクセル 1 バイトとして計算すると 300KB になります。BRAM は 52KB しかないため、必然的に SDRAM を使用することになります。また、300KB は 16 ビットアドレス空間で扱える最大値 64KB を大きく超えており、どのように扱うかは問題です。

PWM 生成

PWM 波形を生成できると、NeoPixel に代表されるアドレサブル RGB LED を駆動したり、モーターの速度や LED の輝度を調整したり、LPF を介してアナログ電圧を出力したりといった用途に応用できます。モーターのような、比較的低速の PWM 波形で良い場合は、専用の回路を用いずにソフトウェアから GPIO を ON/OFF するのでも目的を達成できるかもしれません。しかし、アドレサブル RGB LED を駆動するためには数 100ns のパルスが必要となり、GPIO のソフトウェア制御では厳しいです。

多くのマイコンには、タイマ機能の 1 つとして PWM 波形機能があります。タイマのカウンタがオーバーフローして 0 に戻った際に PWM 出力ピンが 0 となり、タイマが閾値を超えたときに PWM 出力ピンが 1 になる、というような仕組みです。閾値レジスタの設定値を 0~タイマのカウンタの最大値まで可変させることで、デューティー比を 0%~100% の間で可変させられます。この仕組みを ComProc マイコンにも搭載したいです。

おまけ:OSC 展示の話

2024 年 3 月 10 日に開催されたOSC(オープンソースカンファレンス)2024 Tokyo/Spring にて ComProc プロジェクトの展示を行いました。新作の A/D コンバータもここでお披露目しました。筆者の X ポスト

ちぇりーたくあんさん(ちぇりーたくあんのWebサイト)と共同出展でして、非常に賑やかなブースになりました。ちぇりーさんの NAND Only CPU「NLP-16A」の製作途中の最新状態を動く状態で見ることができる、ある意味貴重な展示となりました。高層ビルの完成一歩手前を見ることができるのは、その瞬間しかありません。

OSC のような「展示会」は、一般に展示者と見学者の間の会話がほとんどです。しかし、私は OSC が見学者同士でもわいわい盛り上がれる場になったらいいなと思っています。かつて私が属していた OSASK コミュニティでは、コミュニティメンバーが何人も OSC に来場し、普段はメールの向こうにしか居ない人たちとわいわいできました。そういう雰囲気が復活したらいいなあと思っています。「OSC に行けば誰かと会えるかもしれない。少なくとも川合さん(ブース主)とは会える!他の人と会えなくても多数の展示を見学することは出来るので無駄にはならない。取りあえず行ってみよう」てな感じの心持ちだったかもしれません。

例年、東京での OSC 開催は春と秋の 2 回あります。私としては 2024 年秋にも出展したいなあと思っていますので、皆様も、積極的に次の OSC 東京開催にいらっしゃってください。もし私のブースが無くても、他に面白いブースがたくさんあるはずですし。


作成:2024-03-14 15:02:36

最終更新:2024-04-16 08:38:55