Tang-Nano-9Kを使い倒して、ワンチップで(今更)DOSを動かす

# 目的
　「[CP/M-68K](https://qiita.com/hi631/items/dd2eb4f89e73a66f532f)」の稼働により、モトローラ系の16ビットCPUは制覇した。
　次はインテル系に挑戦だな。
　CP/M-86でも良かったのだろうが、ここはワンクラス上を目指すかな。
　◆◆◆　そうだ、Ｍ＊ＤＯＳを動かしてみよう　◆◆◆
　Tang-Nano-9Kに入る切るかどうかが心配だが。
　ワンチップでは無いと言われそうだが、機能はGW1NRの中に全て納まってるのでワンチップと言い張るゾ。
![dos_start.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/ae662f1b-fb47-3eb3-42aa-cfa37d1f184f.jpeg)

# 経緯
　ＭＳＤＯＳは昔は誰でもご存じだった、Microsoft社製のパソコン用ＯＳ。
　　※ライセンス違反にならない様に、動作確認はFreeDOSで行っています。
　FPGAへのDOSのインプリメントは、「[前回](https://qiita.com/hi631/items/d948d38c25a411d28f2b)」行った経験が有るが、問題は必要なLUT個数。
　10000LUT～15000LUT程度必要となりそうだが、Tang-Nano-9Kは8640LUT。
　　※9000LUTは無いのに9Kとは、まあ四捨五入すればそうだが。
　そこで容量を食っているキャッシュと、DOSの動作に必須でないものは削除し辻褄合わせ。
　　※キャッシュだけで2000LUT位使っている様。
　　※sound関係はバッサリ削除、追加すると使用率が10%程度UPする。
　その結果、下記に示す機能を有するシンプルなシステムに仕上がった。
　＜TN9-DOS諸元＞
　　□８０８６ＣＰＵ　クロック１８ＭＨｚ
　　□メインメモリ　　１ＭＢ、ＤＤＲＲＡＭ
　　□外部記憶装置　　１２０ＭＢ（マイクロＳＤ）
　　□ＨＤＭＩ表示　　ＶＧＡ画面をＨＤＭＩ接続にて表示。
　　　　　　　　　　　キャラクター８０ｘ２５、グラフィック３２０ｘ２００（２５６色）
　　□キーボード　　　ＰＳ２キーボード（１０６ＪＰ日本語仕様）
　LUTの使用率は85%前後で収まっている。
　まあショボいといわれるとそれ迄だが、Tang-Nano-9Kで動いただけでも評価して欲しいな。
　装置外観写真を下記に示す、
　左上はPS2キーボード接続用のコネクタ。上部に見えるのが本家本物(?)の8086。
　　※左上はキーボードを接続して居るが、無くとも起動は出来ます。
![dos_外観.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/81a0ebfa-e9f2-d781-0b1c-865803d10830.jpeg)


# 必要な開発環境とLicense
　□Tang-Nano-9K　　2K円ちょいで入手可能(シ〇ゾーンは入荷待ち、秋〇は販売中)。
　□開発ライセンス　「[Tang Nano、Nano9KのIDEであるGowin EDAをインストール(Winのみ)](https://qiita.com/yosiaki/items/2e635e115ecedabecc35)」に詳しく書かれています。
　□microSDカード　　OS(約120MB)をこれ以上の容量のSDカードに書込む。書き込みソフト(Win32DiskImager等)も必要。
　□HDMIディスプレィとケーブル。

　以下は起動のみで、改変無しなら用意不要。
　□PS2キーボードとコネクタ。
　□NEXT186のソースファイル。
　□86用アセンブラ
　□ターミナルソフト　モニタでの入出力を行う、例えばTeraTrem。


# M*DOSの動作確認
　手っ取り早く動作確認する場合
　◇OSイメージの入ったSDカードの作成
　　「[ＤＯＳディスクイメージ](https://github.com/hi631/tang-nano-9K/tree/master/DOSFDOS-128M.zip)」をダウロードし解凍、SDカードに書き込み、TN9KのSDスロットに挿入。
　　　※今回はBIOSをROM化したので、SDへのBIOSの書き込み処理は不要。
　◇FPGAへの書き込み
　　TN9Kを購入する。Gowin開発環境のインストールとライセンス認証を行う。
　　「[FPGAソースファイル](https://github.com/hi631/tang-nano-9K/tree/master/DOS/Next186_S)」をダウンロードする。
　　Next186_S.gprjを開いて、ソースをコンパイル、USB接続してTN9Kに書き込む。
　　　※取り合えず、Gowin_V1.9.8.03を使っている。
　　　　V1.9.8.07はFlash書き込みが出来なかった。
　　　　V1.9.8.09はプログラマーが異常終了する。当方の環境の問題かも。
　◇動作
　　USBケーブルをUSB電源に、HDMIケーブルをディスプレィに接続し、リセット(TN9KのS2釦)を押す。
　　ディスプレィにDOSの起動メッセージが表示されれば大成功。


# TN9-DOSの動作解説
　◇80186(CPU)
　　NEXT186製、キャッシュを無くしたので、かなり遅くなってる。
　　CPUクロックを18MHzにしているが、これ以上だとモニタは起動しても、DOSが起動しなかった。
　　タイミングを調整すれば動くのかも知れない。
　　　※モニタだけなら40MHzで動作したが、Analyzer oscilloscopeの挙動が不安定。
　　　　Analyzer oscilloscopeが動かないと、手も足も出ないので、デバッグ可能な速度に抑える。
　◇SRAM
　　BLOCKRAMを適用。
　　但し、16bitを指定してもbyte_ena端子が無い(様な)ので、8bitRAMを並列に接続。
　　　※この位はGowinで用意して呉れても良いのでは。
　◇DRAM
　　容量は8MB有るが1MBだけ、TN9K内のDRAM(4MBx2)の一部を適用。
　　バースト(32サイクル)によるブロック単位のアクセスで、RWには10(cpu)クロック程度が必要。
　　同一ブロック(64Byte)での読出し要求にはキャッシュ的に動作させ、3(cpu)クロック程度でアクセス可能。
　　クロックは72MHzと遅く、速度を生かしきっていない。
　　　※これも同様に、早くするとDOSが起動しなくなったので遅くしている。
　　メインメモリとグラフィックプレーンを共用しており、描画処理に1/5程度取られている。
　◇ROM
　　Bootとして3KB、BIOSとして8KB使用している。
　　biosの元ネタではRAMで動く事が前提なので、ROMをRAMにコピー後ROMを無効化している。
　◇ACIA(モニタ用)
　　デバッグ用のシリアル通信を行う。CPUクロックを変えた場合は速度再設定が必要。
　　シリアルポートを兼用しているので、DOSの標準シリアルは取り合えず利用不可。
　◇動作クロック
　　TN9Kのベース(水晶)クロックは27MHz。DRAMは8/3分周した、72MHzで動作。
　　CPUはこれを1/4分周し、18MHzで動作。SDカードは更に1/2分周し、9MHzでの動作。

　[プログラムのソースは「此処」に公開している。](https://github.com/hi631/tang-nano-9K/tree/master/DOS/Next186_S)

# 外部記憶装置（ＳＤカード）
　DOSイメージの128MBをSDに書込めば動作する。
　　※一回目のDIRコマンドが極めて遅かったのでサイズは縮小。
　フォーマットはDOS標準(FAT)であり、パソコン等に接続すればファイルの追加等が可能。
　Next186で使用していた末尾へのBIOSの書き込みは取りやめた。
　　※カードの実容量が公称と異なるものを所持しており、その都度調整が大変なので。


# ＶＧＡ波形のＨＤＭＩ出力
　TN9のサンプルソフトとして開示されているpicotinyから、表示に必要部分を抽出して流用。
　アナログVGA信号(vsync,hsync,hblnk,r,g,b)を信号変換処理(svo_tmds)に繋げば、タイミングが合って居ればHDMIとして表示される。
　　※hblnk信号には、blnk信号をOR(hblnk || vblnk) した信号を入れないとHDMI信号は出ない。
デモ表示も残しているので、どうしても表示されない場合はコメントを入れ替えて確認の事。

# 動作ソフト
　今回使用しているソフトは、BOOTとBIOSのアセンブラで書かれた２点。
　「[ソースは此処](https://github.com/hi631/tang-nano-9K/tree/master/DOS)」の下に格納。
　◇BOOT
　　原本のOSの起動部分(MBR)を読み込むまでの処理に、モニタ機能を追加している。
　　リセット時はfc000 - fffff 迄使用しているが、動作時はfc000 - fcfff に定位する。
　　S2釦(リセット)を押すと、ブート処理を行いOSを読み込みDOSが起動する。
　　S1釦を押したままでリセットすると、モニタとして起動する。
　　　※モニタはハード・ソフトのデバッグには有用だったが、OSが起動すればさして使い道は無いかも。
　◇BIOS
　　fe000 - fffff に定位。
　　Netx186で開発された物をほぼそのまま、一部変更部分としては、
　　　・OS起動中もブレーク処理を有効とする為、NMI割り込みではモニタへジャンプする。
　　　・英語DOSでの動作だが、繋ぐのは日本語キーボードなので、106JPが使えるようにエンコ部分を弄っている。
　　　　　※元に戻すには書き換えて再アセンブルが必要。
　◇ツール
　　双方共に86アセンブラで書かれており、パソコン上(MASM32)でアセンブルする。
　　アセンブラは下記サイトの物を使用している。
　　　「[MASM32 SDK Version 11](https://www.masm32.com/download.htm)」
　　アセンブル用のバッチファイルは、アセンブラの格納位置を各自の環境に合わせて修正の事。
　　アセンブル出力はバイナリ形式(COMファイル)となるので、mi形式への変換を行う。
　◇変換ツール
　bin2mi.exe 　　　バイナリファイルを、TN9Kにロードできる形式に変換する。
　　※ソースと実行ファイルを[cpm68k_optiontools](https://github.com/hi631/tang-nano-9K/tree/master/DOS/tools)に置いておくが、怪しいバイナリファイルが嫌と言う方は、ソースも有るのでMingw等でコンパイルして下さい。


# モニタ
　今更要らない子のような気もするが、結構手間が掛っているので、使うかもしれないとして一応解説。
　　※なんせ、86のアセンブラは殆ど触った事が無いし、セグメント何って事でそりゃ大変だった。
　　　従って、大したことはやって居ない。
　モニタは元のブートプログラムに追加する形を取っている。
　　※この為、ワークがモニタ(fc000 - fcfff)の途中(fc800 - fcbff)という、妙な位置にある。
　　　更にWait動作確認の為、fca00 - fcaffのRAMにはWaitが入る。
　基本的にはモニタの居るセグメント(CS=f000)でしか使って無いので、別のセグメントでの動作は怪しい。
　リセット直後にリセットベクタを切り離し、BIOSにベクタを明け渡している。

　モニタの機能として、下記のような操作が可能。
　dxxxx　xxxx番地からメモリを128byte表示する。xxxxxが5桁の場合はセグメント付きでの指定となる。
　mxxxx　xxxx番地の参照、xxxx:yy の後の入力で変更。2桁以上を入れると2byte変更が可能となる。
　　　　　.(ピリオド)で終了。
　fxxxx　yy　zz　xxxx番地から長さyyまで、zzで埋める。2byte指定も可。
　bpxxxx　xxxx番地にブレークを設定。bpだけの入力でブレーク消去。
　g　　　ブレークした場所からの実行。
　t　　　ブレークした場所からのステップ実行。
　bo　　モニタからDOSを起動。

　DOSの起動に失敗した場合、多分失敗の大部分はSDの読み込み失敗であろう。
　この時の動作確認は、次のようにして行う。
　　※一応、2G,8G,32G,128GBで起動可能な事は確認している。
　モニタを起動して、bo1 と言うのコマンドを発行すると、4桁の数字が３個表示される。
　先頭がSDのセクタ数(x1K)。数字が表示されない場合は、読み込みに失敗。
 　　※32GB以上は数字が変だが動作はした。
　　※後ろの２個の数字は、biosの格納位置だが今は未使用。
　BIOSが読み込めているが起動しない場合は、bb と言うコマンドを発行すと、biosの先頭番地で一端ブレークがかかる。
　後は、bp,g,tコマンドを駆使してbiosの動作をトレースする。
　　※INT命令の次の命令にブレークをかけると、INT実行直後でいったんブレークするのは仕様です。
　メモリの7C00にMBR(SDの先頭セクター)が読み込まれれば、後は動くだろう。


# DOS開発環境
　解像度320x200(256色)の旧いソフトは結構動くようだが、
　640x480のグラフィック画面には設定できないので、このままでDOS/V化は無理。
　実機上の開発環境としては、懐かしのTurboCがお勧めかな。
　2.01が無料で公開されています。※ユーザー登録が必要です。
　パソコン上の様に爆速とはいかずチト遅いが、其れなりの速度で動きます。
　機能的に問題は無いが、今となっては画面が窮屈だな。

　下記は実行画面例。
　　※実行可能なEXEを、ディスクイメージデータのtestディレクトリに格納しています。
　　　tc2でコンパイル可能なソースを、tc-samplディレクトリに格納してています。
　左上：コンパイル画面　　　　　右上：ｖｇａ．ｅｘｅ実行画面(bmp表示例)
　左下：ｃｉｒｃｌｅ実行画面　　右下：ｐａｌｅｔｔｅ実行画面
![turboc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/c19e357a-5f68-42fd-7972-9b0480a0034c.jpeg)

# お手軽な解決策でお茶を濁した部分
　下記については深く考慮せずお茶を濁した。※大部分がその場対応とも言えるか。
　◇長大case文でのコンパイラ動作
　　Next186_CPU.vには1500行近いcase文が存在する。※正確にはfunction文だが。
　　このcase文の結果が常に0になるので、之ではcpuが真面に動作する訳が無い。
　　case文部分を適当に３分割したら、正常に処理はされるなったが、之はコンパイラの不具合だと思う。
　　　※これが仕様だとしても、エラーも吐かないのはダメだろう。
　◇VSYNCでの同期が取れない
　　画面の同期が乱れる。元ネタでは正しく表示しているので、当方が作り込んだミスだろう。
　　　※描画クロックよりCPUクロックが遅い事が原因では無いかと推測。
　　強制的に同期をかけているがあまり美しく無いし、別の副作用が有るかも。
　◇Wait挿入でCPUの命令がスキップ
  　DRAMが遅いので、CPUにはWaitをかけているが、そのタイミングがチト微妙。
　　元々Wait処理は存在していたが、キャッシュ動作時以外は特に考慮されていない模様。
　　DRAMアクセス時に命令を読み飛ばしてしていたので、Waitを考慮するように変更。
　　　※今の所は問題無く動作して居るが、思わぬタイミングでボロが出るかも。

# 感想
　パソコンを自前で開発できる。ワンチップでDOSが動くとは隔世の感かも。
　といっても、他社製FPGAで同一グレード(少し上かも)では、既に実現しているもののパクりですけど。
　次はVGA(640x480)でのDOS/Vという考えも有るが、Tang_Primer_20Kに手を伸ばすのが先かも。
　なお、上記記載内容は全て無保証であり、各自の責任においてご利用願います。