- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
「[CP/M on an AVR(avrcpm)|http://spritesmods.com/?art=avrcpm&page=4]」で公開されているディスクイメージはちょっと問題があり、動作テスト程度にしか使えないので作り直した方がよい。さらにディスクサイズが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%2FM の '''avrcpm_upd.zip'''
!Z80アセンブラ
Win32用Z80アセンブラ(tniasm)は下記から入手。(ソースの終わりに改行を入れておく)
http://www.tni.nl/products/tniasm.html
!連結ツール
システムバイナリをddコマンドで連結する。dd.exeは下記から入手。(cpmtoolsに既にあるdllは上書きしない)
「[コンピュータ広場 CS|http://matanet.ath.cx/cs/dd%20%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AB%E3%82%88%E3%82%8B%20FD%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E4%BD%9C%E6%88%90/]」→[リンク切れ|https://web.archive.org/web/20090308102821/http://matanet.ath.cx/cs/dd%20%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AB%E3%82%88%E3%82%8B%20FD%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E4%BD%9C%E6%88%90/]のためコピーを配置→ [dd.exe|http://star.gmobb.jp/koji/data/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の部分を使用する。
""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秒)
{{comment}}