2012.1.22
前へ
次へ
ホームページトップへ戻る

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第12回]

●BIOSのディスクパラメータ

前回はCP/M BIOSのディスクアクセスルーチンについて説明をしましたが、ディスクパラメータも設定しなければなりません。
これもなかなかに面倒なものなのですが、CP/M2.2ソースプログラムのディスクパラメータの項目も、見事に抜けてしまっています。

こんな具合です。
;
;**************************************************************
;*
;*     BDOS data storage pool.
;*
;**************************************************************
;
EMPTYFCB: DEFB  0E5H            ;empty directory segment indicator.
WRTPRT: DEFW    0               ;write protect status for all 16 drives.
LOGIN:  DEFW    0               ;drive active word (1 bit per drive).
USERDMA:DEFW    080H            ;user's dma address (defaults to 80h).
;
;   Scratch areas from parameter block.
;
SCRATCH1: DEFW  0               ;relative position within dir segment for file (0-3).
SCRATCH2: DEFW  0               ;last selected track number.
SCRATCH3: DEFW  0               ;last selected sector number.
;
;   Disk storage areas from parameter block.
;
DIRBUF: DEFW    0               ;address of directory buffer to use.
DISKPB: DEFW    0               ;contains address of disk parameter block.
CHKVECT:DEFW    0               ;address of check vector.
ALOCVECT: DEFW  0               ;address of allocation vector (bit map).
;
;   Parameter block returned from the bios.
;
SECTORS:DEFW    0               ;sectors per track from bios.
BLKSHFT:DEFB    0               ;block shift.
BLKMASK:DEFB    0               ;block mask.
EXTMASK:DEFB    0               ;extent mask.
DSKSIZE:DEFW    0               ;disk size from bios (number of blocks-1).
DIRSIZE:DEFW    0               ;directory size.
ALLOC0: DEFW    0               ;storage for first bytes of bit map (dir space used).
ALLOC1: DEFW    0
OFFSET: DEFW    0               ;first usable track number.
XLATE:  DEFW    0               ;sector translation table address.
;
;
CLOSEFLG: DEFB  0               ;close flag (=0ffh is extent written ok).
RDWRTFLG: DEFB  0               ;read/write flag (0ffh=read, 0=write).
FNDSTAT:DEFB    0               ;filename found status (0=found first entry).
MODE:   DEFB    0               ;I/o mode select (0=random, 1=sequential, 2=special random).
EPARAM: DEFB    0               ;storage for register (E) on entry to bdos.
RELBLOCK: DEFB  0               ;relative position within fcb of block number written.
COUNTER:DEFB    0               ;byte counter for directory name searches.
SAVEFCB:DEFW    0,0             ;save space for address of fcb (for directory searches).
BIGDISK:DEFB    0               ;if =0 then disk is > 256 blocks long.
AUTO:   DEFB    0               ;if non-zero, then auto select activated.
OLDDRV: DEFB    0               ;on auto select, storage for previous drive.
AUTOFLAG: DEFB  0               ;if non-zero, then auto select changed drives.
SAVNXT: DEFB    0               ;storage for next record number to access.
SAVEXT: DEFB    0               ;storage for extent number of file.
SAVNREC:DEFW    0               ;storage for number of records in file.
BLKNMBR:DEFW    0               ;block number (physical sector) used within a file or logical sect
LOGSECT:DEFW    0               ;starting logical (128 byte) sector of block (physical sector).
FCBPOS: DEFB    0               ;relative position within buffer for fcb of file of interest.
FILEPOS:DEFW    0               ;files position within directory (0 to max entries -1).
;
;   Disk directory buffer checksum bytes. One for each of the
; 16 possible drives.
;
CKSUMTBL: DEFB  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
;   Extra space ?
;
        DEFB    0,0,0,0

ただ、よく見ますと値こそ入っていませんが、それぞれにかなり丁寧なコメントがついていて、値を設定する上で手がかりにはなりそうです。
このCP/M2.2ソースプログラムの先頭の部分を見ますと、下のように表示されています。
;**************************************************************
;*
;*             C P / M   version   2 . 2
;*
;*   Reconstructed from memory image on February 27, 1981
;*
;*                by Clark A. Calkins
;*
;**************************************************************
;
Clark A. Calkinsという署名があります。
このソースプログラムは、おそらく彼がオリジナルCP/Mを逆アセンブルして、そしてそこに先ほどのような詳細なコメントをつけたものでありましょう。
まさに労作です。

そのコメントと、Y様から送っていただいた3冊のCP/M解説書とから情報を得て、下のように値を入れました。
                        ;
  D1B3  E5              EMPTYFCB: DEFB  0E5H            ;empty directory segment indicator.
  D1B4  0000            WRTPRT: DEFW    0               ;write protect status for all 16 drives.
  D1B6  0000            LOGIN:  DEFW    0               ;drive active word (1 bit per drive).
  D1B8  8080            USERDMA:DEFW    8080H           ;12.1.5 ;user's dma address (defaults to 80h).
                        ;
  D1BA  0000            XLATE:  DEFW    0               ;sector translation table address.
                        ;   Scratch areas from parameter block.
  D1BC  C0B8            SCRATCH1: DEFW  0B8C0H          ;relative position within dir segment for file (0-3).
  D1BE  C2B8            SCRATCH2: DEFW  0B8C2H          ;last selected track number.
  D1C0  C4B8            SCRATCH3: DEFW  0B8C4H          ;last selected sector number.
                        ;
                        ;   Disk storage areas from parameter block.
                        ;
  D1C2  00B8            DIRBUF:DEFW     0B800H  ;address of directory buffer to use.
  D1C4  CAD1            DISKPB:DEFW     SECTORS ;contains address of disk parameter block.
  D1C6  80B8            CHKVECT:DEFW    0B880H  ;address of check vector.
  D1C8  A0B8            ALOCVECT:DEFW   0B8A0H  ;address of allocation vector (bit map).
                        ;
                        ;   Parameter block returned from the bios.
                        ;
  D1CA  1000            SECTORS:DEFW    16              ;sectors per track from bios.
  D1CC  02              BLKSHFT:DEFB    2               ;block shift.sector in a block 128*2^n
  D1CD  03              BLKMASK:DEFB    3               ;block mask.sector no. in a block - 1
  D1CE  00              EXTMASK:DEFB    0               ;extent mask.
  D1CF  1700            DSKSIZE:DEFW    23              ;disk size from bios (number of blocks-1).
  D1D1  1F00            DIRSIZE:DEFW    31              ;directory size.(max file name no.-1)
  D1D3  C000            ALLOC0: DEFW    0C0H            ;storage for first bytes of bit map (dir space used).
  D1D5  0000            ALLOC1: DEFW    0
  D1D7  0000            OFFSET: DEFW    0               ;first usable track number.
                        ;
前半部分は値の設定ではなくて、ワークエリアのアドレスの指定です。
USERDMAは本来は0080H〜00FFHですが、いまのところそこはROMになっていますから、今回は8080H〜80FFHを割り当てます。
SCRATCH1〜3は各2バイトのエリアです。
DIRBUFには128バイトのエリアを確保します。
CHKVECTとALOCVECTには、必要バイト数を算出してアドレスを割り当てるべきところなのですが、今はテストですから空いているところを適当に割り当てます。

さて、問題はその次からのディスクパラメータです。
最初のSECTORSは、1トラックを16セクタにしました([第10回])から、16です。
その次のBLKSHFTは何でしょう?
block shift.sector in a block 128*2^n
というコメントがついていますが、これだけではさっぱりわかりません。

●なぜブロックか?

突然にブロックなるものが登場してしまいました。
今までトラックやセクタは出てきましたが、ブロックというのは聞いたことがありませんでした。
CP/Mでは、このブロックというのは非常に重要な概念です。

ブロックを理解するには、まずCP/Mのディレクトリについて理解しなければなりません。
ディレクトリは現在のWindowsでも使われている言葉ですが、CP/Mでは最もシンプルな形で使われています。
フロッピーディスクにあるファイル名のアドレス帳のようなものです。
ディレクトリエリアという特別のエリア(複数のセクタから構成されている)に、ファイル名と、そのデータが書き込まれているセクタの情報などが1ファイルあたり32バイトを使ってまとめられています。
その様子は[第7回]にログファイルとしてお見せしました。
この部分です。

>d.,8800,88ff
8800  00 46 49 4C 4C 45 35 20-20 43 4F 4D 00 00 00 02  .FILLE5  COM....
8810  02 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8820  00 41 42 43 20 20 20 20-20 43 4F 4D 00 00 00 02  .ABC     COM....
8830  03 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8840  00 43 50 4D 54 53 54 39-20 43 4F 4D 00 00 00 02  .CPMTST9 COM....
8850  04 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8860  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
8870  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
8880  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
8890  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
88A0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
88B0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 30 E5 E5 E5  ............0...
88C0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
88D0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
88E0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
88F0  E5 E5 E5 E5 E5 E5 E5 E5-E5 E5 E5 E5 E5 E5 E5 E5  ................
ここには3つのファイルが登録されています。
このダンプリストの1行は16バイトですから、1つのファイルに2行(32バイト)が使われています。

上の行にはファイル名などが書かれています。
下の行にはデータのあるセクタ位置を示す情報が書かれます。

ここでは、最初のファイル(FILLE5.COM)には02が、次のファイル(ABC.COM)には03が、そしてその次のCPMTST9.COMには04が書き込まれています。
みんな小さなサイズのプログラムなので、それぞれ1つの数だけで終わっていますが、サイズが大きいファイルでは、その行にずらりと連続した数字(数字が飛ぶこともある)が並びます。
16バイト全部を使っても終わらないときは、別の32バイトのエリアを使って、その続きを書き込みます。

そのように、データの書かれているセクタ位置を1バイトの数で示すことにします。
そしてその数はトラックを無視して、先頭から順にセクタに番号をつけたものということにします。

するとここで困った問題が発生します。
CP/Mでは1セクタは128バイトとして扱います。
ところでフロッピーディスクにはいろいろなサイズ(記録容量)があります。
Windows用のフロッピーディスクは1.44MBです。
昔のCP/Mの時代のフロッピーディスクは、もっと小さなサイズのものが多かったのですが、それでも250KB〜500KB程度は普通にありました。

仮に計算を簡単にするために、フォーマット後の記録サイズが256KBのフロッピーディスクがあるとしましょう。
1セクタを128バイトとすると、このフロッピーディスクには約2000個のセクタがあることになります。
そのセクタに前から順に番号をつけていくと、0〜255で1バイトで表せる限界にきてしまいます。
とても全部のセクタを1バイトで示すことはできません。

そこでブロックという概念を使うことになります。
2000個(ここでは2048個にしましょう)のセクタは1バイトでは表すことはできませんが、もしも前から順に8個ずつのセクタをひとまとめにして、それをブロックという名前で表したとしますと、2048/8=256ですから、ちょうど1バイトで全部のセクタを示すことができます。
このようにして考えたのがブロックなのです。

[2012.2.13注記]
上ではサイズが大きいディスクでも、ブロック数は0〜255までしか表現できない、ということのように説明していますが、私の理解不足でした。
CP/Mでは256を超えるブロック数も扱うことができ、その場合にはブロック番号は2バイト16ビットで示されます。[注記ここまで]

説明が長くなってしまいました。
すると今回ND80ZVのRAM上に置いた仮想フロッピーディスクは6トラック96セクタですから、1ブロック1セクタとして扱っても1バイトで示すことができます。
しかし、これもテストですから4セクタを1ブロックとして扱うことにします。

さきほどのパラメータのリストがページの上のほうにいってしまいましたので、その部分だけもう一度下に示すことにします。
                
  
                        ;
                        ;   Parameter block returned from the bios.
                        ;
  D1CA  1000            SECTORS:DEFW    16              ;sectors per track from bios.
  D1CC  02              BLKSHFT:DEFB    2               ;block shift.sector in a block 128*2^n
  D1CD  03              BLKMASK:DEFB    3               ;block mask.sector no. in a block - 1
  D1CE  00              EXTMASK:DEFB    0               ;extent mask.
  D1CF  1700            DSKSIZE:DEFW    23              ;disk size from bios (number of blocks-1).
  D1D1  1F00            DIRSIZE:DEFW    31              ;directory size.(max file name no.-1)
  D1D3  C000            ALLOC0: DEFW    0C0H            ;storage for first bytes of bit map (dir space used).
  D1D5  0000            ALLOC1: DEFW    0
  D1D7  0000            OFFSET: DEFW    0               ;first usable track number.
                        ;
1ブロックを4セクタとしましたので、3番目のBLKMASKには4−1=3を書きます。

2番目のBLKSHFTは考え方がちょっと難しいのですが、1セクタ128バイトの場合には、単純に1ブロック当りのセクタ数を2のベキ乗で示します。
たとえば1ブロックが8セクタの場合には8=2^3ですから、3になります。
今回は1ブロックを4セクタにしました。
4=2^2ですから、2を書くことになります。

DSKSIZEはブロック数−1です。
上に書きましたように、今回の仮想ディスクの全セクタ数は96です。
ブロック数は96/4=24ですから、ここには23が入ります。

時間がなくなってしまいました。
この続きは次回にいたします。

ワンボードマイコンでCP/Mを![第12回]
2012.1.22upload
2012.2.13注記

前へ
次へ
ホームページトップへ戻る