CP/Mディスクイメージ作成手順メモ

CP/M on an AVR(avrcpm)」で公開されているディスクイメージはちょっと問題があり、動作テスト程度にしか使えないので作り直した方がよい。さらにディスクサイズが8インチ標準1ドライブでは狭すぎるので拡張する。

完成したソースをアーカイブに添付するほうが簡単だが、CP/Mに関する情報は少なくなってきており、応用が利くようにあえて作業の流れを記載しておく。アスキー出版の「応用CP/M」(1982年)から得られた情報を元にしている。(作業環境OSはWindows)

準備するもの

cpmtools

CP/Mファイルシステムのディスクイメージを作成し、CP/Mファイルの登録、取り出しができる。
http://www.cpm8680.com/cpmtools/

【2013.1.1】 GUI化したものを作成しました。 CpmtoolsGUI こちらも使ってみてください。

CP/Mのシステムバイナリ

CPM.SYS は下記サイトから入手できる。
http://www.cpm.z80.de/binary.html
http://spritesmods.com/?art=avrcpm&page=4
http://www.mikrocontroller.net/articles/AVR_CP/M

システムソースファイル

ipl.asm, bios.asmを下記から入手する。BIOSにシステムのリロードが実装されておりこちらをベースにする。
http://petersieg.bplaced.net/?AVR_CP%2FMavrcpm_upd.zip

Z80アセンブラ

Win32用Z80アセンブラ(tniasm)は下記から入手。(ソースの終わりに改行を入れておく)
http://www.tni.nl/products/tniasm.html

連結ツール

システムバイナリをddコマンドで連結する。dd.exeは下記から入手。(cpmtoolsに既にあるdllは上書きしない)

コンピュータ広場 CS」→リンク切れのためコピーを配置→ dd.exe

ディスクイメージをSDカードへ登録するツール

DDforWindows を使う。下記から入手。
http://blog.halpas.com/archives/1258

ディスクの設計

CP/Mは階層ディレクトリを持たないので1ドライブで容量を拡張すると扱いにくくなる。パーティションを分け以下の構成とする。

[128バイト/セクタ]×[64セクタ/トラック]×[244トラック]×4ドライブ

1ドライブ当り約2メガバイト。計8メガバイトとなる。これならば実用上問題ないだろう。

ディスクパラメータの算出

BIOSに設定するディスクパラメータを計算する。
パーティションで分ける場合、トラックは積算となるので各ドライブの諸元はそれぞれ

ドライブ バイト セクタ トラック
A: 128 64 244
B: 128 64 488
C: 128 64 732
D: 128 64 976

CP/Mブロックサイズ(BLS)は、DSMが256以上になるので必然的に2048バイト以上となるがAVRのメモリが4KBなので2048バイトしか選択の余地は無い。システムトラックはセクタを64としたので1トラックとしている。

BLS=2048

SPT:64
BSH:4 (2048=128*(2^4))
BLM:15 (0〜15: 2048/128-1=15)
EXM:0 (2048:DSM>255)
DSM A:{(128*64)*(244-1)/2048}   -1=971
DSM B:{(128*64)*(488-244)/2048} -1=975
DSM C:{(128*64)*(732-488)/2048} -1=975
DSM D:{(128*64)*(976-732)/2048} -1=975
DRM:127 (2bit*64-1)
AL0:192 (2bit: 0b11000000=192)
AL1:0 (0b00000000)
CKS:(DRM+1)/4=(127+1)/4=32
OFF A:1
OFF B:244
OFF C:488
OFF D:732
CSV A:32
CSV B:32
CSV C:32
CSV D:32
ALV A:(971+1)/8=122
ALV B:(975+1)/8=122
ALV C:(975+1)/8=122
ALV D:(975+1)/8=122

パラメータ算出方法解説

  • SPT(Sector Per Track)
    • 1トラック当りのセクタ数
  • BSH(Block SHift factor)
    • 1ブロックのバイト数(BLS)を128バイト×2の乗数で表す。BLS=128*2^BSH
  • BLM(BLock Mask)
    • 1ブロック内のセクタ数を0〜 で表す。BLS/128 - 1
  • EXM(EXtent Mask)
    • 計算式は不明だが表が示されている。
BLS DSM<256 DSM>255
1024 0 -
2048 1 0
4096 3 1
8192 7 3
16384 15 7

推測で、EXM=(BLS/1024/ブロックポインタのサイズ)-1

ブロックポインタは、DSM<256のとき1バイト、DSM>255のとき2バイトになる

1エクステント当り、ブロックポインタ用に16バイトの割り当てゆえに、

1エクステント当りに指示できるバイト数=BLS*16/ブロックポインタのサイズ=1024*(EXM+1)*16

STAT DSK:コマンドで表示されるRecords/Extent =(EXM+1)*128。(1Record=128バイト)

  • DSM(Disk Size Max)
    • ブロックの最大数 - 1。
  • DRM(DiRectory entries Max)
    • ディレクトリエントリーの数 - 1。(AL0,AL1のビット1の数)*BLS/32-1
  • AL0,AL1
    • この2バイトで1ビットを1ブロックとみなしたビットパターンでディレクトリエントリ(=1)を表す
AL0 AL1
11000000 00000000

これから分かることは、

ディレクトリーエントリとして確保できる領域は最大16ブロックまで。

AL0、AL1が意味するものは何か?これも未確認で推測だが、

CP/Mシステムはディスクから一律に16ブロックのディレクトリーエントリ領域を確保する?

AL0、AL1はマップであり、確保した領域のうちビット1の部分を使用する?

空きは、ディレクトリーエントリが物理損傷した場合のリカバリー用ではないか。

→確認してみた。ビットの位置を変更してみたが変化無し。

ディレクトリーエントリ領域はビット分しか確保していなかった。

構想のみで実装しなかったのか?

  • CKS(ChecK vector Size)
    • (DRM+1)/4。ディレクトリチェック用ワークエリアサイズ。
  • OFF(track OFFset)
    • システムトラック数。パーティションに分けるときにも利用できる。
  • CSV(Check Scratchpad Vector)
    • =CKS
  • ALV(ALlocation scratchpad Vector)
    • (DSM+1)/8。1ビット1ブロックとみなすマップを作り使用済/未使用エリアを管理するためのワークエリア。

なおこれらのパラメータはCP/Mが動作する環境があればDISKDEFマクロによって自動的に算出することもできる。→ DISKDEFマクロの使い方メモ

ソースの修正

ipl.asmの修正

予め43行を

	ld a,1	;execute DMA READ
	out (22),a

とし、21〜24行を削除しておく。

26行あたり。読み込むセクタ数。修正によって少し増えるので多めにとっておく。

	ld b,55		;

49行あたり。1トラック当りのセクタ数を26から64へ変更

	cp 64		;

bios.asmの修正

予め、76,77行を削除。31〜34行を削除。

32行あたり。システムのセクタ数。44。もとのコード($-ccp)の意味がわからないので修正。

67行あたり。追加。理由は後述。

	ld	(cdisk),a
	ld	(odisk),a	;add neko Java
	jp	gocpm 

101行あたり。ipl同様。1トラック当りのセクタ数を26から64へ変更

	cp	64	;if sector >= 64 then change tracks.

108行あたり。トラック数が256以上(トラックのポインタが2バイト)になるのでbレジスタに正しい値を入れる。

	push	hl
	ld	b,0	;add neko Java.
	call	settrk

home:。トラックが2バイト指定になったことによる。

home:
	push af
	ld a,0
	out (16),a
	out (17),a	;add neko Java.
	pop af
	ret

seldsk:。4ドライブ化。前のカレントドライブをodiskに保持し、不正なドライブを選択したときは前のドライブに戻す。これをやっておかないとエラーメッセージ表示後、リブートの無限ループになる。

seldsk:			;mod for 4drive. neko Java
	push af
	ld a,c
	cp 0
	jr nz,seldsk_1
	ld hl,dph0
	jr seldsk_ok
seldsk_1:
	cp 1
	jr nz,seldsk_2
	ld hl,dph1
	jr seldsk_ok
seldsk_2:
	cp 2
	jr nz,seldsk_3
	ld hl,dph2
	jr seldsk_ok
seldsk_3:
	cp 3
	jr nz,seldsk_na
	ld hl,dph3
seldsk_ok:
	ld (odisk),a
	pop af
	ret
seldsk_na:
	ld hl,0
	ld a,(odisk)
	ld (cdisk),a
	pop af
	ret

settrk:。トラックが2バイト指定になったことによる。

settrk:
	push af
	ld a,c
	out (16),a
	ld a,b		;add neko Java
	out (17),a	;add neko Java
	pop af
	ret

read:、write:。AVRがディスクエラーを返せるので取り込むようにする。

read:
	ld a,1
	out (22),a
	in a,(23)	;mod neko Java
	ret

write:
	ld a,2
	out (22),a
	in a,(23)	;mod neko Java
	ret

ディスクパラメータヘッダ。下記を参考に、以下dph1,dph2,dph3を定義する。

;Disk Parameter Header
dph0:
	dw trans ;XLT: Address of translation table
	dw 0 ;000: Scratchpad
	dw 0 ;000: Scratchpad
	dw 0 ;000: Scratchpad
	dw dirbuf ;DIRBUF: Address of a dirbuff scratchpad
	dw dpb0 ;DPB: Address of a disk parameter block
	dw chk0 ;CSV: Address of scratchpad area for changed disks
	dw all0 ;ALV: Address of an allocation info scratchpad

ディスクパラメータブロック。下記を参考に、以下dpb1,dpb2,dpb3を定義する。dpb1以降のDSM=975、OFF(積算)に注意。

dpb0:
	dw 64 ;SPT: sectors per track
	db 4 ;BSH: data allocation block shift factor
	db 15 ;BLM: Data Allocation Mask
	db 0 ;Extent mask
	dw 971 ;DSM: Disk storage capacity
	dw 127 ;DRM, no of directory entries
	db 192 ;AL0
	db 0 ;AL1
	dw 32 ;CKS, size of dir check vector
	dw 1 ;OFF, no of reserved tracks

スキューはかけないのでここの記述は意味なし。適当。

trans:
	db 0

後はdirbuf:(=128)、chk0:〜chk3:(=CSV)、all0:〜all3:(=ALV)のバイト数を算出した値に設定する。

dirbuf:
	ds 128
chk0:
	ds 32
.
.
all0:
	ds 122
.
.

最後に以下を追加。前のカレントドライブ保持用。

odisk:
	ds 1	;add neko Java

ファームの修正

z80cpm.hの修正。最後の方。SECT_CNTとBLOCK_SIZEを修正。

/* Disk parameters ----------------------------------------- */
#define SDC_CLST_SIZE	512	// fixed for SDC.
#define SECT_SIZE		128	// fixed for CP/M.
#define SECT_CNT		64	// CP/M sector size.
#define BLOCK_SIZE		2048	// CP/M block size.

z80cpm.cの修正。166行。var_calc()内。トラックのハイバイトが0に固定してあるのでコメント化する。

	//Track_no_h = 0;
	Track_no = ((WORD)Track_no_h << 8) + (WORD)Track_no_l;

アーカイブに添付のMakefileでビルドする。

diskdefsファイルの修正

cpmtoolsのdiskdefsファイルを定義する。同様にcpm_b,cpm_c,cpm_dを定義。それぞれtracksとboottrkは異なる(積算になる)ので注意。

# CP/M ドライブAアクセス用--
diskdef cpm_a
  seclen 128
  tracks 244
  sectrk 64
  blocksize 2048
  maxdir 128
  skew 1
  boottrk 1
  os p2dos
end

ディスクイメージを作成する。

以下作業ディレクトリを下記と仮定する

[ツール    ] D:\cpmtools
[ソース    ] D:\cpmtools\z80
[A:ファイル] D:\cpmtools\z80\a
[B:ファイル] D:\cpmtools\z80\b
[C:ファイル] D:\cpmtools\z80\c
[D:ファイル] D:\cpmtools\z80\d

環境設定、作業準備

コマンドプロンプトから、

set CPMTOOLS=
set CPMTOOLS=D:\cpmtools
set PATH=%CPMTOOLS%;%PATH%
d:
cd D:\cpmtools\z80

アセンブル

tniasm ipl.asm ipl.bin
tniasm bios.asm bios.bin

連結

dd conv=sync bs=128  count=1 if=ipl.bin > cpm.bin
dd conv=sync bs=128 count=44 if=CPM.SYS >> cpm.bin
dd conv=sync bs=128  count=10 if=bios.bin >> cpm.bin

ディスクイメージ作成

mkfs.cpm -f cpm_d diskimage
mkfs.cpm -f cpm_c diskimage
mkfs.cpm -f cpm_b diskimage
mkfs.cpm -f cpm_a -b cpm.bin -L test diskimage

ファイルコピー(a-dフォルダのファイルをイメージへ)

cpmcp -f cpm_a diskimage ./a/*.* 0:
cpmls -f cpm_a diskimage
cpmcp -f cpm_b diskimage ./b/*.* 0:
cpmls -f cpm_b diskimage
cpmcp -f cpm_c diskimage ./c/*.* 0:
cpmls -f cpm_c diskimage
cpmcp -f cpm_d diskimage ./d/*.* 0:
cpmls -f cpm_d diskimage

イメージをSDカードに書き込む

DDforWindows を使う。読出す場合はSDCの容量一杯までやってしまうが途中でESCキーで止めることができる。

イメージからファイルを取り出す場合の例

cpmcp -f cpm_a diskimage 0:*.* コピー先ディレクトリ

AVRとZ80でCP/M へ戻る
CpmtoolsGUI

関連サイト

CP/M on an AVR
http://spritesmods.com/?art=avrcpm&page=1
改善版
http://petersieg.bplaced.net/?AVR_CP%2FM ←BIOSのベースにしたのはこちらのサイト。
http://www.mikrocontroller.net/articles/AVR_CP/M


  • ($-ccp) の$には現在アドレス位置が入りますから(bios-ccp)と読み替えます-CCP) - samllaCircuit (2011年09月09日 23時32分07秒)
  • ご指摘ありがとうございます。アセンブラは詳しくないので。修正不要ということで削除しておきます。 - 管理人 (2011年09月10日 03時12分33秒)
お名前: コメント:

トップ メニュー

This web page is described in Japanese, but you can read in English by translation site.

  • このサイトはリンクフリーです。
  • コメント欄は改行せず一行で入れてください。
  • スパム判定ではじかれた場合は、その後に「書込みました」旨のみのコメント等何らかの書き込み成功していただけると早く対応できます。
  • 非日本語対応ブラウザからは書き込みできません。