公開日:2026/04/04
title.png

38th Season


#38-9 週刊「スタックマシンを作る」創刊号

 新たに、スタックマシンと呼ばれる方式の、新規CPUコアを設計してみたいと思います。
 本HPにて、Cmod A7ボード(FPGA)を使って開発しているオリジナル16ビットCPUコアMoscoviumは、汎用レジスタを使って処理を進めるCPUなので、汎用レジスタマシンと呼ばれます。スタックマシンは、汎用レジスタマシンとは異なる考え方に基づくCPU方式です。

 新たにCPUコアを起こそうと考えた動機や、汎用レジスタマシンとスタックマシンの違いなどのお話から始めましょう。

開発の動機

 動機は、先日入手したShrike-Lite(下図)のFPGA(SLG47910)へ、Moscovium用に作成した周辺I/Oユニットを移植して活用したいと思った事に遡ります。

a382_shrike.jpg

 Shrike-LiteにはRP2040というMCUが搭載されているので、FPGAの活用方法を以下図の様に想定しました。

a389_bridge.png

 上図の通り、RP2040とインターフェイスするUART等の通信ユニットと、肝心な周辺I/Oユニットとの間の橋渡しをするため、FPGA内にもCPUを搭載する構成です。
 CPUは単に、UARTがRP2040から受信したコマンドに基づいて周辺I/Oユニットを操作し、必要ならその結果をUARTへ返してRP2040へ送信するだけですので、特別な機能や性能は必要ありません。

周辺I/Oユニットの候補

 FPGA(SLG47910)に搭載する周辺I/Oユニットの候補と、その論理規模(LUT数等)を以下表にまとめておきます。

周辺I/Oユニット LUT数 FF数 備考
非同期シリアルUART8N1ユニット 290 246 RP2040との通信用
システムタイマSYSTIMユニット 253 253  
ΔΣDA変換器DAC121ユニット 47 40  
実時間時計RTC400Sユニット 284 153  
サウンドジェネレータSNDG1PBユニット 202 128  

※LUT数/FF数は、Cmod A7ボード(FPGA)+Vivadoでの論理合成結果であり、参考値。

 現時点ではFPGA(SLG47910)への移植未済の状態なので、あくまで候補としてリストアップしました。1,120LUTの小さなFPGA(SLG47910)に載るかどうかも含めて検討が必要だと考えています。

Tennessineはどうか?

 8ビットデータパスなのでプログラミングし難く、あまり使っていませんが、Moscoviumシリーズの最小CPUコアとしては、Tennessineコアが存在しています。Tennessineの論理規模は約1,300LUTです。

 今回のFPGA(SLG47910)は最大1,120LUTなので、LUT数が不足です。

 現在手持ちの最小コアであるTennessineでも、大きすぎると判りました。しかも、前節の表に挙げたような周辺I/Oユニットを搭載する余裕も必要なので、もっと小さいCPUコアが必要となりました。

スタックマシンZPUとの出会い

 本HPでTennessineを設計した時、論理規模を比較・評価する為に出会ったスタックマシンがZPUです。

 出会った時の感想は、「その手があったか」と言う感じでした。

レジスタファイルが不要

 スタックマシンは、Moscoviumの様な汎用レジスタマシンと異なり、レジスタファイル(下図、参考)が必要ありません。

a154_rgf.png

 上図の通りレジスタ数も多いし、読み出しバスや書き込みバスなどの制御で、相当量の論理規模が推量されます(∵巨大なセレクタの塊)。更に、命令コードにも影響が及びます。

 命令コードの中には、演算や処理の対象とするレジスタ番号フィールドが存在します。汎用レジスタが×8個ならレジスタフィールドは3ビットですが、×16個なら4ビット、×32個なら5ビットが必要です。更に、1つの命令で指定すべきレジスタ数が2個なら×2倍、3個なら×3倍のレジスタフィールドが必要です。

  例)ネイティブARM(32ビット命令コード)の場合

※MIPSアーキテクチャでは32個の汎用レジスタがあり、ARM同様3レジスタ演算命令も存在するため、命令コード中のレジスタフィールドは最大で5ビット×3レジスタ=15ビットもあります。繰り返しになりますが、命令コードが32ビット長なので、15ビットのレジスタフィールドは屁でもありません。

 スタックマシンには汎用レジスタが存在しないので、この様な大量のレジスタフィールドが必要ありません。例えば、命令コードを8ビットに押し込む、等と言う、大幅な痩身が可能となるのです。命令コードが短くなれば、命令デコーダなどの論理規模も小さくなると期待できます。

 つまり、スタックマシンは汎用レジスタマシンと比べて、CPUの論理規模を削減する目的に対して非常に有利なアーキテクチャなのです(その手が在ったか)。

 ZPUに戻ると、「GCCツールチェーンが使える」という謳い文句で32ビットデータパスを採用しているため、32ビットデータパスの分、回路規模は大きく、論理規模の比較では、我がTennessineに軍配が上がっています。Tennessineでも大きすぎるくらいなので、当然、ZPUでも解になりません。

 今回、最大1,120LUTと言う小規模なFPGA(SLG47910)に載せるため、もっと小さなCPUが必要となりました。こちらの周辺I/Oユニット1〜2個も一緒に搭載できる必要があるので、CPUコアに許容される論理規模は、500LUT未満が目標です。
 これが、16ビットデータパス、8ビット命令コードのスタックマシンを設計する動機です。従って、今回設計するCPUコアは論理規模の小さいことが正義であり、処理速度は二の次、三の次として設計を進めます。

スタックマシン

 詳細設計に入る前に、ざっと、スタックマシンの動作原理について解説しておきます。

演算命令

 スタックマシンには汎用レジスタが存在しません。その代わりにスタックをCPUの内部占有資源として内蔵しています。スタックマシンに於いては、スタックへ積んだデータに対する演算によって処理が進んで行きます。

 同じく、スタックを使った計算方式として、逆ポーランド記法(RPN;Reverse Polish Notation)が有名なので、この方式に倣っておこうと思います。

  逆ポーランド記法:

 減算など、2項が非可換な演算の場合、記述順に注意してください。


 データは記述した順(左から右)にスタックへ積まれるため、(A+B)×(C−D)を計算する様子は以下図の様になります。

a389_rpnopr.png

 演算命令は上図の如く、スタックから2数を取り出して、演算し、結果をスタックへ積む、という動作の繰り返しとなります。

演算以外の命令

 演算以外の命令も、スタックを介した処理となります。以下に一部例を示します。

  例)演算以外の命令

命名Samarium

 オリジナル16ビットCPUコアMoscoviumの時には、Micro Controllerの頭文字Mcを元素記号とするモスコビウムから命名しました。今回の新規CPUはスタックマシンである事が特徴の一つなので、Stack Machineの頭文字Smを元素記号とする、サマリウムから命名しようと思います。

 サマリウムは、原子番号62、希土類元素、ランタノイド、放射性物質☢️、α崩壊でNd(Neodymium)になる、等の特長を持った元素です。

 以降、設計する新規CPUを、オリジナル極小CPUコアSamariumと称します。


 CPUって「作って終わり」とはならず、アセンブラやライブラリなどの開発環境を揃えたり、ROM/RAM等のメモリや周辺I/Oモジュールなども揃えなくてはなりません。万一、考え抜けやバグが見つかれば、影響を最小化しながらの修正を余儀なくされます。新規CPUを起こすという事はリスクである訳です。リスクを許容して先へ進みます。


btn_arduino.png

btn_prev.png btn_next.png

home