FPGA Tang Nanoでstack machine CPUを動かす

#始めに
Tang Nanoという小さくて安価なFPGAボードで何かできないかというシリーズの第２弾。第１弾の[Subleqという1命令CPU](https://qiita.com/yoshiki9636/items/458057b608ecf939590e)を作ったのですが、なかなか動作に癖があり、プログラミングというよりパズルを解いているようになってしまいます。もう少しCPUらしいものは作れないかと探すと、TTLでstack machineを作っている人がいました。これならレジスタの実装も要らなく、命令数を少なくすることで、Tang Nanoに載せられそうな大きさにできそうです。ということで、前作のSubleqで作ったUART利用のモニタ機能をそのまま使い、RTLを作成して動かしてみました。

#参考ページ

[Tang Nanoで1命令CPU Subleqを動かす](https://qiita.com/yoshiki9636/items/458057b608ecf939590e)

[Tang NanoでuartのIPコアを動かした件](https://qiita.com/yoshiki9636/items/cabcd0c62ea97472b51c)

[SiPeed Tang Nanoの環境構築(Windows編)](https://qiita.com/tomorrow56/items/7e3508ef43d3d11fefab)

[Sipeed Tang Nanoで遊んでみる (Linux版)](https://qiita.com/ciniml/items/bb9723673c91d8374b63)

[Tang NanoのFPGAとPC間でUART通信をする](https://qiita.com/ciniml/items/05ac7fd2515ceed3f88d)

[GOWIN Semiconductor Corp.(IP仕様書等：要登録)](https://www.gowinsemi.com/ja/)

#必要なもの
- Windows10 PC
- Tang Nano
- USB typeCケーブル
- Gowin IDE (windows 10版)
- Teratermか、シリアル通信ソフト

#Stack machineをTang Nanoに焼くまで
FPGAのIPをセットアップするところまでは、[Tang Nanoで1命令CPU Subleqを動かす](https://qiita.com/yoshiki9636/items/458057b608ecf939590e)で書いた手順と全く同一です。そこまでが終了していることを前提とします。

githubから[ファイル一式](https://github.com/yoshiki9636/stackmachine)をクローンします。windowsのgitを使うか、別途linuxでgit cloneしてディレクトリごとコピーしてください。

https://github.com/yoshiki9636/stackmachine

この中には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で、それを選択して立ち上げます。

#使用方法
操作はターミナル上で行います。~~仕様上の制約と思われるのは、キー入力のエコーバックが１入力分ずれます。しかも次のキャラクタの入力で、そのキャラクタが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 address

- opecode 2 : POP
              Pop 1 value from data stack and store reg_a
              reg_b also stored reg_a's previouse value
              
- opecode 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 zero

- opecode 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がよいか物色中です。