2020年4月29日水曜日

CP/M用の仮想ドライブの構築ソフト

CP/M-80用の仮想ドライブ構築ソフトCpmDrvWin.exeを作りました。



FM-7用の自作Z-80カードのためのCP/Mを制作中ですが、何回も起動を繰り返すので、フロッピーディスクから起動したり、読み書きするのは結構面倒です。
とりあえず起動するのはフロッピーからでも仕方がないとして、せめて読み書きはもっと便利にしたいし、ファイルをWindowsとの間で自由にやり取りしたいと考えて、自作CP/MのBIOSの仕上げを中断して、仮想ドライブ構築ソフトCpmDrvWin.exeの制作に取り掛かりました。

今までにFlex9用、OS-9用、F-Basic用を作ってきましたが、CP/M用については、以前作ろうと試みたものの、CP/Mのファイルシステムが理解できず挫折していました。
今回は中日電工の菱田さんのブログで勉強しましたので大丈夫だとは思いましたが、それでも意外に時間がかかりました。

CP/Mのファイルシステムというかディレクトリの構成法は他のDOSと比較すると、原始的というかどうしてこうなっているのかと思えるもので、中でも特に、同じファイル名のディレクトリエクステントが複数存在する(それも、ディレクトリ全体を読まないと幾つあるかも分からない...)のには参りました。

とりあえず第1版として出来上がったものが動作している様子を示します。


CpmDrvWin.exeの動作画面


下のXM7上で動作しているFM-CP/Mと同じ情報が(並び順は異なりますが)表示されているのが分かると思います。
XM7ではスクロールアップしてしまったものはもう見ることはできませんが、CpmDrvWin.exeでは自由にスクロールアップダウンしてみることができます。


XM7上のFM-7 CP/Mの動作画面

機能としては、
・ファイルの追加(リストボックス中へのドラッグ&ドロップによる)
・ファイルの名称変更、削除、Windowsへの読み出し(ファイルを選択してからの右ボタンメニューによる)
・全ファイルのWindowsへの読み出し(編集メニュー中のコマンドによる)
があります。

現在は、表示されているドライブがWindows上の仮想ドライブとして見えるように、CP/M側のBIOSを手直し中です。
しばらく使用して不具合などを修正したら、CP/MのBIOSと共に公開する予定です。


2020年4月18日土曜日

FM-7用の自作CP/Mがとりあえず動作しました

自作したZ80カード用に制作しているCP/Mがとりあえず動作しました

 

動作しなかった原因は

前回は動作していないと報告しました。その原因はいくつかありましたが主なものは以下の2つでした。
(1)DMAADRSの読み方が間違っていた
 FDDの読み書き時に用いるバッファのアドレスをZ80で設定して6809で読む際に、例のビッグエンディアンとリトルエンディアンの違いに引っかかってしまった。

(2)CP/Mでもセクタ番号が1から始まっているものと思い込んでいた。
 CP/Mでははセクタ番号は1ではなく0から始まるのですが、参考にした本(「CP/M80の世界」 工学社)でも1から始まるように書かれていたので信じ込んでしまった。

(2)は決定的でした。(1)に気づいて修正してDirectoryが表示されるようになったのですが、ファイル内容をTYPEしてみると半分ゴミが混じるのです。
プログラムを何回見直しても間違いが見つからず困っていましたが、そういえば中日電工の菱田さんのブログではセクタ番号を0からにしていたなと思い出して、それに合わせてプログラムを書き直したところようやく動作しました。

動作の様子

動作画面を示します。


CP/M起動画面


6809用のBIOS09を別ファイルにしてあるので、CP/M本体(Z80側のBIOS80を含む)、BIOS09の順に読み込んで、BIOS09を起動すると6809側の初期化をした後Z80に動作を移してCP/Mが起動します。
FM-CP/M用のフロッピーディスクがありましたので、それを読み込ませています。


コマンドも動作しています


STATコマンドやTYPEコマンドが正常に動作しています。

メモリマップ

RAMディスクが無くなったので、TPAが$0100から$47FFまでと広くなりました。
サイズとしては25K CP/Mということでしょうか。
しかし、F-BASICと共存する形ですのでちょっと窮屈です。

左:以前のもの 右:今回のもの




以前報告した自作のRS232Cカードも装着しており、RS232CのI/Oルーチンも実装しているので、WindowsからHEXファイルを読み込めますし、それなりに使える状態になっているかなと思います。

これから

変更すべき重要な点は2つあります。
(1)ブロッキング、デブロッキングをまともにしていない。
書き込み時にはまずCP/Mでの2セクタ(256バイト)を読み込んで、それに書き込むべき1セクタ(128バイト)を重ね書きしてからそれをフロッピーに書き込んでいます。
また読み込み時も、連続したセクタの読み込みでバッファにデータがあっても毎回フロッピーを読み込んでいます。
とりあえず動作させるためでしたが、流石に何とかしないと恥ずかしい。

(2)メモリマップで分かりますようにF-BASICのROMが邪魔をしていますので、オールRAMの状態で動作するように手直しをしなければもったいない。

また、今どきフロッピーディスクでもないので、ドライブC:やD:にWindows上の仮想ドライブを設定してFlex09やOS-9のように仮想ドライブをメインにしたいという希望もあります。
これが実現できると、ファイルの保存がWindows上でできるので、使い勝手がそれなりに良いCP/Mになるのではないでしょうか。

自作のCP/Mであれば機能の拡張も可能でしょうし、お仕着せのメーカー製よりもいじりがいがありそうです。BIOS09を拡張すればあれこれできそうで楽しみです。

しかし、不思議なのですがCP/MはなぜFAT情報(に相当するもの)をディスクに持たない設計にしたのでしょう。以前、Flex09, OS-9, F-BASIC用の仮想ドライブソフト(FlexDrvWin.exe, OS9DrvWin.exe, FBasDrvWin.exe)を製作した時と同じようにCpmDrvWin.exeを作ろうとしたことがあったのですが、ディスクの入れ替え時の切り替えの面倒さでメゲてしまったことがありました。

最後に

まず中日電工の菱田さんに感謝いたします。
80系の経験がほとんどない私が曲がりなりにも作ることができたのも菱田さんのブログのおかげです。またND80Z3.5のマニュアル中のZ80や8080の命令表もとても分かりやすくて助かりました。

今はCP/Mのソースも公開されており、個人使用なら自由に使えるようですし、Z80カードも費用がそれ程かからず製作できますので、FM-7やFM-77をお持ちの方が遊んでみるのには向いているのではないでしょうか。
フロッピーディスクがなくても、RAMディスク版をオールRAMで動作させれば良いのですから、必要なのはZ80カードのみです。(RS232Cカードも必要かも)
280回も続くブログですが、117回まで読めばRAMディスク版が作れます。私は第87回ででき上がったファイル cpm22l.txt を元にしました。

参考にはならないと思いますが、私が製作したBIOS09を載せておきます。まだ途中の段階のものですが、FM-7のBIOSを使えばこの程度で動作するのだという見本ということで。
Z80の方は、基本的にパラメータを書き込んでコマンド番号を設定しているだけです。

*
* MY BIOS09 for CP/M-80
*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ENTRY EQU $6233
FBASE EQU $5406 ;BDOS ENTRY POINT
DPBASE EQU $6239 ;DISK PARAMETER HEADER BASE
TDRIVE EQU $04
TBUFF EQU $80 ;i/o buffer and command line storage.
TRKADRS EQU $4B90
SCTADRS EQU $4B92
DMAADRS EQU $4B94
DRVNO EQU $4B96
CMDNO   EQU $4B98
PTO09   EQU $4B99
PTOZ80  EQU $4B9B
KCSAVE  EQU $4B9D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

*---------- 6809 routine ----------
 ORG $6800
*
BIOS EQU $FBFA
ACK EQU $06 ;
NAK EQU $15 ;
ESC EQU $1B ;

*USART 8251A
SDATA EQU $FD06 ;DATA
SCMD EQU SDATA+1 ;CMD
SSTS EQU SDATA+1 ;STATUS

MRSTU EQU $40 ;master reset
MODEU EQU $4E ;1stopbit,non pari,8bit,16x
CLRTSU EQU $15 ;RTS=H,ER,RxE,TxEN
SERTSUR EQU $34 ;RTS=L,ER,RxE for receive
SERTSUS EQU $31 ;RTS=L,ER,TxEN for trans
TxEMPTY EQU $04

START EQU *
*initialize
* reset 8251A
 CLRA
 STA SCMD
 STA SCMD
 STA SCMD
 LDA #MRSTU ;reset
 STA SCMD
 LDA #MODEU ;1stop,nonpari,8bit,16x
 STA SCMD
* set command to 8251A
 LDA #CLRTSU ;RTS=H,ER,RxE,DTR,TxEN
 STA SCMD

*set Z80 cold start
*write to $0000
 LDX #0
 LDA #$C3
 STA ,X+
 LDD #ENTRY
 EXG A,B
 STD ,X++

*go to Z80
TOZ80 EQU *
 LDX #$FD05
 LDA #1
 STA ,X
 NOP

*from Z80
*****************************
CMDIN LDA CMDNO
 CMPA #2
 BEQ CONST
 CMPA #3
 BEQ CONIN
 CMPA #4
 LBEQ CONOUT
 CMPA #5
 LBEQ LIST
 CMPA #6
 LBEQ PUNCH
 CMPA #7
 LBEQ READER
 CMPA #8
 LBEQ HOME
 CMPA #9
 LBEQ SELDSK
 CMPA #10
 LBEQ SETTRK
 CMPA #11
 LBEQ SETSEC
 CMPA #12
 LBEQ SETDMA
 CMPA #13
 LBEQ READ
 CMPA #14
 LBEQ WRITE
 CMPA #15
 LBEQ LISTST
 CMPA #16
 LBEQ SECTRAN
 BRA TOZ80
*****************************
*
CONST EQU * ;2
 LDX #RCBKIN
 JSR [BIOS]
 CLRB ;00
 LDA RCBDBA+1 ;1:keyin, 0:none
 BEQ CS1 ;not keyin
 LDA RCBDBA ;keycode
 DECB ;ff
CS1 STA KCSAVE ;0 or keycode
 STB PTOZ80 ;0 or ff
 LBRA TOZ80

*
CONIN EQU * ;3
 LDA KCSAVE 0:none, !0:keycode
 BNE CI2
 LDX #RCBKIN
CI1 JSR [BIOS]
 LDA RCBDBA+1 ;keyin?
 BEQ CI1
 LDA RCBDBA
CI2 STA PTOZ80
 LBRA TOZ80

*
CONOUT EQU * ;4
 LDA PTO09
 LDX #RCBOUT
 STA RCBDBA
 LDD #$0001
 STD RCBLNH
 JSR [BIOS]
 LBRA TOZ80

*
LIST EQU * ;5
 LDA PTO09
 LBSR SNDCH
 LBRA TOZ80

*
PUNCH EQU * ;6
 LDA PTO09
 LBSR SNDCH ;rs232c
 LBRA TOZ80

*
READER EQU * ;7
 LBSR RCVCH ;rs232c
 STA PTOZ80
 LBRA TOZ80

*
HOME EQU * ;8
 LDX #RCBRST
 LDA PTO09
 STA 7,X
 JSR [BIOS]
 LBRA TOZ80

*
SELDSK EQU * ;9
 LBRA TOZ80

*
SETTRK EQU * ;10
 LDX #RCBRWD
 LDA TRKADRS
 CMPA #39
 BLS STT1
 CLRA
STT1 STA 4,X
 LBRA TOZ80

*
SETSEC EQU * ;11
 LDX #RCBRWD
 BSR SETSCT ;A:sct,B:side
 STD 5,X
 LBRA TOZ80

*
SETDMA EQU * ;12
 LBRA TOZ80

*
READ EQU * ;13
 BSR READSUB
*set read data
 LDX #RCBBUF
 TST BUFHL ;0:even, 1:odd
 BEQ RE1
 LDB #128
 ABX ;rcbbuf+128
RE1 PSHS D
 LDD DMAADRS
 EXG A,B
 TFR D,Y
 PULS D
 LDB #128
RLOP LDA ,X+
 STA ,Y+
 DECB
 BNE RLOP
 CLRA
 STA PTOZ80
 LBRA TOZ80

*
READSUB EQU *
 LDX #RCBRWD
 LDA #10 ;read cmd
 STA ,X
 LDD #RCBBUF
 STD 2,X
 LDA TRKADRS ;trk
 STA 4,X
 BSR SETSCT ;A:sct,B:side
RS2 STD 5,X ;sct,side
 LDA DRVNO ;drv
 STA 7,X
 JSR [BIOS]
 RTS

*
*return A:sct,B:side,BUFHL:0or1
SETSCT EQU *
 CLRB
 CLR BUFHL
 LDA SCTADRS ;sct
 BITA #$01
 BEQ SE1
 DECA
 INC BUFHL ;0:even, 1:odd
SE1 LSRA
 INCA
 CMPA #16
 BLS SE2
 SUBA #16
 INCB
SE2 RTS

*
WRITE EQU * ;14
*read
 BSR READSUB
*set write data
 LDX #RCBBUF
 TST BUFHL ;0:even, 1:odd
 BEQ WR0
 LDB #128
 ABX
WR0 PSHS D
 LDD DMAADRS
 EXG A,B
 TFR D,Y
 PULS D
 LDB #128
WLOP LDA ,Y+
 STA ,X+
 DECB
 BNE WLOP
*write
 LDX #RCBRWD
 LDA #9 ;write cmd
 STA ,X
 LDD #RCBBUF
 STD 2,X
 LDA TRKADRS ;trk
 STA 4,X
 BSR SETSCT ;A:sct,B:side
WR2 STD 5,X ;sct,side
 LDA DRVNO
 STA 7,X
 JSR [BIOS]
 CLRA
 STA PTOZ80
 LBRA TOZ80

BUFHL FCB 0

*
LISTST EQU * ;15
 CLRA not ready
 STA PTOZ80
 LBRA TOZ80

*
SECTRAN EQU * ;16
 LBRA TOZ80
*
*
RCBKIN FCB 21
 FCB 0
 FDB RCBDBA
 FDB 00

RCBOUT FCB 20
 FCB 0
 FDB RCBDBA
RCBLNH FDB 0001
*
RCBDBA RMB 2
*
RCBRST FCB 8
 FCB 0
 FDB 00
 FDB 00
 FCB 0
 FCB 0 DRVNO

RCBRWD FCB 9 9:dwrite, 10:dread
 FCB 0
 FDB RCBBUF
RCBTRK FCB 0 trk
RCBSCT FCB 0 sct
RCBSID FCB 0 side
RCBUNT FCB 0 DRVNO
*
*
*--------------------------------------
* receive from serial port
* (use USART 8251A)
*    A <- port
*
RCVCH EQU *
 LDA #SERTSUR ;RTS=L
 STA SCMD
 NOP
RCV1 LDA SSTS
 ASRA
 ASRA
 BCC RCV1
 LDA SDATA ;get data
 PSHS A
 LDA #CLRTSU ;RTS=H
 STA SCMD
 PULS A,PC
*
*--------------------------------------
* send to serial port
* (use USART 8251A)
*    port <- A
*
SNDCH EQU *
 PSHS A
 LDA #SERTSUS ;RTS=L
 STA SCMD
 NOP
SND1 LDA SSTS
 ASRA
 BCC SND1
 PULS A
 STA SDATA ;send data
 PSHS A
SND2 LDA SSTS
 BITA #TxEMPTY
 BEQ SND2
 LDA #CLRTSU ;RTS=H
 STA SCMD
 PULS A,PC
*

RCBBUF RMB 256

 END START


蛇足

製作したZ80カードですが、多少余りがありますので40Pコネクタとのセットで頒布しようと思い、ちょっと安い業者を見つけてコネクタを発注したのですが発送予定が何と7月末と言われました!
しかし待つしかありませんね。


2020年4月15日水曜日

FM-7用のCP/M制作の試み(まだ未完成ですが...)

Z80カードを製作したので、CP/M-80を自作して走らせてみようと考えました


今更8ビットのCP/Mでもないとは思いますが、大昔にFM-7のCP/MでTurboPascalを使用していたこともあり、Z80カードを製作したのを機会に、もう一度昔の環境を復活させてみたくなりました。

と言っても80系の経験はほとんどないので自力ではとても無理ですが、幸い手元には中日電工さんのND80Z3.5とCP/M互換DOSがありますので、当時中日電工の菱田さんがCP/M互換DOSを開発する一部始終を連載された2012年のブログを元にすれば作れるだろうと思いました。
(それに、実際の処理はFM-7のBIOSに丸投げすれば良いだろうという、甘い考えもありました。)

実際に取り掛かってみて、まず引っかかったのは機械語での6809とZ80の間の切り替えでした。何しろ、$FD05に1や0を書いて切り替わった後に、どこへ飛んでいくかも分かっていないという無知な状態からのスタートです。
前回報告したATmega2560カードで四苦八苦しながら得た経験もあり、手探り状態ながら少しずつ進んできました。

ND80Z3.5用のRAMディスク版は移植できた

現在は、菱田さんのブログにあるND80Z3.5の32KBのRAM上で動作するRAMディスク版のCP/MがFM-7のDISK BASIC上でとりあえず動いたという状態です。
下にメモリマップを示します。

メモリマップ

TPAがわずか700hという超ミニサイズのCP/Mです。
使用したCP/Mのソースは公開されているcpm2-asm.zip中のcpm22.z80です。菱田さんのブログの通りにソースのバグを修正し、CONSOLE I/OとRS232CルーチンだけをFM-7用に書き直し、RAMディスク関係はND80Z3.5版をそのまま使わせてもらいました。



動作画面

CP/M本体をロードしておいて、6809用のBIOSをロードして実行するとCP/Mが起動します。この状態ではRAMディスクの中身は空ですが、菱田さんのブログでの手法を真似て6809のBIOSの起動中にTPAにプログラムを書き込んでおき、起動後にSAVEコマンドで保存しています。DIR,SAVE,ERAコマンドが正常に動作しています。

フロッピーディスク版はまだ動かない

次の段階として、フロッピーディスクのアクセスルーチンを書き、ディスク関係のパラメータを書き換えてRAMディスクからフロッピーに切り替えてみましたが、今のところ正常に動作していません。
FM-CP/Mのディスクを入れてDIR A:やDIR B:とすると、ドライブのアクセスランプは点灯してディレクトリを表示しようとするのですがファイル名が表示されません。
原因はまだ掴めていません。セクタブロッキング・デブロッキングあたりではないかと予想していますがどうでしょうか。

という現状報告でした。

2020年4月10日金曜日

ArduinoMega2560カードの紹介その後(完結編)

ArduinoMega2560カードが正常に動作するようになりました


前回、FM-7の40Pスロットで動作するArduinoMega2560カードを紹介しましたが、その際、動作後に6809に戻すためにはFM-7のメインRAMのリフレッシュ信号が必要であること。それをMega2560のソフトで実現したいが、なかなかうまく行かず、F-BASICに戻ってはくるがエラーメッセージが出てしまうという報告をしました。

そのブログを読んで下さったtomi9さんから、すぐに具体的なアドバイスをいただきました。

オートリフレッシュを用いる

それは、FM-7のDRAMであるMB8265はオートリフレッシュ(RFSH Refresh)でリフレッシュできるということ(など)でした。私のDRAMに関する知識は数十年前のもので、RASオンリリフレッシュでリフレッシュするものだと思い込んでおりましたので、まさに目からうろこでした。
早速そのようにプログラムを修正し、リフレッシュ信号などのパルス幅もできる限りデータシートの値に近づけてみました。

その結果、かなり動作が安定し、相変わらずエラーメッセージが出るものの、いつも同じエラーメッセージが表示されるようになりました。

Z80W信号がHighになることを確認する

さらにtomi9さんからの追加のアドバイスによって、Mega2560から6809へ復帰するために$FD05に0を書き込んだ後に、Z80W信号が実際にHighに変わるのを確認するためのwhile文を追加したことで、ほぼ確実に6809に戻ってくるようになりましたが、まだ、BREAKキーを押して戻す必要がありました。

ついに

その後、「思い付きハードで七転八倒」さんによる動作確認の結果やお二人からのプログラムの修正案をいただきながらプログラムの細かい見直しをした結果、ついに、常に正常に復帰させることができるようになりました。


連続実行の結果


ご覧のように、何回連続実行してもちゃんとF-BASICに復帰して、20行が実行されてLISTが表示されています。

FM-7の個体差か

しかし、私の2台のFM-7ではどちらも正常に動作しましたが、tomi9さんや「思い付きハードで七転八倒」さんのFM-7でも同様に正常に動作するというわけではないようです。
同じFM-7でも微妙な個体差があるようで、リフレッシュや6809への切り替え時のタイミングの調整で対応する必要があるということでしょうか。


資料

「思い付きハードで七転八倒」さんより提供された回路図を示します。


回路図


FM-7とMega2560の動作のシーケンスを下に示します。

動作のシーケンス

まとめ

FM-7の40Pスロットに他のボードを装着して動作させる場合には、6809がHALTしているので、ボード側でDRAMのリフレッシュを行なわなければならないが、それをソフトで行う試みについて報告しました。

この試みから得られた知見

(1)6809から別のCPUに制御を移した場合は、そのCPUでDRAMのリフレッシュを行う必要があるが、そのリフレッシュ方法としてはオートリフレッシュ(RFSH Refresh)が使用できる。
(2)6809から別のCPUに制御を移すには$FD05に1を書き込むだけで良いが、6809に戻すには$FD05に0を書くだけでなく、QB, EBの制御も必要。
(訂正:ご指摘を受けて間違っていることに気づきましたので、訂正します。戻るときも$FD05に0を書くだけで良いです。)
(3)同じFM-7という機種でも、このような場合には「個体差」が結果に影響することがある。
(追記:この手法そのものがFM-7には不適切なために「個体差」が影響したと言うべきでした。)

最後に、オリジナルのボードを考案されたFS-Micro Corporationさん、そのボードを目的に合うように改造され、動作確認やアドバイスを下さった「思い付きハードで七転八倒」さん、そして重要なアドバイスをいただいたtomi9さんの諸氏に感謝いたします。

なお、Mega2560ボードの回路図とスケッチはOneDriveで公開しております。