「[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の部分を使用する? ""空きは、ディレクトリーエントリが物理損傷した場合のリカバリー用ではないか。 ""→確認してみた。ビットの位置を変更してみたが変化無し。 ""ディレクトリーエントリ領域はビット分しか確保していなかった。 ""構想のみで実装しなかったのか? *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}}