始めに
Tang Nanoという小さくて安価なFPGAボードで何かできないかというシリーズの第2弾。第1弾のSubleqという1命令CPUを作ったのですが、なかなか動作に癖があり、プログラミングというよりパズルを解いているようになってしまいます。もう少しCPUらしいものは作れないかと探すと、TTLでstack machineを作っている人がいました。これならレジスタの実装も要らなく、命令数を少なくすることで、Tang Nanoに載せられそうな大きさにできそうです。ということで、前作のSubleqで作ったUART利用のモニタ機能をそのまま使い、RTLを作成して動かしてみました。
参考ページ
SiPeed Tang Nanoの環境構築(Windows編)
Sipeed Tang Nanoで遊んでみる (Linux版)
GOWIN Semiconductor Corp.(IP仕様書等:要登録)
必要なもの
- Windows10 PC
- Tang Nano
- USB typeCケーブル
- Gowin IDE (windows 10版)
- Teratermか、シリアル通信ソフト
Stack machineをTang Nanoに焼くまで
FPGAのIPをセットアップするところまでは、Tang Nanoで1命令CPU Subleqを動かすで書いた手順と全く同一です。そこまでが終了していることを前提とします。
githubからファイル一式をクローンします。windowsのgitを使うか、別途linuxでgit cloneしてディレクトリごとコピーしてください。
この中にはasm,sim,src,toolとありますが、srcのみを使用します。srcは以下のファイルリストになります。
clkgen.v
dram.v
iram.v
ramblk.v
sm_logics.v
sm_status.v
sm_top.cst
sm_top.sdc
sm_top.v
uart_controller.v
uart_if.v
uart_logics.v
これらのファイルをIDEに登録してください。以下のVerilog Filesというところを右クリックするとAdd Fileというメニューがでるので.vファイルをすべて登録してください。.cstファイルはPhysical Constraints Files、.sdcファイルはTiming Constraints Filesに登録してください。
ここまで来たら、processタブで、Synthesize、Place&Route、Program Deviceで焼くことができます。
接続はteratermを使用します。Tang NanoをUSBで接続した状態で、teratermを開きます。最初の通信相手の選択で、メニューの下の方にCOMポートの欄があります。ここが選択可能になっており、かつ、Tang NanoのCOMポートが選択できればOKで、それを選択して立ち上げます。
使用方法
操作はターミナル上で行います。仕様上の制約と思われるのは、キー入力のエコーバックが1入力分ずれます。しかも次のキャラクタの入力で、そのキャラクタがTang Nanoに受信されるように見えます。コツとしては、スペースを打つと、Stackmachineは無視するので、何かわからないときはスペースを打ってみると前の入力がエコーバックしてきます。(Bugfixしました。2021/8/22)
本Stack machineの仕様とUart monitorの使用方法です。gitのreadmeをそのまま引っ張ってきたので、へたくそで申し訳ありませんが、英語です。
Specification:
- 8bit data stack machine archtecture with uart debugger
- Instruction: 8bit or 16bit word length
- 8 instructions available
- Instruction memory: 8bit 256words : all for instructions
- Data: 8bit length
- Data stack 31 steps: because of Tang Nano's capacity of logics
- Data register: reg_a and reg_b 8bit rength
- Data reg_a is set stack's pop'ed data
- Data reg_b is set reg_a's data when pop stack
- Uart: controlling load programs, reading wiriting memory, excecutions, and monitoring
Instructions:
- 1st byte 7:4 : opecode
- 1st byte 3:0 : control bits
2nd byte 7:0 : Immediate value or jump address (2byte instruction only)
opecode: 0 : JMP
Jump command controlled by flag bits
bit 3 : Stack Underflow : 1: data stack underflow : can be cleard by CLR
bit 2 : Stack Overflow : 1: data stack underflow : can be cleard by CLR
bit 1 : Carry : 1: previouse calculation results carry
bit 0 : Zero : 1: previouse calculation results zero value
calculation: ADD SUB CMP only
none : Immediate Jump
2nd byte : Jump addressopecode 2 : POP
Pop 1 value from data stack and store reg_a
reg_b also stored reg_a's previouse valueopecode 4 : PUSH
Push 1 value to data stack
value can be used as reg_a, reg_b and Immediate
bit 1: reg_b selected
bit 0: reg_a selected
none : Immediate value selected
2nd byte : Immediate value (when immediate selected)opecode 6 : ADD
Add reg_a and reg_b or Immediate value, push result to data stack and change flags
bit 0: Add reg_a and reg_b
none : Add reg_a and Immediate
2nd byte : Immediate value (when immediate selected)opecode 8 : SUB
Subtract from reg_a to reg_b or Immediate value, push result to data stack and change flags
bit 0: Subtract from reg_a to reg_b
none : Subtract from reg_a to Immediate
2nd byte : Immediate value (when immediate selected)opecode a : SUB
Subtract from reg_a to reg_b or Immediate value, and only change flags
bit 0: Subtract from reg_a to reg_b
none : Subtract from reg_a to Immediate
2nd byte : Immediate value (when immediate selected)opecode c : OUT
Pop a data and output poped data to port#'s port, reg_a and reg_b also changed as POP
2nd byte : port# ( only port 0 is impremented for LED )opecode e : CLR
Clear data stack pointer to zero and clear all flags to zeroopecode f : NOP
Only step PC up
Uart monitor
Uart monitor can use to control CPU, read/write memory, monitor CPU status.
Control commands
g XX : Execute CPU form address XX
w XX : Write instruction memory from address XX
r XX YY : Dump instruction memory between XX and YY
p : Dump data stack memory
s : Step CPU execution
t : Trash and fill 0 to instuction memory, data stack, registers, flags
q : Quit : using g and w
Command g and s : Output log to uart. Each instruction makes log
incuding PC, instruction bytes, flag, reg_a, reg_b, stack pointer
Command r and p : Dump memory with 4 bytes per line.
プログラムの作り方
toolにperlで書いた簡単なアセンブラを置きました。asm2.plです。perlのある環境で、アセンブラのファイルを食わせるとバイナリ列を吐き出します。asmの下にあるファイルはすべて変換が可能です。これをもとに書いてみて下さい。Lチカなどあります。
これを実機で動作させる場合は、以下のようにバイナリ列をコピペしてください。
w 00
<バイナリ列をコピペ>
q
g 00
これで動作させることができます。uart monitorはスペースとCRを無視してくれるので、
asm2.plが吐くCRの多いテキストもそのままコピペできます。
動かしてみてください。
最後に
このRTLですが、ここから少しでも論理を増やすと配置エラーとなり、Tang Nanoで動かなくなります。もうこのFPGAでは限界かなと思っております。次はもう少し規模の大きなものに挑戦したいので、どのFPGAがよいか物色中です。