Tang Nanoで1命令CPU Subleqを動かす

#始めに
Tang Nanoという小さくて安価なFPGAボードで何かできないかと思いました。CPU自作などというのは非常に手間がかかる上に、Tang Nanoには載りませんでしたというオチになりかねないので、考えあぐねていると、原理上特殊な複合命令を1命令でCPUができるということを思い出し、調べてみると[Subleq](https://esolangs.org/wiki/Subleq)という1命令CPUに行き当たりました。これは良いということで、[以前作成したUARTループバック](https://qiita.com/yoshiki9636/items/cabcd0c62ea97472b51c)を使ってコントロールするSubleqプロセッサを作ってみました。コード量は1000行を超えるので、[githubに置きました。](https://github.com/yoshiki9636/subleq)ソースを読みたい方は本文にはソースを載せないので、そちらを見てください。本文ではSubleqをTang Nanoで動かすまでと、操作方法について述べたいと思います。

#参考ページ

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

[Subleq](https://esolangs.org/wiki/Subleq)

[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か、シリアル通信ソフト

#SubleqをTang Nanoに焼くまで
まずは、[このサイト](https://qiita.com/tomorrow56/items/7e3508ef43d3d11fefab)のようなTang Nanoの立ち上げサイトでIDEのセットアップとテストをしてください。次に、[このサイト](https://qiita.com/ciniml/items/05ac7fd2515ceed3f88d)にある方法で、USBのuartを有効化してテストください。ここまで終了していることを前提にします。
まずは、Gowinを立ち上げ、新規プロジェクトを作成します。FPGAはGW1N-LV1QN48C6/I5を設定してください。

![コメント 2020-06-03 220351.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/07766384-8bbe-e5d2-5647-094468f2be61.jpeg)

次にIPの設定をします。今回使用するIPはOSC、PLL、UART masterの3個です。
Tools→IP Core Generatorで、IPコアジェネレータを起動します。

![コメント 2020-06-04 120827.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/93fea510-eac6-be58-dcd1-f38d9f1d55bf.jpeg)

IPコアの一覧が出るので、CLOCKをクリックすると、CLOCK系のIPが出ます。
まずOSCを入れるので、クリックします。分周値を入れることができるので、2を入力してOKを押します。GW1N-LV1QN48C6/I5は内部オシレータは240MHzとのことなので、2分周で120MHzになります。

![コメント 2020-06-03 221653.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/93300182-f1b6-60f5-c985-73f630ee770f.jpeg)

次にrPLLをクリックします。rPLLは設定できる項目がたくさんありますが、基本的には入力クロック周波数と出力クロック周波数の設定のみで使用できるようです。入力クロック周波数に、先ほどのOSCの120MHzを入れて、出力にUART masterで使用する50MHzを入力します。

![コメント 2020-06-03 221842.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/e5268892-df1b-807d-32ea-895c4aba7c51.jpeg)

最後にUART masterを設定します。リストの一番下にUARTがあります。パラメータ表示のうち、周波数は50MHzから動きません。どうやら、これがIPが使用する内部クロックで変更不可のようです。もうひとつのボーレートを使いたいものに合わせます。いろいろと試したところ、115200は動かず、57600と9600は動いているので、その間は動くと思われます。

![コメント 2020-06-03 222012.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/8cb1a3bc-7edf-9c47-24fc-ab1426e12c18.jpeg)

これでIPの設定は終わりです。

ここまでは、[「Tang NanoでuartのIPコアを動かした件」](https://qiita.com/yoshiki9636/items/cabcd0c62ea97472b51c)と同一です。

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

https://github.com/yoshiki9636/subleq

この中にはsim,src,syn,uart_loopbackとありますが、srcとsynのみを使用します。srcとsynの中のファイルを１つのフォルダに集めてください。以下のファイルリストになります。
clkgen.v
controller.v
led_io.v
subleq_ram.v
subleq_regs_exec.v
subleq_status.v
subleq_top.v
uart_if.v
subleq.sdc
subleq_top.cst
これらのファイルをIDEに登録してください。以下のVerilog Filesというところを右クリックするとAdd Fileというメニューがでるので.vファイルをすべて登録してください。.cstファイルはPhysical Constraints Files、.sdcファイルはTiming Constraints Filesに登録してください。以下のような表示になります。

![スクリーンショット 2020-09-14 211439.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575990/e5937ccc-eb1d-2983-d40d-99153df83086.jpeg)

ここまで来たら、processタブで、Synthesize、Place&Route、Program Deviceで焼くことができます。

接続はteratermを使用します。Tang NanoをUSBで接続した状態で、teratermを開きます。最初の通信相手の選択で、メニューの下の方にCOMポートの欄があります。ここが選択可能になっており、かつ、Tang NanoのCOMポートが選択できればOKで、それを選択して立ち上げます。

#使用方法
操作はターミナル上で行います。~~仕様上の制約と思われるのは、キー入力のエコーバックが１入力分ずれます。しかも次のキャラクタの入力で、そのキャラクタがTang Nanoに受信されるように見えます。コツとしては、スペースを打つと、Subleqは無視するので、何かわからないときはスペースを打ってみると前の入力がエコーバックしてきます。~~(コードを修正しました。2021/8/22)

まず、本Subleqの仕様です。

- データ長　8bit
- アドレス　8bit ( 0x00 - 0xff )
- メインメモリ　256 byte ( 8bit × 256 address )
- I/O オンボードRGB LED点灯　（アドレス0xfd,0xfe,0xffに0xffを書き込むと点灯）

コマンド類はすべて独自仕様で、独断と偏見で実装しました。以下、コマンドのusageです。
使われる数字はすべて2桁の16進数で、英字はすべて小文字です。

q：　w,gコマンドでストップさせるのに使用。

w：　メモリライトコマンド
    usage : w XX DD DD DD .... q
　　XX : ライト先頭アドレス
　　DD : データ（1byte単位でスペースを打つとわかりやすい）
　　q  : ライトを終了するときに打つ

r：　メモリリードコマンド
　　usage : r XX YY 
　　XX : リード先頭アドレス
　　YY : リード終了アドレス
　　ダンプが3byteづつ表示されます。なぜ3byteかというとSubleqの命令が3byteで読みやすいからです。

g：　連続実行コマンド
　　usage : g XX  .... q
　　XX : ジャンプアドレス　ここから実行します。
　　q  : 実行を終了します。
　　実行中は7byteの実行ログが出続けます。Byteは順に
　　[PC] [オペランド1] [オペランド2] [オペランド3] [読み出し1] [読み出し2] [減算結果]

s：　１ショット実行　現在のPCから１命令実行します。
　　usage : s
　　実行ログはgコマンドと同一フォーマットで出力されます。

t：　メモリ消去　256byteすべてに0x00を書き込みます。
　　usage : t

#最後に
まだ作ったばかりで、プログラムもろくに書いていませんが、サンプルプログラムができたら、この記事にアップデートしていこうと思います。