石原 博の覚書

電子工作に関する日々の覚書を記載します

68k emulator (Musashi)でCP/M 68K(2)

2025-01-05 16:58:24 | 日記
前の続き

./cpmsim で起動すると Cドライブにはデフォールトでdiskc.cpm.fsが使用される。

別のファイルを指定する場合は、./cpmsim -c Cドライブファイル。
Aドライブなら -a Bドライブなら -bだが、ファイルは含まれていない。
cpmtoolsでファイルを作成できるのだが、容量が少ないのであまり作る意味はない。

現状の diskc.cpm.fsは16MBで user毎に大量のファイルを含んでいる。
(なぜかcpmsimにはdiskdefsが含まれない。https://github.com/linuxha/cpmsimにあるので使わせてもらう。
256セクタ/トラック, 512トラック, 2KBブロック, トータル16MB)
-----------------------------------------------------
# Format for the CP/M-68K sim C drive images
diskdef em68k
seclen 128
tracks 512
sectrk 256
blocksize 2048
maxdir 4096
skew 0
boottrk 1
os 2.2
end
---------------------------------------------------
$ cpmls -Df em68k diskc.cpm.fs などとすれば内容が見える。

試しに以下のスクリプトで抽出してみた。(ユーザ 7, 8, 9, 12, 15は空)
#!/bin/sh
# 2024/12/30 extract cpmsim diskc.cpm.fs contents
for user in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do
rm -rf diskc$user
mkdir diskc$user
cpmcp -f em68k diskc.cpm.fs $user:* diskc$user
done

逆にファイルを作るスクリプトは以下のとおり。事前に入れたいものをdiskc7などにコピーしておけば良い。
#!/bin/sh
# 2024/12/30 make cpmsim diskc.cpm.fs contents
cp -f diskc.cpm.fs diskcx.cpm.fs
for user in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do
cpmrm -f em68k diskcx.cpm.fs $user:*
cpmcp -f em68k diskcx.cpm.fs diskc$user/* $user:
done
(オリジナルのシステム部分はそのままにしたいので、コピーしてファイル削除してから作成)

以前作成したbcplインタプリタも動作が確認できた。


参考)
A、Bドライブは simbios.sをみると
Aドライブは 8inch SS (ibm-3740 26セクタ/トラック 1KBブロック 242KB) 普通のスキュー6(xlt0)
Bドライブは (40セクタ/トラック 2KBブロック トータル392KB) 変なスキュー(xlt1)
Aドライブは標準のため問題ないが、Bドライブはdiskdefsがない。
---該当部分---------------------------------------------
dpb0: dc.w 26 ;sectors/track
dc.b 3,7 ; bsh, blm
dc.b 0,0 ; null extent mask, fill
dc.w 242 ; disk size in blocks
dc.w 63 ; directory mask
dc.w 0
dc.w 16 ; check vector size
dc.w 2 ; track offset

dpb1: dc.w 40 ;sectors/track
dc.b 4,15 ; bsh, blm
dc.b 0,0 ; null extent mask, fill
dc.w 392 ; disk size in blocks
dc.w 191 ; directory mask
dc.w 0
dc.w 48 ; check vector size
dc.w 2 ; track offset

dpb2: dc.w 256 ;sectors/track
dc.b 4,15 ; bsh,blm (2K blocks)
dc.b 0,0 ; extent mask, fill
dc.w 8176 ; disk size in blocks (minus 1)
dc.w 4095 ; directory mask
dc.w 0
dc.w 0 ; check vector size (none)
dc.w 1 ; track offset

xlt0: dc.w 0,6,12,18,24,4,10,16,22,2,8,14,20
dc.w 1,7,13,19,25,5,11,17,23,3,9,15,21

xlt1: dc.w 0,1,2,3,4,5,6,7
dc.w 16,17,18,19,20,21,22,23
dc.w 32,33,34,35,36,37,38,39
dc.w 8,9,10,11,12,13,14,15
dc.w 24,25,26,27,28,29,30,31
--------------------------------------------------------

これからdiskdefsを作ってみた(skewtabにこんな書き方が出来るとは知らなかった)
--------------------------------------------
# Format for the CP/M-68K sim B drive images
diskdef em68kb
seclen 128
tracks 160
sectrk 40
blocksize 2048
maxdir 192
skewtab 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23,32,33,34,35,36,37,38,39,8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31
boottrk 2
os 2.2
end
----------------------------------------------

良く調べてみると、https://github.com/linuxha/cpmsim の diskdefs にはこのような記載もある。
1セクタ1024にしてskewを2にしているのだが、これでも良いのかなあ。一応試してみると動くのだが。。
-----------------------------------------------
# Format for the 5.25" floppies on my MEX68KECB based system
# and the B drive of the CP/M-68K sim.
diskdef ecb800
seclen 1024
tracks 160
sectrk 5
blocksize 2048
maxdir 192
skew 2
boottrk 2
os 2.2
end



注意点(私のミス)
実は最初ファイルを作成するスクリプトで diskcx.cpm.fsを作成して起動するとエラーとなった。

./cpmsim -c diskcx.cpm.fs

C>AUTOST.SUB

C>��������������������������������������������������������������������������������������������������������������������������������
�����������������������������?

ダンプしてみると以下のとおり(ディレクトリ領域を見てるみたい)
C>dump autost.sub
0000 00 (000000): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 10 (000010): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 20 (000020): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 30 (000030): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 40 (000040): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 50 (000050): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 60 (000060): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*
0000 70 (000070): E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 E5E5 *eeeeeeeeeeeeeeee*

*** E O F ***

さらに

C>bbye
Insufficient memory or bad file header

$>hexdump -C diskcx.cpm.fsしてdirectory部分をみると、ブロック指定部分がおかしい。
00008000 00 41 52 36 38 20 20 20 20 36 38 4b 00 00 00 80 |.AR68 68K....|
00008010 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 |................|
00008020 00 41 52 36 38 20 20 20 20 36 38 4b 01 00 00 19 |.AR68 68K....|
00008030 08 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

ブロックが0000から始まっている。本来はdirectory部分をスキップするはず。
散々調べると、使用しているcpmtoolsはaptで取得したものではなく、どこかからダウンロードしていたことがわかった。
(apt list --installed にない)

過去のソースを調べるため、https://git.gag.com/?p=debian/cpmtools;a=summary を見ると、
New upstream version 2.23 cpmtools の cpmfs.c で以下の差分がある。

Cpmtools 2.20
/* mark directory blocks as used */ /*{{{*/
- *d->alv=(1<<((d->maxdir*32+d->blksiz-1)/d->blksiz))-1;

+ /* A directory may cover more blocks than an int may hold bits,
+ * so a loop is needed.
+ */
+ for (block=0; block<d->dirblks; ++block)
+ {
+ offset = block/INTBITS;
+ d->alv[offset] |= (1<<(block%INTBITS));
+#ifdef CPMFS_DEBUG
+ fprintf(stderr,"alvInit: allocate directory block %d\n",block);
+#endif
+ }

コメントにあるように、directoryが intのビット長(この場合は32bit)を超える場合は問題が発生する。

maxdir=4096 blksiz=2048 なので (4096 * 32 + 2048 - 1) / 2048 = 64.9995 整数なので64
つまり *d->alvは32ビットなのに 1<<64 - 1 を代入している(オーバーフロー)。

いろいろな場合をhexdumpで調べてみると
maxdir="1024" blksize 2048 16ブロック要の場合 (1024*32 + 2048 - 1) / 2048 = 16.9995 -> 16 OK
maxdir=2048 blksize 2048 32ブロック要の場合 (2048*32 + 2048 - 1) / 2048 = 32.9995 -> 32 NG
maxdir=4096 blksize 2048 64ブロック要の場合 (4096*32 + 2048 - 1) / 2048 = 64.8885 -> 64 NG 
maxdir=2048 blksize 4096 16ブロック要の場合 (2048*32 + 4096 - 1) / 4096 = 16.9997 -> 16 OK

32ブロックの場合は行けそうに思うのだが、NGなのが良くわからない。

まあ apt install cpmtools で動くようになったから良いか。

===2025/1/6 追加===
32ブロックで駄目な理由がわかった。

i = 1<<32; だと最適化のため、iには0が代入される。
しかし x=32; i=1<<x; だと以下のようにコンパイルされる。同じことのように見えるが、
実は 80386以降は、シフトの回数は 0x1fでマスクされる。つまり32ビットシフトはシフトしないのと同じ。
movl $1, %edx
movl %eax, %ecx
sall %cl, %edx

実際に以下の例だと
===========================
#include <stdio.h>
int main()
{
int i;
int x = 32;

i = 1 << 32;
printf(" i=%x\n", i);
i = 1 << x;
printf(" i=%x\n", i);
}
===========================
i=0
i=1
と表示される。


最新の画像もっと見る

コメントを投稿