2023年12月15日金曜日

FT245高速通信カードを用いるファイル転送ソフト(FLEX9版とOS-9版改)

 

F-BASIC版、OS-9版に続いてFLEX9版を作成すると共にOS-9版を微修正しました


【2024年1月13日追記】F-BASIC版、OS-9版、FLEX9版、CP/M版の最新版を1月13日のブログ「FT245高速通信カードを用いるファイル転送ソフトのCP/M版ができました」にアップしましたので、このブログのOneDriveを削除しました。

【12月17日追記】OneDriveに上げたファイルの中のOS-9版が古いものでしたので、最新版に差し替えました。

ようやくFLEX9版ができあがり、これでCP/Mを除いて3つの環境でファイルをFMとWindowsPC間でファイルを自由に転送することができるようになりましたので、Windows上の慣れたエディタで作成したプログラムをFMに転送して最後の仕上げ作業をするという一連の流れがよりスムーズに進められるようになりました。(以前はRS232を使用したものを使っていたのですが、転送時間が格段に短くなりました。)

CP/M版の作成は80系の知識がない自分にとっては敷居が高く、時間がかかりそうですので、とりあえず、これまでのまとめとして3種の版をまとめて紹介しておきます。

まずはWindows側のslwinft245.exeです。



slwinft245.exe


F-BASIC版、OS-9版、FLEX9版に共通して使用できます。
COMポートはbaud:115200以上, 8bit, non-parity, 1stop bit に設定します。
また、FT245通信カードのTXE機能はOFFのままで構いません。

FM側のドライブソフトです。


(1)F-BASIC版です


F-BASIC版のSLWINFT


(2)OS-9版です


OS-9版のslwinft


前回のブログのものではディレクトリを表示するメニュー項目がありませんでしたが、追加することができました。また、FM-7用のOS-9LevelIで動作することも確認しました。

(3)FLEX9版です


FLEX9版のSLWINFT


見てわかりますようにメニューはほとんど同じにしてあり、操作性もほとんど同じですが、処理対象のドライブ指定だけは、OS-9やFLEX9ではOSであらかじめ指定できるのに対して、F-BASICではできないのでメニューでドライブ変更できるようにしてあります。ただし、メニューからディレクトリ表示できるのはドライブ0と1だけです。(メニューソフトはF-BASICで書いてありますので、簡単に書き換えることができますが。)

以上の3つのOS(F-BASIC版、OS-9版、FLEX9版)に対応したソフトをOneDriveに上げておきますので、FT245高速通信カード(RAMディスク付きも)をお持ちの方は自由にご使用ください。

12月17日追記】差し替えたのはOS-9版のみで、他は変更していません。

【2024年1月4日追記】最新版をOneDriveに上げました。


2023年12月7日木曜日

FT245高速通信カードを用いるファイル転送ソフト(F-BASIC版とOS-9版)

 FT245高速通信カードを用いるファイル転送ソフトのF-BASIC版とOS-9版を作成しました


【追記】Windows側のslwinft245.exeの機能拡張やOS-9版の修正をしましたので、次のブログ「FT245高速通信カードを用いるファイル転送ソフト(FLEX9版とOS-9版改)」の方にソフトの公開を移動しました。

今までFT245高速通信カードを用いる場合には、2D(2DD)ディスクを丸ごと転送するディスク転送ソフト(FDDIMG_RW77.exeやFT245DRV.exe)を使用していました。

しかし、いくら高速とはいえ2Dディスクで約1分、2DDディスクで約2分かかりますので、ファイルを一つだけコピーしたい場合には時間がかかりすぎです。
特に、Windows上の慣れたエディタで作成したプログラム等をF-BASICやOS-9等に転送して使用するという、私のプログラム開発の手順の中では転送時間が長いのは致命的です。
ということで、ディスク転送ソフトではなくファイル転送ソフトが必要と感じていました。

ディスク転送ソフトの場合にはOSの種類によらず、40(80)トラック、16x2セクタ/トラック
のディスクであればF-BASIC上のドライブソフトで転送できましたが(ただし、FLEX9だけは32セクタ/トラックなので転送できない)、ファイル転送の場合にはOSの機能を用いてファイルを読み書きしますので、当然OSに依存することになります。

ということで、まずは使用頻度の高いF-BASIC版を作成し、続いてOS-9版も作成しました。

Windows側のslwinft245.exeはもちろん、全OS共通です。
起動後にCOMポートとOSの選択をしたのちに使用可能状態になります。



Windows側のslwinft245




FM-7/77側のドライブソフトはOSに依存しますので、それぞれのOS用に作成しました。


【1】F-BASIC用のSLWINFT


まずF-BASIC用のSLWINFTを紹介します。
対象ドライブはデフォルトで1ですが、もちろん変更できます。
TXE機能のON,OFFはFT245通信カードの設定と一致させます。
(TXE機能がないカードの場合はOFFに設定します。)


FM-7/77側のSLWINFTメニュー



使用するソフト
〇FM-7/77側   メニュープログラムSLWINFT(F-BASIC)を実行する。
         起動時に機械語サブプログラムSLWINFToが読み込まれる。
         (SLWINFToは&H6000~&H61E7に配置される)
〇WindowsPC側 SLWINFT245.exeを実行する。

動作環境
〇FM-7     F-BASIC V3.0
〇FM77AV2   F-BASIC V3.0、V3.3
〇FM77AV40SX F-BASIC V3.0、V3.4
以上の環境で動作することを確認してあります。

使い方
◎WindowsPC -> FM-7/77 への転送
  FM-7/77側でメニュー2を選択する。
  Windows側で転送するファイルを選択(ドラッグ&ドロップまたは直接書き込み)して「FMへの書き込み」ボタンを押す。

  FM-7/77側に既に同名のファイルが存在する場合には、重ね書きをするかどうかを選択できます。

  ファイル種別は自動的に判別しますが、通常のバイナリファイルの場合は先頭に5バイトのヘッダー、末尾に5バイトのフッターが必要ですので、そのための情報として保存アドレスと実行アドレスをセットします。(既にヘッダー、フッターがついているファイルの場合はそのまま転送されます。)

◎FM-7/77 -> WindowsPC への転送
  Windows側で読み込んだファイルを保存するファイル名をセットして、「FMから読み込み」ボタンを押す。
  FM-7/77側のファイル名と異なるファイル名でも構いません。
  FM-7/77側でメニュー1を選択し、転送するファイル名を入力してEnterキーを押す。
  存在しないファイル名を入力した場合にはエラーメッセージが出て、再入力を促されます。
  機械語ファイルの場合にはヘッダーとフッターが削除された通常のバイナリファイルとして保存されます。(読み取った保存アドレスと実行アドレスは画面上に表示されます。)

その他
  FM-7/77側ではドライブ番号をメニュー3で変更できます。
  また、メニュー4でTXE機能を使用するかしないかを選択できます。通常は機能OFFで問題はありません。


【2】OS-9用のslwinftos9



OS-9側のslwinftos9のメニュー


使用するソフト
〇FM側      ドライブプログラムslwinftos9を実行する。
〇WindowsPC側 SLWINFT245.exe(F-BASIC版と同じ)を実行する。

 (FM側のslwinftos9をどうやってOS-9に読み込むかですが、OS-9のディスクもF-BASIC
上のディスク転送ソフトft245drvで転送できますので、これを利用してOS-9のディスクに
読み込みます。)

動作環境
〇FM77AV40SX OS-9Level2
 Level1では動作確認をしていません
 【12月15日追記】動作することを確認しました。

使い方
◎WindowsPC -> FM への転送


メニュー2の実行例

  FM側でメニュー2を選択する。
  「Send file from Windows...」が出て受信モードに入る。
  Windows側で転送するファイルを選択(ドラッグ&ドロップまたは直接書き込み)して「FMへの書き込み」ボタンを押す。このファイル名でFMに保存される。

  FM側に既に同名のファイルが存在する場合には上書きされる。

  ファイル種別は自動的に判別するので、実行モジュールファイルとテキストファイルのどちらであっても構わない。

◎FM -> WindowsPC への転送


メニュー1の実行例

  FM側でメニュー1を選択する。  
  Windows側で読み込んだファイルを保存するファイル名をセットして、「FMから読み込み」ボタンを押す。
  FM側のファイル名と異なるファイル名でも構いません。
  FM側でメニュー1を選択し、表示「Input file name:」に続いて転送するファイル名を入力してEnterキーを押す。
  存在しないファイル名を入力した場合にはメニューに戻ってしまうので、最初からやり直す。

その他
  メニュー3でTXE機能を使用するかしないかを選択できます。通常は機能OFFで構いません。

現在のところはF-BASIC版とOS-9版のみですが、順次CP/M版、FLEX9版を作成する予定です。

現在のF-BASIC版とOS-9版をOneDriveに上げておきますので、FT245高速通信カード(RAMディスク付きも)をお持ちの方は自由にご使用ください。
【12月15日追記】ソフトの公開は12月15日のブログに移動しました。



2023年11月17日金曜日

PC-G850V用USB-シリアルケーブルの作成

 以前作成してあったPC-G850V用のUSB-シリアルケーブルを新たに作り直しました

いつも興味深い記事が連載されているskyriverさんのブログ「PICマイコンは面白い」で、以前、PC-G850Vを入手されたという記事を読み、そういえば昔、同僚が面白いと言っていたポケコンだなと思い出し、私も入手してみました。同時に、skyriverさんが作られたUSB-シリアルケーブルを見習って同様なケーブルを作って使用してきました。

それがこれです。


以前作成したケーブル


そのアダプタ部

74HC00をインバータとして使用して、TxD,RxD,RTS,CTSを反転してUSB-TTL変換ケーブルに接続しているだけです。

機能的にはこれで十分でしたので、skyriverさんの実践をそのまま後追いする形で楽しく遊んできましたが、流石にCP/Mを走らせるまではやってみるつもりはありませんでした。


ところが、skyriverさんが開発されたCP/Mも実行できる増設メモリボード(EborsyEEP)を見て、そのコンパクトさと実用性に感心してしまいBOOTHで購入させていただきました。
見つけたコネクタ
さらに純正の電源も入手したので、これで本格的に遊べると思っていたところに、偶然PC-G850のシリアル端子用のコネクタを入手することができました。(右画像)
これでしたら、ピンの両側にガイドが付いているので安定感があります。

ということで、これを使用してUSB-シリアルケーブルを作成しようと考えてネットで参考資料を探していたところ、「ポケコン用USB通信ケーブルを作ろう」というサイトに、変換ケーブルがFTDI社のチップを使用していればFT_PROGというユーティリティを用いてピンの極性を反転させることができると書かれてありました。

私のケーブルは以前紹介しましたように、格安で入手したものですので、FTDI社の純正チップではないだろうと思ったのですが、試してみたところFT_PROGで認識できて、無事に書き換えることができました。

書き換えたケーブルを用いることで、アダプタの機能としては単なるケーブルの6ピンとPC-G850Vの11ピンとの間を接続するだけで良いことになります。

作成したアダプタです。
裏面画像で分かりますように、単なるピン間を接続しているだけです。


アダプタ表面・裏面


FT_PROGで書き換えたケーブルと組み合わせます。


新USB-シリアルケーブル


最後に動作画面を載せておきます。
右端のシステムバスに装着してあるのが増設メモリボード(EborsyEEP)です。
CP/Mをセット済みですので、増設メモリを装着して電源を入れれば、モニタに移ってG100でCP/Mが起動します。

動作画面

最後に
貴重な情報や資料を公開してくださったskyriverさん他の方々に感謝いたします。



2023年10月23日月曜日

FT245通信カードの新基板の製作

 FT245通信カードの新基板を製作しました

【2024年1月24日】末尾にOneDriveを追加して、RAMディスクのない従来のFT245カード用のドライバ一式を上げました。

ブログ「思いつきハードでソフトに七転八倒(https://vehwk3yxv7hw.blog.fc2.com/blog-date-202206.html)」のshujiakitaさんの発案・製作によるFM-7/77用の「FT245使用の高速通信カード」と「RAMディスクカード」について、プリント基板を作成したり、両カードの合体カードを製作したりしながら、その都度それらをブログで紹介してきました。

FT245通信カード用のディスクイメージ転送専用ソフトhttps://flexonsbd.blogspot.com/2023/01/ft245.html

FT245通信カードとRAMディスクカードの合体カードの製作https://flexonsbd.blogspot.com/2022/06/ft245ram.html

FT245高速通信カードの改造の試み
https://flexonsbd.blogspot.com/2022/04/ft245.html

FM-7用の512KB RAMディスクカードの紹介
https://flexonsbd.blogspot.com/2022/02/fm-7512kb-ram.html

高速通信カードFT245の使い方の紹介
https://flexonsbd.blogspot.com/2022/02/ft245.html

FT-245カード用の転送ソフトの使い方
https://flexonsbd.blogspot.com/2021/04/ft-245.html

FT-245カード用の高機能な転送ソフト
https://flexonsbd.blogspot.com/2021/01/ft-245.html

Ndittを使用しないでGOTEK用のHFEファイルを作成する(その3)https://flexonsbd.blogspot.com/2020/12/ndittgotekhfe_11.html


振り返ってみますと、2020年12月11日のブログから始まって、上記のように8回も紹介していますが、それだけ私にとっても非常に有用なツールであり手放せないものになっています。


今回製作したカードの改善点

今回新たに基板を作成することにしました。回路には見直すところはありませんでしたが、念のために電源ラインを強化すること、FT245カードにはコネクタの取り付け穴の追加と、合体基板で採用したTXE#をソフトで読めるようにする切り替えスイッチの追加を行いました。

製作した3種のカードです。


製作したカード3種


(1)上左のカード:オリジナルのカードで秋月電子製のFT245モジュールを使用しています。

(2)上右のカード:オリジナルのFT245モジュールをFT245RLチップに置き換えたものです。マイクロUSBケーブルも使用できるようにマイクロコネクタも装備しています。

(3)下のカード:(2)にRAMディスクカードを合体させたものです。(2)と同様にマイクロコネクタも装備しています。


使用するドライブソフト

使用するドライブソフトは従来のものと変わりませんが、メニューを多少変更しました。

(1)shujiakitaさん作成の高機能ソフト(転送機能のみでなく様々な機能があります)

FM-7側:メニューソフト:FM7FDRAM(従来のFM7FDUIXのメニューを多少変えましたのでFM7FDRAMと改名)、機械語サブプログラム:FDIMGFMX, XRAMDK77

Windows側:FDDIMG_RW77.exe

(2)私作成の単機能ソフト(使いやすさを求めて転送機能に特化)

FM-7側:メニューソフト:FT245DRV、機械語サブプログラムFTDRV11o

Windows側:ft245drv.exe


以上、FT245通信カードを多少手直しして製作したという紹介でした。

ドライブソフト一式をOneDriveに上げておきます。


【2024年1月24日追加】RAMディスクのない従来のFT245カード用のソフト(Windows側:FDDIMG_RW77.exe、FM-7側:FM7FDUI5, FDIMGFM2)をOneDriveに上げました。なお、FM7FDUI5, FDDIMGFM2はFB_TRANS.DATの中にも入れてあります。



2023年10月22日日曜日

FM77AV20/40用のFM77-732互換カードの製作

FM77AV20/40用の拡張ドライブ用のアダプターFM77-732の互換カードを製作しました 

FM77AV20/40には2台の2DDドライブが装備されていますが、時には2Dドライブ(5インチや3.5インチ)を増設したい時があります。

普通のドライブ増設の手段としては現在のドライブが接続されているケーブルにさらにドライブを接続する方法があります。FDC(フロッピィディスクコントローラ)として通常使用されているMB8877AやMB8866はドライブが4台まで接続できるので、この方法で増設できそうなのですが、実際に試みてみるとうまくいきません。2D、2DDドライブのどちらも正常に動作しないのです。

正規の方法としては、拡張ドライブ接続用の専用のアダプターFM77-732を使用することになっていますが、現在入手するのは困難です。

ということで手持ちのFM77AV40SXにドライブを増設することはあきらめていたのですが、最近、知人がSXを入手されたところ、それにFM77-732が取り付けられていました。

これが純正のFM77-732カードです。


オリジナルのFM77-732カード


早速そのFM77-732をお借りして調べてみました。

使用されているICは74HC04(2個), 74HC05, 74LS14, MB463(3個)の計7個のコンパクトなカードでしたが、ネット検索してもMB463の規格が分かりません。

基板のパターンは単純な二層基板なので、目視と導通テスターで調べて回路図を起こしてみました。ここに回路図を載せるのは差し障りがあるかもしれませんので掲載しませんが、基本的には単なるバッファ回路でした。

ただし、HeadLoadとStepPulseという2信号のみはフラットケーブル(つまり内蔵のドライブへの信号)からではなく、別途メインボードの5ピンソケットから取っています。内蔵ドライブへの信号は2DD用ですので、それとは別にメインボード上で2D用の信号を生成しているのだと思われます。

回路図の検討からMB463は通常のバッファICの7438で代用できそうだという見込みが立ちましたので、プリント基板を起こすことにしました。相変わらずドジをしてしまって作り直すことになりましたが、2枚目で無事に動作しました。

使用する部品のほとんどは何とか入手できましたが、5ピンコネクタだけはメインボードのソケットに合致するものが見つかりませんでした。。。

作成したプリント基板です。


作成した基板


製作したFM77-732互換カード


製作した互換カード


このカードをFM77AV20/40の背面の拡張FDDのコネクタ取り付け部に固定し、メインボードのFDDへのケーブルを抜き、そこにフラットケーブルの先端のコネクタを装着し、抜いたケーブルは画像の白の中継コネクタに嵌め込みます。

5芯のケーブルはメインボードのコネクタに装着したいのですが、画像のコネクタでは合いませんので、両端がオス・メスのブレッドボード用のケーブル5本を用いて繋ぎます。

なお、37ピンD-Subコネクタと増設ドライブとの接続ケーブルは信号のピン配列が一致していますので画像のようにフラットケーブルの両端にコネクタを付けたものでOKでした。


FDD接続ケーブル

全体の接続図

FM77-732カードの接続図

接続テストとしては、2Dの3.5インチドライブYD-625を使用しましたが、DISK-BASICの起動時にドライブ数として3以上を設定することで、特に問題もなくドライブ2として読み書きができました。

間に合わせに使用したケーブル
以上、現在では入手が困難なFM77-732カードと同等の機能を持つカードを製作してみたという報告でした。

唯一の問題は5ピンのコネクタが入手できないということですが、画像のようなオス・メスケーブルでとりあえず間に合わせることができました。

回路図を公開できれば自作してみたいという方がおられる(?)かもとは思いますが、このような数十年前のメーカー製品の回路図の公開は許されるのでしょうか。



2023年10月1日日曜日

アップスキャンコンバータの製作(その2)

 以前製作したアップスキャンコンバータのプリント基板を作成して作り直した結果、なんと3台も作ることになってしまいました

以前、2021年6月15日のブログ「アップスキャンコンバータの製作」で紹介しましたアップスキャンコンバータですが、FM-7に接続して2年ほど使用していました。機能面では特に問題はなかったのですが、ベース基板が手配線であることと切り替えボックスへの収め方にとりあえず感があるのが気にかかっていました。

そんな時に、入手しにくい12接点のロータリースイッチがヤフオクに出品されているのを見つけて、もう一台製作して今度はプリント基板を作成し、ちゃんとしたケースに収めようと考えました。

製作したプリント基板が下画像です。(ミスを重ねて3枚目でようやく完成しました。)


作成した基板


以前のものはこのようにとりあえずの手配線でした。


第一作の手配線基板

オリジナルの作者であるNibbles lab. HomePageのOh!石さんが「RGBI対応スキャンコンバータ」で使われたケースはタカチのMX型モバイルケースMX2-8-10というアルミケースのしっかりしたもので、私も真似をして同じMX2-8-10SGを使いました。

なお、元の製作記事は上記サイト中の「研究成果->完了プロジェクト->RGBI対応アップスキャンコンバータ」です。貴重な製作記事を公開していただきありがとうございます。また、FPGAカードはデザインウェーブマガジン2007年7月号の付録基板です。

ケースに収めた状態です。


上蓋と背面パネルを取り外した状態


分解した様子です。


組み立てた状態とケースから取り出した状態


前面・背面パネルです。

前面パネルと背面パネル

前面パネルには8ピンDINの入力端子と切り替えスイッチを、背面パネルにはD-Sub 15ピンのVGAコネクタと5V電源入力を配置しました。


以上の画像からお分かりのように、1台製作するだけのつもりだったのに結果的に2台作ってしまいました。
プリント基板も2回作り直して3作目でようやく完成したのですが、1作目はFPGAカードのコネクタ一位置の実測間違いでカードが取り付けられず、2作目は電源入力の番号付けのミスで5VがそのままFPGAカードにかかってしまうという致命的なミスを犯してしまいました。
3作目でようやく完成した基板ですが、組み立てても動作しませんでした。

その理由ですが、FPGAカードのコンフィグROMに書き込もうとしてもROMやFPGAを認識しないのです。てっきり5V印加のせいでFPGAが破損したものと思い込んで、新たにFPGAカードを入手しました。しかし、やはりこれも認識しないので、困り果ててネット検索したところXilinxの書き込みソフトがそのままではWindows10に対応しておらず、ドライバを前のバージョンのものに差し替える必要があることが分かりました。2年前はWindows7を使用していたので正常に使えていたのでした。

なお、第一作ですがFPGAカードの上に取り付けてあった部品を裏側に回すことで、下画像のように、切り替えスイッチの中に収めることができました。
(とはいっても、タカチのケースに合わせた基板のサイズが長すぎたので、数mmほど削ることになりましたが。)


切り替え機に収めた


以上で、気にかかっていたアップスキャンコンバータの製作ですが、これでようやくけりをつけることができました。(しかし、XRGB-2plusが常時使用と予備機で2台、今回製作した切り替え機中の1台、タカチのケース入りの2台と計5台にも増えてしまいました。どうしよう...)

作成した基板が少しですが余っていますので、ご希望の方がおられましたらメールで連絡を下さい。郵便代のみでお送りいたします。



2023年8月20日日曜日

MC09でASSIST09など用のPL/0の実行ファイルを作成する(補足)

 MC09でASSIST09など用のPL/0の実行ファイルを作成していて気付いたこと

前回のブログで、MC09でコンパイルした実行ファイルをASSIST09などで走らせる方法を紹介しました。

その中で、wnoy さんのサイト「小さな言語」中でPL/0をMC09でコンパイルしてMPB6809のモニター上で走らせておられたので、それを私も走らせてみたと書きましたが、実際には、それはMPB6809のモニターを実装してサイト中のバイナリリストを入力したものを、そのまま走らせたということでした。


前回も掲載した画像ですが


上記サイトにはMC09でコンパイルした結果のアセンブルリストが掲載されていたので、その中のI/O関係を自分の環境に合わせて書き換えてアセンブルすれば実行ファイルが生成されるはずです。

しかし、実はこのようにして生成された実行ファイルは、最初は正常に動作しませんでした。

私が通常使用している6809用のアセンブラはFLEX09上のASMBと自作のWindows上で動作するクロスアセンブラです。加えて、リファレンス用としてアークピットさんのX6809を使用しています。

残念ながらPL/0のアセンブルリストはラベルの長さが6文字を超えているためにASMBではアセンブルできないので、自作のクロスアセンブラでアセンブルしていましたが、結果がwnoyさんのものと異なってしまうのです。これは自作のソフトのバグかと疑って、X6809でアセンブルしてみても結果は自作のものと全く同じでした。


LEAX 2,PC という命令の変換結果がおかしい!

誤変換されてしまう命令を示します。MC09によるコンパイル結果のアセンブルソースでは、文字列の表示に下記のパターンが多用されています。(十数か所あります!)

LEAX 2,PC

BRA ZZZZ <- 表示ルーチンへ

FCB $xx1,$xx2,$xx3,...,$xxn

ZZZZ (表示ルーチン)

これは、LEAX 2,PCで表示すべき文字列の先頭のアドレスをXに入れておいて、BRA命令で表示ルーチンへ飛んでいるわけですが、問題は先頭行の LEAX 2,PC で、これが正しく変換されていないのが正常に動作しない原因でした。

wnoyさんのサイトでは、変換結果は 30 8C 02 であるのに対して、自作のアセンブラやアークピットさんのX6809ではいずれも 30 8D XXXX となりますし、LEAX <2,PC と書き換えてみても X6809では 30 8C XX となるのですが、XXは02にはなりませんでした。

参考までに、X6809でのアセンブル結果を示します。 

 


このLEAX命令の意味としては、LEAX命令の位置のPC値に2を加えた値をXの値とするということですから、EFFEやF2という値は明らかにおかしくて0002や02にならなければなりません。

結局、自作のクロスアセンブラを修正することになった

めったに使うことのない命令でしたので気づくのが遅れましたが、自作のクロスアセンブラを正しく変換できるように修正し、改めてPL/0のアセンブルリストをアセンブルし直した結果、正しく動作する実行ファイルが得られました。ということで、ようやくPL/0をASSIST09や自作モニター上で走らせることができました。(長かった、、、)

ちなみに、この変換結果はアークピットさんのX6809だけでなく、FLEX09上のASMBでも同様で上記と全く同じ結果となります。ということは、これは誤変換ということではなく、このLEAX命令の解釈としては上記の変換結果の方が正しいということを意味するのでしょうか。しかし、実際に実行してみると、30 8C 02 でないと正しく動作しないのですが,,,

(wnoyさんがどのアセンブラを使用されたのかは分かりませんが、アセンブルリストの行末記号が$0Aですので、おそらくLinux上のクロスアセンブラas09を使用されたのだと推測しています。)


2023年8月16日水曜日

FLEX09上のMC09でASSIST09などのモニター下で動作する実行ファイルを作成する

 FLEX09上のMC09を用いてFLEX09がない環境で動作する実行ファイルを作成する

FLEX09には高機能で使いやすいアセンブラASMBがあって便利に使っています。さらに有名な整数型CコンパイラMC09もあります。

ASMBで作成した実行ファイルはもちろんFLEX09のない環境に移行して動作させることができるので、しばしばそのような使い方をしているのですが、MC09については、生成された実行ファイルがFLEX09と密接に関連していて、他の環境で動作させることはできないと思い込んでいました。

しかし以前、「小さな言語」というwnoy さんのサイトがありまして、そこではMPB6809というボードマイコンとそれ用のモニタープログラムが公開されていました。

(現在このサイトは存在しませんが、その内容を保存された方が紹介されています。「MPB6809」で検索するとヒットします。)

このサイトでは他にもForthの移植やTinyBasicの解析などもされているのですが、何とPL/0をMC09でコンパイルして移植しておられるのです。

私もこのモニタープログラムを入力してROMに焼き、自作の6809マイコンでPL/0を走らせてみました。PL/0は実用を目指したコンパイラではないので、特に使い続けるつもりはありませんでしたが、MC09でコンパイルした実行ファイルをMPB6809というマイコンに移植したという点に興味を持ちました。

FLEX09に依存しているファイルI/Oを使わないプログラムならFLEX09がなくても動作するのは当然ではありますが、初めて見る実例でした。このサイトを知ったのは十年以上前なのですが、それ以来、時々ですがMC09でコンパイルした結果のソースリストをいじって自作のマイコンで走らないかと試していました。

PL/0のソースは大幅に書き換えないとそのままではMC09でコンパイルできないので、まだPL/0をコンパイルすることはできていないのですが、他のプログラムについては、最近ようやく何とか動くようになりました。

動作試験に用いたマイコンは下画像のもので、2MHz動作の63B09と68B02を切り替えて使用しています。モニターは6809では自作のものとASSIST09を、6802では自作のものとMIKBUG2をROMに入れてあり、FlexDrvWin.exeという仮想ドライブ構築ソフトを用いることで6809のFLEX09と6800のFLEX2が走っています。


使用したボードマイコン


MC09での実行ファイル作成手順

MC09でコンパイルした結果はC.OUTというアセンブルリストとして出力され、それをMC09に標準で添付されているC.TXTというアセンブルリスト中に読み込んで、全体をアセンブルすることで実行ファイルが生成されます。

MC09 oooo.C --> アセンブルリスト C.OUTが作られる。

ASMB C.TXT oooo.CMD --> C.TXT中にC.OUTが読み込まれ、実行ファイル oooo.CMDが生成される。


C.TXTを書き換えれば良いはず

このC.TXT中にコンソールI/OやファイルI/Oなどが書き込まれているので、コンソールI/Oを自分の環境に合うように書き換え、ファイルI/Oは不要ということで削除すれば良いはずなのですが、エラーの連発でなかなかうまくいかず、試行錯誤の連続でしたが、wnoyさんのPL/0のアセンブルリストを参考にしながら何とか動作するものを作ることができました。

もちろん、FLEX09のファイルI/Oを必要とするプログラムはダメですが、ファイルI/OがないプログラムならMC09で作成して、マイコン等で走らせることができます。サンプルとしてメモリダンププログラム mdump.c を作成してみました。


ASSIST09用と自作モニター用の2種を作成した

作成したのは、私の自作マイコンにインストールしてある自作モニター用のC_SBC.TXTとモトローラ社のモニターASSIST09用のC_ASSIST.TXTの2種です。

これらを標準のC.TXTの代わりに用いることで、自作モニタ―上やASSIST09上で動作する実行ファイルが得られます。

MC09 -O1.C.OUT oooo.C --> アセンブルリスト C.OUTがドライブ1に作成される

ASMB C_SBC oooo.BIN +YLS または ASMB C_ASSIST oooo.BIN +YLS --> 実行ファイル oooo.BIN がドライブ1に作成される

この実行ファイルをFLEX09のディスクから取り出してマイコン側にインストールして、$100から実行します。

(C.TXTにORG $100と書いてあるので、MC09で作成した実行ファイルは$100から実行することになっていますが、実は、アドレス依存のコードではないのでどのアドレスに置いても実行できます。)

作成したC.SBC.TXTとC.ASSIST.TXTを下記に示します。基本的にI/O関係のアドレスが異なるだけですが、ASSIST09のI/OルーチンはSWI命令を使っているのに対して、私の自作モニターは普通にJSR命令を使っているので、コールの仕方もそれぞれに合わせています。


以下にC.ASSIST.TXTとC.SBC.TXTのリストを示します

C_SBC.TXT 

  
 


C_ASSIST.TXT 

  
 


(以下省略)の部分は標準のC.TXTの192行目以降と同じです。


参考までに、サンプルとして作成した mdump.c を示しておきます。このような、ファイルI/OがないプログラムはFLEX09がなくても動作するわけです。

mdump.c 

  
 

出来あがった mdump.bin のサイズは4.2KBほどでした。サイズは大きくなりますが、アセンブラで書くよりも作成時間が短くなるので、サイズがそれほど問題にならない場合にはMC09を使用するメリットはあると思います。


参考までに、私の場合の具体的な実行ファイル作成・実行手順を示します。

1.WindowsPC上のエディタでソースプログラムを作成する。

2.FlexDrvWin.exe中のイメージファイル(.DSKまたは.D77)にソースをドラッグ&ドロップする。

3.MC09でコンパイル、ASMBでアセンブルする。

4.出来あがった実行ファイル(.BIN)をイメージファイルからWindowsPCへ読み出す。

5.バイナリ形式の実行ファイルを自作の変換ソフトCvtMotHexBin.exeを用いてモトローラ形式(.MOT)に変換する。

6.モニターのLoadコマンドでモトローラ形式の実行ファイルを読み込む。

7.モニターのGoコマンドで実行する。


以上ですが、作成・使用したファイル(C_ASSIST.TXT, C_SBC.TXT, 最新版のFlexDrvWin.exe, CvtMotHexBin.exe, サンプルのmdump.c)をOneDriveに上げておきます。なお、FLEX09やMC09の作成手順は以前のブログで紹介しております。


2023年7月16日日曜日

FM77AV40用1024KB増設RAMカードの製作

 FM77AV40用512KB増設RAMカードの容量を760KBに増加させました

2022年10月21日に「FM77AV40用512KB増設RAMカードの製作」を紹介しました。製作した基板のサイズは純正の256KB増設メモリカードよりはるかに小さなものでしたが、それでもまだ基板に余裕がありましたので、512KBメモリをもうひとつ載せられそうです。ということで、容量を倍増させたカードを製作してみることにしました。

これが製作した1024KB増設RAMカードです。(実際に増加する容量は760KBです。)

512KBメモリはSOP型のHM628512を自作変換基板にセットしたものを使用しています。


1024KB増設RAM


回路図を下に示します。

最初は通常のTTL-ICで試作しましたが、未使用のゲートが多く、あまりにも無駄が多いのでどうしようかと思っていたところに、知人からこういう時にはGALを使ったら良いかもとのアドバイスを受けて、GALに変更することにしました。


最初に試作した回路

Latticeの16V8Bを使用しましたが、3個のTTL-ICを1個のGALで置き換えることができました。


GALに変更

GALのプログラムにはMicrochip社のWINCUPLを用いました。

GALを使用するのは初めてだったのですが、実際に使用してみて、この程度のロジックをGALのプログラムに置き換えるのは、初心者でもそう難しいことではないと感じました。

参考までに、今回の置き換えの部分を示しますが、あとはそれぞれの入出力信号を16V8Bのピンに割り当てればOKです。

/* EQUATIONS */

CS1 = !(A18 & A19) ;

CS2 = !(A18 $ A19) ;

WE  = !(!RW & E) ;

OE  = !(RW & E) ;


製作した結果は

前回と同様、OS-9 Level2でフリーメモリを確認しました。

その結果が下記ですが、760KB増えています。


フリーメモリ確認


512KBのメモリを2個搭載しているので1024KBの容量なのですが、拡張メモリの範囲は$40000~$FFFFFの768KBですので、これだけ増加するはずですが、実際には$40000~$FDFFFの760KBの増加になっています。OS-9の場合は、最上位の$FE000~$FFFFFの$2000バイト(8Kバイト)は使用不可のようです。

この位のRAM容量があれば、一部をRAMディスクに充てることもできそうです。

以上、512KBの増設RAMの容量をさらに増やしてみたという報告でした。

現在48ピンのコネクタの入手は困難ですが、コネクタさえ入手できれば回路は簡単ですし512KBのSRAMも入手は容易ですので製作そのものは容易です。


2023年7月5日水曜日

コンパイラ作成の試み その3 番外編 (Z80版8ビットコンパイラの入力)

 Z80版8ビットコンパイラ stellarを入力してみました




5月20日の「コンパイラ作成の試み その1「ハイクラスC言語」のリストを入力」で参考文献として紹介しました「Z80CPU対応 新言語作成の技法 (大貫広幸著 MIA社)」中に掲載されています、CP/M-80で動作するコンパイラ言語 stellarのアセンブルリストを入力してみました。

120ページ以上ありましたが、何とか入力してCP/M-80のMacro-80でアセンブルして実行形式を作成することができました。

作成したファイルは

・stellar.com  コンパイラ オブジェクトファイルを生成

・convobj.com 生成されたオブジェクトファイルをHEX形式に変換

の2つで、コンパイルの手順は 下に例を示しましたが、stellar.com でコンパイル、convobj.com でHEX形式に変換、save.comでディスクに保存した後に実行となります。


d>stellar mdump

Stellar compiler Rev 1.01 ( CP/M-80,MSX-DOS Version )
Copyright (c) 1984 H.Ohnuki / MIA

Program  name : mdump
Function name : getchr
Function name : putchr
Function name : putnl
Function name : putstr
Function name : puthex
Function name : puthex1
Function name : bdos

Program  04EF (0100-05EE)
Data     0047 (4000-4046)

**  End of compile,  No error(s)

d>convobj mdump

Stellar utility,  convert object ==> intel HEX
Rev 1.00  Copyright (c) 1984  H.Ohnuki / MIA

Program  name : mdump = 0100
Function name : getchr = 0482
Function name : putchr = 04A1
Function name : putnl = 04C4
Function name : putstr = 0511
Function name : puthex = 0549
Function name : puthex1 = 057A
Function name : bdos = 05B6
Constant name : _work = 4000
Constant name : _var = 4030
Constant name : _code = 0100
Constant name : ngetchr = 0001
Constant name : nputchr = 0002
Variable name : d = 4030
Variable name : i = 4031
Variable name : sttadr = 4032
Variable name : endadr = 4036
Variable name : sadr = 403A
Variable name : eadr = 403C
Variable name : ch = 403E
Data     name : msttadr = 020D
Data     name : mendadr = 0217
Data     name : header = 0221

End address   : 05EE
Program size  : 04EF  [ 5 Page ]

d>save 5 mdump.com
d>
d>mdump
sttadr= $1234
endadr= $1567

      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
1230: 55 E5 22 DD 55 CD E8 12 3E 32 2B CD 79 23 21 00  U.".U...>2+.y#!.
1240: 00 22 DF 55 3A 93 55 FE 7B 28 1F FE 9A C2 19 2A  .".U:.U.{(.....*
1250: CD 1A 25 CD C5 17 FE 7B C2 19 2A 2A 6D 55 22 DF  ..%....{..**mU".
1260: 55 CD E8 12 3E 32 2B CD 79 23 CD 50 15 2A DD 55  U...>2+.y#.P.*.U
1270: CD 48 22 2A DB 55 CD 48 22 21 F9 12 CD A5 22 2A  .H"*.U.H"!...."*
1280: 69 55 2B 2B 22 D9 55 CD 93 11 2A DF 55 7C B5 20  iU++".U...*.U|.
1290: 19 2A DB 55 3E 21 CD 79 23 3E 34 CD 5E 23 2A D7  .*.U>!.y#>4.^#*.
12A0: 55 3E 20 CD 35 15 3E C2 18 19 CD 48 22 2A DB 55  U> .5.>....H"*.U
12B0: CD 48 22 21 04 13 CD A5 22 2A D7 55 3E 30 CD 35  .H"!...."*.U>0.5
12C0: 15 3E D2 DC 79 23 CD 68 15 E1 22 6D 55 01 06 00  .>..y#.h.."mU...
12D0: 21 DB 55 CD 0E 25 01 0F 00 21 73 55 CD 0E 25 21  !.U..%...!sU..%!
12E0: 73 55 CD 39 08 C3 1A 25 23 22 6D 55 EB 2A 6B 55  sU.9...%#"mU.*kU
12F0: B7 ED 52 EB D0 22 6B 55 C9 0A 3A B9 B9 21 BB BB  ..R.."kU..:..!..

      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
1300: 96 DA 00 00 08 3A B9 B9 21 BB BB 86 77 FE 23 CA  .....:..!...w.#.
1310: 97 13 3D C2 19 2A 21 73 55 CD C0 08 B7 C4 7F 28  ..=..*!sU......(
1320: 21 73 55 7E E6 2F FE 02 C2 19 2A 01 0F 00 CD FE  !sU~./....*.....
1330: 24 21 73 55 CB EE CD 39 08 2A DB 55 E5 2A 80 55  $!sU...9.*.U.*.U
1340: 22 DB 55 CD 1A 25 FE 2C C2 19 2A CD 1A 25 CD C5  ".U..%.,..*..%..
1350: 17 FE 7B C2 19 2A 3E 32 2A DB 55 CD 79 23 CD 50  ..{..*>2*.U.y#.P
1360: 15 CD 93 11 3E 21 2A DB 55 CD 79 23 3E 35 CD 5E  ....>!*.U.y#>5.^
1370: 23 2A D7 55 3E 20 CD 35 15 3E C2 DC 79 23 CD 68  #*.U> .5.>..y#.h
1380: 15 E1 22 DB 55 01 0F 00 21 73 55 CD 0E 25 21 73  ..".U...!sU..%!s
1390: 55 CD 39 08 C3 1A 25 21 96 55 7E B7 C2 19 2A 2F  U.9...%!.U~...*/
13A0: 77 CD 1A 25 FE 2C C2 19 2A CD 1A 25 CD 00 18 47  w..%.,..*..%...G
13B0: 3A 98 55 3D C2 48 2A 78 FE 7B C2 19 2A FD 7E FD  :.U=.H*x.{..*.~.
13C0: B7 28 11 21 F7 17 3D 28 08 21 FF 13 CD 9A 22 18  .(.!..=(.!....".
13D0: 08 CD 9A 22 3E 47 CD 5E 23 CD 50 15 CD 93 11 2A  ...">G.^#.P....*
13E0: D7 55 3E 10 CD 35 15 30 0C E5 3E 05 CD 5E 23 E1  .U>..5.0..>..^#.
13F0: 3E C2 CD 79 23 AF 32 96 55 CD 68 15 C3 1A 25 02  >..y#.2.U.h...%.

      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
1400: 06 B8 2A E3 55 E5 2A E1 55 E5 21 00 00 22 E3 55  ..*.U.*.U.!..".U
1410: 22 E1 55 CD C5 17 FE 94 C2 19 2A 3E B7 CD 5E 23  ".U.......*>..^#
1420: 3E CA 21 00 00 CD 79 23 2A 69 55 2B 2B 22 E1 55  >.!...y#*iU++".U
1430: CD 1A 25 CD 91 10 3A 93 55 FE BD 28 2A FE 95 28  ..%...:.U..(*..(
1440: 08 2A E1 55 CD C2 23 18 0D CD 1A 25 FE 93 28 17  .*.U..#....%..(.
1450: CD 6F 14 CD 91 10 2A E3 55 7C B5 C4 C2 23 E1 22  .o....*.U|...#."
1460: E1 55 E1 22 E3 55 C9 CD 6F 14 CD 1A 25 18 A4 2A  .U.".U..o...%..*
1470: E3 55 3E C3 CD 79 23 2A E1 55 CD C2 23 2A 69 55  .U>..y#*.U..#*iU
1480: 2B 2B 22 E3 55 C9 FE 3B C2 19 2A 3E C3 2A D9 55  ++".U..;..*>.*.U
1490: CD 79 23 2A 69 55 2B 2B 22 D9 55 C3 1A 25 FE 99  .y#*iU++".U..%..
14A0: C2 19 2A CD 1A 25 3D C2 19 2A 21 73 55 CD C0 08  ..*..%=..*!sU...
14B0: B7 28 0D 3E 98 32 73 55 21 00 00 22 80 55 18 1E  .(.>.2sU!..".U..
14C0: 3A 73 55 47 E6 0F FE 08 C2 19 2A 2A 80 55 78 87  :sUG......**.Ux.
14D0: 38 0C 3E 18 CD 35 15 3E C3 DC 79 23 18 13 3E C3  8.>..5.>..y#..>.
14E0: CD 79 23 2A 69 55 2B 2B 22 80 55 21 73 55 CD 39  .y#*iU++".U!sU.9
14F0: 08 CD 1A 25 FE 3B C2 19 2A C3 1A 25 FE 3B C2 19  ...%.;..*..%.;..

      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
1500: 2A 3A E9 55 B7 28 12 3E C3 2A EA 55 CD 79 23 2A  *:.U.(.>.*.U.y#*
1510: 69 55 2B 2B 22 EA 55 18 05 3E C9 CD 5E 23 C3 1A  iU++".U..>..^#..
1520: 25 FE 3B C2 19 2A 3E C3 2A 63 55 11 03 00 19 CD  %.;..*>.*cU.....
1530: 79 23 C3 1A 25 E5 F5 ED 5B 69 55 13 13 B7 ED 52  y#..%...[iU....R
1540: D1 5D 7D 87 9F BC E1 20 05 CD 6F 23 B7 C9 37 C9  .]}.... ..o#..7.
1550: DD E1 2A D7 55 E5 2A D9 55 E5 21 00 00 22 D9 55  ..*.U.*.U.!..".U
1560: 2A 69 55 22 D7 55 DD E9 DD E1 2A D9 55 7C B5 C4  *iU".U....*.U|..


stellar言語の特徴ですが、基本データ長は8ビットです。(68系のTL/1と同じですね)

しかし、64KBのメモリ範囲をアクセスできる関数が用意されているので、それ程不都合はないようです。また、制御構文も if, while, until, for, loop文があるのでプログラムが組みやすいようです。

特筆すべきは、inline文が用意されていて、プログラム中に機械語命令やデータを入れることができることと、インデックスレジスタ IX,IYを操作する文があることです。

書籍にはサンプルとしてファイルダンプ fdumpとハノイの塔 hanoi がありましたので、それらを参考にして、メモリダンププログラム mdump を作成してみました。


	/* memory dump */

prog	mdump();

cons    ngetchr := 1,                    /* get chr from console */
    	nputchr := 2;                    /* put chr to console   */

var		d, i,
        sttadr[4], endadr[4],
        sadr[2], eadr[2],
		ch;

data	msttadr: "sttadr= $",0,
        mendadr: "endadr= $",0,
		header:	 "      +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF",0;

{
    /* input disp adrs area */
    putstr(;.msttadr);
    for i:=0 to 3 {
        sttadr[i] := getchr();
    }
    putnl();
    putstr(;.mendadr);
    for i:=0 to 3 {
        endadr[i] := getchr();
    }
    putnl(2);
    sadr[0] := (sttadr[0]-$30)*$10+(sttadr[1]-$30);
    sadr[1] := (sttadr[2]-$30)*$10+(sttadr[3]-$30);
    eadr[0] := (endadr[0]-$30)*$10+(endadr[1]-$30);
    eadr[1] := (endadr[2]-$30)*$10+(endadr[3]-$30);
    
    /* disp memory data */
    sadr[1] := sadr[1] & $f0;                                           /* start from adrlow=$x0 */
    {
        putstr(;.header);
        putnl();
        {
            puthex(sadr[0]); puthex(sadr[1]);putchr(':');putchr(' ');   /* disp adrs */
            for i:=0 to 15 {
              puthex(memory[sadr[0], (sadr[1])+i]); putchr(' ');        /* disp by hex */
            }
            putchr(' ');
            for i:=0 to 15 {
                d:=memory[sadr[0], (sadr[1])+i];
                ch:= ?(d>=$20 & d<=$7e;d,'.');
                putchr(ch);                                             /* disp by ascii */
            }
            putnl();
            sadr[1] := sadr[1] + $10;
        } until (((sadr[0] <> eadr[0]) & (sadr[1] = $00)) | ((sadr[0] = eadr[0]) & (sadr[1] > eadr[1])));
        putnl();
        sadr[0] := sadr[0] + 1;
    } until  ((sadr[0] > eadr[0]));
}

/***** subroutine *****/

getchr();
{
    bdos(ngetchr);
}

putchr(x);
{
    bdos(nputchr, x);
}

putnl(n);
cons
    cr := $0d,
    lf := $0a;
var
    pn at ( _work );
{
    if pn=0 then n:=1;
    loop #,n {
        bdos(nputchr, cr);
        bdos(nputchr, lf);
    }
}

putstr(;ix);
var x;
{
    while x:=@[ix+] {
        bdos(nputchr, x);
    }
}

puthex(h);
{
    puthex1(h>>4);
    puthex1(h);
}

puthex1(h);
{
    bdos(nputchr, ?((h:=h & $0f)<10 0005h="" _work="" a="" argn="1" at="" bdos="" br="" c="" call="" cd="" d1="" dd="" de="" e1="" e5="" e="" else="" f="" fd="" func="" h="" hl="" if="" inline="" ix="" iy="" ld="" pop="" push="" then="" var="" x="">


この例で分かりますように、CP/MのBDOSを直接呼べますので、I/O関連のプログラムも容易に作成できます。ということで、GAMEやTL/1言語のようなマシンに密着したツールソフトを作成するのに向いている言語ではないかなという印象です。以上、書籍に掲載されていたCP/M版のZ80用の8ビットコンパイラを入力して、簡単なサンプルプログラムを作ってみたという報告でした。 

もし、使ってみたいという方がおられましたら、メールで連絡をくだされば実行ファイル(stellar.comとconvobj.com)を返信メールに添付してお送りできます。 (もっとも、書籍中の構文や文法の解説を読まないと、使ってみるのもなかなか大変ですが。)

2023年7月4日火曜日

コンパイラ作成の試み その2 言語の拡張(コメントとFOR文など)

 コンパイラ作成の試み その2 言語の拡張(FOR文で四苦八苦)


(表示用のアイコンとして入れてあります)

前回からずいぶんと時間が過ぎましたが、言語の拡張がなかなかうまくいかず、四苦八苦していますが、とりあえず現在の状況です。

拡張したのは以下の3つです。

1.コメント文が使えるようにした。

  プログラム作成時にはコメントアウト機能は必須だと思いますので、/*と*/で囲んだ部分はコメントとして読み飛ばされるようにしました。

2.PRINT文(PRINTLNも)の書式を変更した。

  C言語に慣れているせいか PRINT文の書式には違和感がありましたので、プリントする式部分を括弧で囲むように書式を変更しました。

  変更前:PRINT I, ": ", DATA[I];

  変更後:PRINT (I, ": ", DATA[I]);

3.FOR文を追加した。(...未完成)

  制御文としては、IF文、WHILE文、DO..WHILE文があるのですが、やはりFOR文があると便利ということで追加してみようと試みました。

1と2は何とか実現できたのですが、3のFOR文の追加については四苦八苦した挙句、一応それらしく動作するものができたのですが、動作が思ったようにはなりません。。。

  例えば FOR (I=0; I<10; I=I+1) PRINT(I,","); の場合

  結果は 1,2,3,4,5,6,7,8,9,10 となってしまうのです。

その理由ですが、FOR文を頭から見ていくため、まず I=0 の初期設定で I の値を設定し、次に I<10 の終了条件の真偽判定をして、真の場合は続いて I=I+1 の増分を実行してから PRINT文を実行した後にFOR文の先頭に戻るという手順を繰り返すために、繰り返しの1回目から制御変数の増分を実行してしまうためです。

この言語は全てをスタックに積む形式で行っているために、途中経過をどこかに保存しておくということができず、プログラムをシーケンシャルに実行していくために、このような結果になってしまっています。

(WHILE文やDO..WHILE文ではシーケンシャルに実行していって正しい結果が得られるような書式になっています。)

スタック言語ではFOR文のような、解析した順序とは異なる順序で実行しなければならない文は不可能なのでしょうか。それとも何か実現できるような手法があるのでしょうか。

(そういえば、中田先生のPL/0にもFOR文はありませんね、、、)

私の知識・経験不足のためにこれ以上は無理なようですので、言語の拡張はここまでにして、次は、中間言語に変換しているところを直接6809の命令語に変換するように変更して、6809機で動作するコードを生成するコンパイラに仕上げていこうと思います。


2023年5月20日土曜日

コンパイラ作成の試み その1「ハイクラスC言語」のリストを入力



 コンパイラを作ってみたくて「ハイクラスC言語」のリストを入力してみました

昔からコンパイラの自作に憧れていまして、入手した書籍は十数冊になると思いますが、本をいくら読んでも(もちろん、完全に理解できるまで読み込めていないのですが)、コンパイラ(あるいはインタプリタ)の構造についてはおぼろげには理解できたような気がしても、実際のプログラムをどのように構成すればよいのかが良く分かりませんでした。

目標は6809用の整数型のコンパイラの自作なので、特に具体的なコード生成手法を知りたいのですが、何しろコンパイラの本というのは理論的な本が多くて、、、


今までに読んだ本で印象に残っている本を挙げると、


・明解入門 コンパイラ・インタプリタ開発 (林晴比古 SoftBank社)
 分かりやすかったのですが、変数の使える電卓プログラムまででめげました。

・Go言語でつくるインタプリタ (Thorsten Ball著、設楽洋爾訳 技術評論社)
 段階ごとにテストで確認しながら進む手法に感心しましたが、使ったことがないGo言語に戸惑いながらでしたので、途中で力尽きました。

・コンパイラ 作りながら学ぶ (中田育男 オーム社)
 言わずと知れた中田先生の本です。この本で扱われているPL/0をFLEX9上のMicroCコンパイラを使用して6809に移植しようと試みたのですが、私には無理でした。

・Z80CPU対応 新言語作成の技法 (大貫広幸著 MIA社)
 ほとんど使用経験のないZ80の本ですが、この本で初めてコード生成の具体的手法を知りました。後半はPC-8801とCP/M-80で動作するコンパイラ言語Stellarのアセンブルリストが掲載されています。(いつかCP/M-80版を入力してみたいです。120ページ以上ありますが

・ハイクラスC言語 (末石吾朗、小林優 技術評論社)
 具体的なコード生成に重点を置いているので読みやすいです。仮想マシンの命令コードを設定して、それに対応するコンパイラと、生成された仮想コードを解釈・実行するインタプリタのソースリストが掲載されています。

何冊読んでもなかなか進めないので、思い切って作り始めようと考えたのですが、実は今までにも始めながら途中で投げ出したことが数回ありますので、ゼロから作り始めるのは無理だと考えて、大昔に購入して本棚に入れたままになっていた「ハイクラスC言語」中のリストをまず入力して、その仮想マシンの部分を6809に置き換えるという方針で始めることにしました。




何とプログラムリストの一部が欠落していた


コンパイラプログラムmccとインタプリタプログラムmaiを入力してみました。
入力してみて初めて分かったのですが、何とmccの8個のファイルのうちの c_dec.c のリストが抜け落ちているのです。。。(誤植にしてはヒドイ...)
ただ、その中に3つの関数があることは分かっていて、それらの処理内容も本文中に書かれているので、既に他のファイルは入力してしまったこともあり、何とか自分で記述するしかないと覚悟をしました。
(ちなみに、所有しているのは平成5年の初版で誤植が非常に多いのですが、30年前のものなので、出版社のサイトを見ても関連する資料が見つかりません...)

作成しなければならない関数は、変数宣言を処理する vardec()、関数を処理する function()、文をコンパイルする statement()の3つです。
その仕様についての解説です。

vardec関数の仕様

function関数の仕様

statement関数の仕様


四苦八苦しながら2週間近くかかって何とかエラーが出ない状態にすることができましたが、その過程でプログラムの構造について結構理解が進んだような気がしますので、結果的には良かったと考えることにします。


30年も前の書籍ですし、今更リストを入力しようとする方もおられないとは思いますが、私が書いた c_dec.c を下に示しておきます。(書籍中のリストにこれを追加することで、一応、正常に動作すると思います。)

/***********************************************************************
 ****																****
 ****	c_dec.c	Micro C Compiler declaration procedure file	    ****
 ****																****
 ***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "c_mcc.h"

/***************************************************************
 *		vardec()		変数宣言の処理
 *			戻り値:	なし
 *			引数:		なし
 ***************************************************************/
void vardec(void)
{
	do {
		getsym();
		if (sym != IDENT)
			puterr("Variable ID expected.");
		getsym();
		if (sym != LBRCKT) {	/* 単純変数 */
			enter(VAR_SMPL);
			gen(VAR_SMPL, lblcnt++);
		}
		else {					/* 配列変数 */
			getsym();
			if (isdigit(sym) != 0)
				puterr("Number expected.");
			enter(VAR_ARY);
			gen(VAR_ARY, lblcnt++);
			
			getsym();
			if (sym != RBRCKT)
				puterr("']' expected.");
			getsym();
		}
	} while(sym == COMMA);
	
	if (sym != SEMICOL)
		puterr("';' expected.");
	getsym();
}

/***************************************************************
 *		function()		関数処理
 *			戻り値:	なし
 *			引数:		なし
 ***************************************************************/
void function(void)
{
	int i, mflag;
	int j;
	
	source_f();
	if ((i = position()) < 0) {
		label(lblcnt++, fp);
//		enter(FUNCID);
		enter(UNDEFID);
	}
	else {
		if (strcmp(id, "main") == 0) {		/* if "main" */
			j = 0;
			while (strcmp(idtbl[j].name, id) != 0 && j <= idcnt) {
				j++;
			}
			if (j < idcnt) {				/* already exist */
				if (idtbl[j].kind != UNDEFID) {
					puterr("Symbol redeclarated.");
				}
				else {
					mflag = ON;
					label(0, fp);
//					enter(BLTFUNC);
					idtbl[j].kind = BLTFUNC;
					idtbl[j].addr = j;
				}
			}
		}
		else if (idtbl[i].kind == UNDEFID) {
			label(idtbl[i].addr, fp);
//			enter(FUNCID);
			idtbl[i].kind = FUNCID;
//			idtbl[i].addr = lblcnt;
		}
		else
			puterr("Symbol redeclarated.");
	}
	
	getsym();
	if (sym == LBRACE) {
//		i = 0;
//		while (strcmp(id, idtbl[i].name) != 0 && i < idcnt)
//			i++;
//		label(idtbl[i].addr, fp);
		getsym();
		while (sym != RBRACE) {
			statement();
			if (sym == EOFSYM)
				puterr("'}' expected.");
		}
//			if (strcmp(id, "main") == 0 && mflag == ON) {	/* if "main" */
			if (mflag == ON) {	/* if "main" */
				gen(JUMP, 1);
				mflag = OFF;
			} else
				gen(RET, DUMY);
//		}
	}
	else
		puterr("'{' expected.");
	
	getsym();
}

/***************************************************************
 *		statement()		文処理
 *			戻り値:	なし
 *			引数:		なし
 ***************************************************************/
void statement(void)
{
	switch (sym) {
		case IDENT:
					assign();
					break;
		case IFSYM:
					if_proc();
					break;
		case WHILESYM:
					while_proc();
					break;
		case DOSYM:
					do_while();
					break;
		case CALLSYM:
					call_proc();
					break;
		case INPUTSYM:
					input_proc();
					break;
		case PRINTSYM:
					print_proc();
					break;
		case PRTLNSYM:
					print_proc();
					gen(NEW_LINE, 0);
					break;
		case LBRACE:
					lbrace();
					break;
		case SEMICOL:
					getsym();
					break;
		default:
			puterr("statement expected.");
	}
}



わずか160行ほどのプログラムの作成に2週間もかかってしまって情けないですが、他の関数の動作を推測・確認しながらでしたので、こんなものかなと、、、

入力して出来上がった言語mcコンパイラ・アセンブラの仕様ですが、2バイトの整数型のもので、次に示したhit & blowの例で大体の雰囲気が分かってもらえるかと思います。

var i, j, inp, cnt;
var ans[4], in[4];
var hit, blow;
var flag[10], endflag, once_more;

main
{
println "*** Hit & Blow ***";
println "Guess 4 digit number (Miunus to abort)";
do {
call game;
print "Once more ( YES: 1, NO: other ) ? ";
input once_more;
} while (once_more == 1);
println "See you again !";
}

game
{
call init;
cnt = 1;
endflag = 0;
do {
call inpnum;
if (inp < 0)
endflag = 1;
else
call compare;
cnt = cnt + 1;
} while (endflag == 0);
}

init
{
i = 0;
while (i < 10) {
flag[i] = 0;
i = i + 1;
}
i = 0;
while (i < 4) {
ans[i] = rnd % 10;
while (flag[ans[i]] != 0)
ans[i] = rnd % 10;
flag[ans[i]] = 1;
i = i + 1;
}
}

inpnum
{
do {
print "Guess ? ";
input inp;
if (inp >= 10000)
println "Too Big. Re-enter!";
} while (inp >= 10000);
in[0] = inp / 1000;
in[1] = (inp % 1000) / 100;
in[2] = (inp % 100) / 10;
in[3] = inp % 10;
}

compare
{
hit = 0;
blow = 0;
i = 0;
while (i < 4) {
j = 0;
while (j < 4) {
if (ans[j] == in[i]) blow = blow + 1;
if (j == 1) if (ans[j] == in[i]) hit = hit + 1;
j = j + 1;
}
i = i + 1;
}
blow = blow - hit;
print cnt, " times.  ";
if (hit == 4) {
println "Match !!";
endflag = 1;
}
else println "Hit=", hit, " Blow=", blow;
}

このコンパイラの拡張例として、言語仕様の拡張(関数の引数、戻り値、ローカル変数の追加)や、特定CPUのコードを生成するための手順が解説されていますので、これをベースにして、仮想マシンのコードを生成している部分を6809の命令に置き換えることができれば6809のコンパイラができるはずですので、ぜひ実現させたいと思っています。

以上、書籍「ハイクラスC言語」中のコンパイラ・インタプリタのリストを入力してみたという紹介でした。