Categories: R10コンピュータ

日立 MB-S1 S1-CP/M80 移植作戦 その21 BIOSの作成5

S1のFDD I/Fアクセス方法が分かってきたので、ここで一度整理しておきたいと思います。

S1のFDD I/Fアクセスのカギは$FF04のUNITSELだとは気付いていたのですがS1活用研究を読んでも
DRQは$FF02のリードとあり、いまいち理解できませんでした。

そこで、6809活用研究に掲載のMP-1870の回路図を眺めていると$FF04にはMB8876AのDRQもIRQリードできることが分かりました^^

■$FF04 UNITSELのビット割付け

$FF04 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
READ #DRQ N/A N/A N/A N/A DT/#ST0,1 DT/#ST2,3 #IRQ
WRITE
(MP-1870)
N/A NMIMASK DDEN HEAD1 MOTORON N/A Drive^1 Drive^0
WRITE
(S1/30-40)
#FDCENBL 8’RESET #DDEN HEAD1 MOTORON N/A Drive^1 Drive^0
S1活用研究ではDDENが#になっている?
MP-3560の資料を見るとMP-3550には無さそうなDT/#STという信号が増えているもよう・・ $FF04のリードで取得できるようですが何をする信号なのかご存じの方教えてください^^

■$FF08 HALT → WRITEでS1バス41ピン HALT をアクティブ、解除は37ピンの#RESET,又は#38ピンの#NMI又はFDCの#DRQ

■MB8876A関連のレジスタは

アドレス(Aモード) WRITE READ
$FF00 コマンドレジスタ ステータスレジスタ
$FF01 トラックレジスタ トラックレジスタ
$FF02 セクタレジスタ セクタレジスタ
$FF03 データレジスタ データレジスタ

これを踏まえてS1でFDDにアクセスする手順を整理すると、こんな感じになりそうです。

FDD I/Oアクセスメモ

 

基本的な手順

①システムクロックを1MHに設定
②UNITSELを設定(密度,サイド,モータオン,ドライブNo)
③FIRQ,IRQ禁止
④FDC IDLE確認
⑤FDCコマンド実行
⑥FDCコマンド完了待ち
⑦FDCからステータス受取り
⑧ステータスからエラーを判断
⑨UNITSELを設定(モータオフ)
⑩システムクロックを2MHzに設定
⑪FIRQ,IRQを許可
※メモ
TYPE1のコマンド完了は#IRQのNMI割込みをSYNCで遷移、TYPE2のコマンド完了は$FF04のBit0(#IRQ)で遷移させる。
1セクタ分のループ(256回)は定数でループせずに$FF04のBit7(#DRQ)で行う。

この手順に合わせて具体的な手順をメモしておくと

 

RESTORE(HOME)

①システムクロックを1MHzに設定→$FFEBに$0
②UNITSELを設定(密度,サイド,モータオン,ドライブNo)→$FF04に00101000(ドライブ0でモータオン)
③FIRQ,IRQ禁止→ORCC #$50
④FDC IDLE確認→ステータスレジスタでBit7=ノットレディ-とBit0=ビジーをチェック
⑤FDCコマンド実行→$FF00に$FF(コマンド$00の反転)
⑥FDCコマンド完了待ち→FDCからのIRQをNMIとしてSYNCで検出
⑦ステータスレジスタでコマンド実行結果を受取り→$FF00
⑧TYPE1のリザルトからBit4=シークエラ-,Bit3=CRCエラ-のビットをチェック
⑨UNITSELを設定(密度,サイド,モータオフ,ドライブNo)→$FF04に00100000(ドライブ0でモータオフ)
⑩システムクロックを2MHzに設定→$FFEBに$02
⑪FIRQ,IRQを許可→ANDCC #AF

 

SEEK

①システムクロックを1MHzに設定→$FFEBに$0
②指定セクタNoからサイドとB面の場合セクタ番号を補正
③②で算出したサイドを反映したUNITSELを設定(密度,サイド,モータオン,ドライブNo)→$FF04
④FIRQ,IRQ禁止→ORCC #$50
⑤FDC IDLE確認→ステータスレジスタでBit7=ノットレディ-とBit0=ビジーをチェック
⑥指定トラックNoを反転してデータレジスタにセット→$FF03 トラックレジスタではないので注意
⑦FDCコマンド実行→$FF00に$EF(コマンド$10の反転)
⑧ステータスレジスタでコマンド実行結果を受取り→$FF00
⑨TYPE1のリザルトからBit4=シークエラ-,Bit3=CRCエラ-のビットをチェック
⑩UNITSELを設定(密度,サイド,モータオフ,ドライブNo)→$FF04に00100000(ドライブ0でモータオフ)
⑪システムクロックを2MHzに設定→$FFEBに$02
⑫FIRQ,IRQを許可→ANDCC #AF
※メモ
READやWRITEと組み合わせで使用の場合①③④⑩⑪⑫はREAD,WRITE内で行う

 

1セクタREAD

①システムクロックを1MHzに設定→$FFEBに$0
②FIRQ,IRQ禁止→ORCC #$50
③SEEKサブルーチンで目的のトラックへ移動やサイド指定を済ませる
④UNITSELを設定(密度,サイド,モータオン,ドライブNo)→$FF04に00101000(ドライブ0でモータオン)
⑤トラックNoを反転してトラックレジスタにセット→$FF01
⑥セクタNoを反転してセクタレジスタにセット→$FF02
⑦FDC IDLE確認→ステータスレジスタでBit7=ノットレディ-とBit0=ビジーをチェック
⑧FDCコマンド実行→$FF00に$7F(コマンド$80の反転)
⑨FDCからの#IRQチェック→コマンド完了で#IRQ=0Bitがクリアされると終了⑩に分岐
⑩FDCからのDRQ待ち→$FF04のBit8が#DRQ→ビットがクリアされるまでループ
⑪#DRQ検出でデータレジスタから1バイト読込んでメモリに書込を繰り返す(⑨-⑪のループ)→$FF00
⑫ステータスレジスタでコマンド実行結果を受取り→$FF00
⑬TYPE2のリザルトから#Bit4=レコードノットファウンド, Bit3=CRCエラー, Bit2=データロストをチェック
⑭UNITSELを設定(密度,サイド,モータオフ,ドライブNo)→$FF04に00100000(ドライブ0でモータオフ)
⑮システムクロックを2MHzに設定→$FFEBに$02
⑯FIRQ,IRQを許可→ANDCC #AF
※メモ
1セクタ=256回のカウントはコマンド完了#IRQで検出しループから抜ける

 

1セクタWRITE

①システムクロックを1MHzに設定→$FFEBに$0
②FIRQ,IRQ禁止→ORCC #$50
③SEEKサブルーチンで目的のトラックへ移動やサイド指定を済ませる
④UNITSELを設定(密度,サイド,モータオン,ドライブNo)→$FF04に00101000(ドライブ0でモータオン)
⑤トラックNoを反転してトラックレジスタにセット→$FF01
⑥セクタNoを反転してセクタレジスタにセット→$FF02
⑦FDC IDLE確認→ステータスレジスタでBit7=ノットレディ-とBit0=ビジーをチェック
⑧FDCコマンド実行→$FF00に$5F(コマンド$A0の反転)
⑨FDCからの#IRQチェック→コマンド完了で#IRQ=0Bitがクリアされると終了⑩に分岐
⑩FDCからのDRQ待ち→$FF04のBit8が#DRQ→ビットがクリアされるまでループ
⑪#DRQ検出でメモリから1バイト読込んでFDCのデータレジスタに書込を繰返す(⑨-⑪のループ)→$FF00
⑫ステータスレジスタでコマンド実行結果を受取り→$FF00
⑬TYPE2のリザルトから#Bit4=レコードノットファウンド, Bit3=CRCエラー, Bit2=データロストをチェック
⑭UNITSELを設定(密度,サイド,モータオフ,ドライブNo)→$FF04に00100000(ドライブ0でモータオフ)
⑮システムクロックを2MHzに設定→$FFEBに$02
⑯FIRQ,IRQを許可→ANDCC #AF
※メモ
1セクタ=256回のカウントはコマンド完了#IRQで検出しループから抜ける


この手順が正しいかどうか不明ですが、一応目的の動作ができています。

実験しながら改良点があれば随時更新します

やっとS1のFDD I/Fにアクセスできる目途がついた、そんな記録・・・^^

kabekin

View Comments

  • 倉庫を漁って昔作った色々なコードのアセンブルリストやDISK-BASIC,BootROMなどの逆アセンブルリストを持って帰ってきました.プリントアウトしていたのは一部だけで,それ以外はフロッピーやHDDの中に入ったまま...
    こいつらを取り出す(読めるかどうか不明)のは大変です.
    あと,Level3のHuENGINEでCP/M80を動かしていた時の09側のコードのリストも見つかりました.
    S1用に作ったアセンブラのI/O(本体はインターフェイス誌'79.2月号のもの),アセンブラ版の逆アセンブラーのリスト(1985.10.27)とかも.
    必要な情報があれば分かるものはお答えします.

    • ありがとうございます。
      これまで書籍や雑誌の記事等でチェックしていましたが、HuEngineの情報入手は絶望的だと思っていましたので、何か情報が得られると嬉しいです^^
      是非とも活用してみたいボードなので、色々教えて下さい
      メールアドレスを頂いていますので、後程メールさせて頂きます。

  • ~DDENですが、MB8876/MB8877のデータシートによると37番ピンであり、
    どちらも負論理、1で単密度、0で倍密度のようです。
    ところで2HDのDiskBASICのレジスタアクセスパターンを見てみましたが、
    ちょっと複雑。Read sectorの後、$FF08に$FFを書き込んでなにか待っている様子です。
    samのルーチンは任意ドライブ、任意トラック、任意セクタ指定で複数セクタ連続読出し
    が実現できています。この後、Write sectorを実装し、Disk BASICによらない環境で動作確認
    で完了かと思います。おっと、Level3さんのご指摘も含めてコードの見直しも必要ですね(^^;ゞ

    • 6809活用研究でMP-1870の回路図を確認してみましたが8876のDDENが不論理なので途中のインバータを考えるとやはりBit5はHが倍密度っぽいですね。
      同じく6809活用研究で2HD用のFDCカードの回路を見てみると$FF08にWRITEするとS1バスを介して6809にHALTをかけるフリップフロップが入っていました。
      HALTのリセット条件は#RESETまたは#MNIまたはFDCの#DRQのようです。
      $FF08のREADは無さそうです
      先日頂いたコメントのおかげで、コンソールI/Oのサブルーチンは一応使えるようになりました。
      ディスクI/O関係のサブルーチン実装は難しいと思いますが、先が見えてきました(^^)

  • 2HDですが、FDCにコマンドを書いた後、$FF04のbit7をONにしてFDCをマスクします。すると、$FF02のbit7が#DRQとして見えるようになります。さらに、DRQが来たときのみ$FF03のDATA REGが見えるようになります。
    S1 DISK BASICでは、FDCをマスクした後、$FF08に書き込みをしてHALT状態になり、DRQで解除後すぐ$FF03をリードする処理になっていたと思います。

    • なるほど、S1活用研究に書かれていた解説はSasajiさんにコメントいた内容だったんですね。
      回路図からは$FF02のREADの動作を理解できませんでした^^;;;
      >FDCをマスクした後、$FF08に書き込みをしてHALT状態になり、DRQで解除後すぐ$FF03をリードする
      >処理になっていたと思います。
      こちらの情報をもとに上記のアクセス手順で高密度の項を整理しておきたいと思います^^

  • FDDやHDDからの読み取り方法を知るにはIPLやBOOT Loaderを解析するのが一番手っ取り早いと思いますよ.私はそうやってI/Oルーチンを自分のものにしてきました.読み込みと書き込みはわずかの違いだけで作る事ができますので,まずはBoot時の読み込み方法を解析するのが良いです.逆アセンブラがあればそれほど手間はかからないです.もちろんI/Oマップも知っておかないと何してるか分からないですが.

    • そうですね。
      実は今使っているCP/MのブートローダはDISKBASICのブートローダを使っており、メモリーマッピングの部分を少し変更しているだけになっていたりします。
      FD関係のI/Oマップは理解していたつもりだったのですが、高密度用は$FF02のREADを使っているなど、知らないこともあってまだまだ皆さんに教えて頂きながらでないと知識が足りないことを実感しています^^;;

  • うちに残っていたS1の2HDのIPLの逆アセンブルリストです.
    IPLは$2000番地にロードされ,その後IPLによってトラック1セクター1からのデータが$2200-$2500に読まれる用になっています.3セクター分ですね...
    2000: LDA #$28
    STA LFF14 ; = ($FF14)
    LDA #$2F
    CLRA
    CLRB
    BSR L2017
    LDA LFF10 ; = ($FF10)
    LDA LFF13 ; = ($FF13)
    JMP L202B
    ; Wait loop
    L2017: LDX #$0000
    L201A: JSR L2021
    LEAX -1,x
    BNE L201A
    RTS
    L2022: FCB $00 ; Track
    L2023: FCB $34 ; Sector
    L2024: FDB $0000 ; NMI vector save
    ;
    L2026: FDB $2200 ; Top Address
    L2028: FDB $2500 ; End Address
    L202A: FCB $FE ; DP Save
    L202B: TFR DP, B
    LDB #$FF
    TFR B,DP ; Set DP to $FF
    LDX L2026 ; Start Address Read
    JSR L20BE ; NMI vector set
    ;
    L203A: INC L2023 ; Inc sector No.
    LDB L2023 ; load sector No. to B
    CMPB #$34 ; sector No. >= 52 ?
    BLS L2067
    INC L2022 ; increase Track No.
    LDA #$01
    STA L2023 ; sector No. set as 1
    LDU #L205E ; NMI vector set to $205E
    STU LEEF5 ; ($EEF5)
    LDA L2022 ; Read Track No. to A
    COMA
    STA <$03 ; Track set to $FF03
    LDB #$EC ; ($13) Seek command
    STB <$00 ; Seek comannd set to $FF00
    L205C: BRA L205C ; Wait for NMI
    ; NMI after Seek
    L205E: LEAS $0C,S ; Stack adjust after NMI
    LDA <$00 ; ($FF00)
    COMA
    ANDA #$90 ;
    BNE L20B6
    L2067: LAD L2022 ; Track No. set to ($FF01)
    COMA
    STA <$01 ; ($FF01)
    LDA #$20
    LDB L2023
    CMPB #$1A ; if Sector Sector
    L207A: ORA #$08
    STA <$04 ;
    COMB
    STB <$04 ; Set Sctor to ($FF04)
    LDU #L2097
    STU LEEF5 ; (%EEF5)
    LDB #$7F ; ($80) Read Command
    STB <$00 ; ($FF00)
    STA <$08
    NOP
    L208E: LDB <$03 ; ($FF03)
    COMB
    STB ,X+
    LDA #$30
    STA <$04 ; HALT on
    BRA L208E
    ;
    L2097: LEAS +$0C,S
    LDB <$00
    LDA #$30
    STA <$04 ; ($FF04)
    COMB
    ANDB #$FC
    BNE L20B6
    CMPX L2028 ; Load finished?
    LBLS L203A
    BSR L20BE
    LDB L202A
    TFR B,DP ; Restore DP
    JMP [L2026] ; Jmp to the original NMI vector
    L20B6: LDB L202A
    TFR B,DP ; Restore DP
    BSR L20BE
    L20BE: PSHS U,X
    LDX LEEF5 ; ($EEF5)
    LDU L2024 ; Save and exchange NMI vector
    STX L2024
    STU LEEF5
    PULS X,U,PC

    • レベル3の倍密度ではFDCカードのブートROMでトラック0のセクタ1~2の512バイトが$4400~ロードされて実行されるというブートシーケンスは知っていたのですが、S1は情報がなくブートローダの逆アセンブルでブートの仕組みを教えて頂きました。
      高密度のブートローダも作成しましたが、セクタ0が単密度なので初期化処理を減らしたり、メッセージを短くしたりと倍密度のローダよりちょっと苦労しました^^

      • レベル3の倍密度フロッピーはトラック0の表だけが単密度でした.フォーマッターを作る時にも最後にトラック0の表だけ単密度でフォーマットするように作成したことを覚えています.
        これはいにしえの8インチのフロッピーがそのような仕様になっていたのを踏襲したからだと思われます.
        8インチは当初単密度だったものが後に倍密度が登場した関係でBOOT用のトラック0の表だけは単密度で統一してここが読めるようにしておいて,その後は読み込んだBOOTルーチンで残りを単密度でアクセスするか倍密度でアクセスするかできるようにしていたのです.
        レベル3も当初片面単密度の80KBであったのが後に両面倍密度の320KBに変更された事もあり,同様の仕様にしたのでしょうね.他の

        • レベル3の倍密度DISKBASICは持っていないので確認できていないのですが、S1の高密度DISKBASICのフロッピはトラック0の表のみが単密度ですよね。
          S1の倍密度DISKBASICはトラック0の表も倍密度なので扱いやすくて好きです^^;;
          レベル3の80KBディスクは3インチのCFで楽しんでいます^^
          http://asakita.net/kabekin/2014/10/9406.html

          • 私は当初MB6890には片面単密度のシングルドライブを使っていました.その後高校の先輩がMP-3550(倍密度FDDx2)を譲ってくれたので,こちらを使うようになりました.この時に単密度DISK-BASICの逆アセンブルリストからセルフアセンブラでアセンブルできるリストにしてディスクアクセスの部分をMP-3550用に書き換え,MP-3550でも単密度DISK-BASICが動くようにしました.倍密度のドライブは単密度も読み書きできるので,こんなことも可能でした...
            MB-S1/10は基本的に8インチ2台で動かしていたので,8インチのフロッピーに残っていますがこれは今となっては読み出すのは難しいです.幸い後からMB-S1/45も入手してこちらを使うようになったので5インチの2HDフロッピーにもデータは残っているはずなんです.起動できたらかつてのソースコードを探してみるつもりです.

  • Level3もブートローダはFDCを制御する必要があったんですね。
    S1もLevel3の文化を引き継いでいるんですかね?
    開発中のS1 CP/MにもなんとかFDアクセスルーチンを組み込みました。
    まだいくらか問題がありますが最低限の機能は実現できました。
    2HDタイプのほうは実現できてなく、Sasajiさんのコメントをたよりに作成か
    Level3さんの発掘コードに期待でしょうか・・(^^
    FMの場合はROMにFDアクセスルーチンを持っているのでブートローダは
    簡単な記述で済むばかりか、普通にプログラムからFD読み書きに利用することが可能で
    BIOS09の開発でも問題になることはなかったです。

    • samさん,2HDのIPLは片面単密度を読んでいますが,FDCの操作法は高密度も基本的に同じでI/Oポートの密度設定やサイド設定をするだけで読み込みルーチンの構造を変える必要はないです.
      個人的にはFDCを直接制御する方法の方が楽だと思っています.
      FMの場合もCP/M68KやOS9/68000のような別のCPUを使用する場合にはROMルーチンは使えませんから自前でFDCやDMACをコントロールする必要があります.周辺I/Oを直接操作する方法を知っていればCPUが変わろうがOSが変わろうが同じですので,こちらを知っておく方が便利です.

  • Level3さん、コメントどうもありがとうございます。
    たしかに言われることごもっとも。
    今回samはFDCについて全く知らなかった状態から多くのことを学べました。
    samはFMについては2Dの環境でROM内ルーチンを利用する方法しかしらないのですが
    2HD(2DD?)とか他CPUからの制御とか同様にできるんですね。
    I/O領域を6809と共有しているんでしょうね?

    • asmさん,I/Oアドレスは2Dが$FF00からで2HDは$FF10からだったと思います.2DのコントローラーがMB8866で2HDのコントローラーがMB8876と同じ富士通の石ですのでルーチンの組み方はさほど変わらないです.
      なお,ドライバーの工夫が必要ですが,2HDのドライブで2D,2DD,2HDの読み書きが可能になります.昔そのような仕様のドライバーを書いたことがあります.ただし,2HDのドライブで2Dを読み書きするには工夫が必要です.
      2Dと2DDの違いはトラック密度です.2Dは40トラック,2DDは80トラックです.つまり,2Dのトラック1にSEEKするためにはドライブにはまずトラック2にSEEKするコマンドを送り,読み書きする前にそのトラックの番号を1に指定して読み書きを実行します.このようにすることで3種類のメディアの読み書きができるのです.

      • S1のFDCカードの回路図を見てみると2D用のMP-1870も2HD用のS1/30-40用も両方ともMB8876のようでした。
        ドライバソフトの工夫でS1用の2HDデッキ(HFD516CT)で3モードできるようになると最高ですね^^;;