石原 博の覚書

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

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
と表示される。

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

2024-12-23 22:16:01 | 日記
しばらく68k実機を使っていたが、遅いしSDカード経由でのプログラム移動は面倒なのでPC上のエミュレータを使ってみることにした。

skyriverさんのブログ(https://piclabo.blog.ss-blog.jp/2018-07-22)
@hi631(Hiromichi Kitahara)さんのqiita https://qiita.com/hi631/items/577d943adbe9b03dce1c
を参考にしました。

---使用するファイル--------
・Musashi
 https://github.com/kstenerud/Musashi
・CP/M-68K Simulator
 http://davesrocketworks.com/electronics/cpm68/simulator.html
----------
Musashi-master.zipを展開し、cpmsim.zipを展開したもので上書き。(m68kconf.hだけ同じ名前のファイルがある)
ところがコンパイルエラーが多発。Musashiがバージョンアップして不整合が起きているような感じ。
cpmsim.zipはMusashiのバージョン3.3を想定しているようだが、現在のMusashiはバージョン4.6

エラーとその対応
[1]'obj/m68kopac.c' を make するルールがありません
>make: *** 'obj/m68kopac.o' に必要なターゲット 'obj/m68kopac.c' を make するルールがありません. 中止.
色々warningが出るが結局このエラーで止まる。m68kopac.cなどどこにもない。
 makefileを調べて見ると以前は「obj/m68kmake obj m68k_in.c」によりobj/m68kops.c、obj/m68kopac.c、
 obj/m68kopdm.c、obj/m68kopnz.cを生成していたようだが、現在のバージョンでは obj/m68ops.c しか作っていない。
 (すべてm68kops.cに含まれているようだ)

MUSASHI Version3.3の m68kmake.c
/* Default filenames */
#define FILENAME_INPUT "m68k_in.c"
#define FILENAME_PROTOTYPE "m68kops.h"
#define FILENAME_TABLE "m68kops.c"
#define FILENAME_OPS_AC "m68kopac.c"
#define FILENAME_OPS_DM "m68kopdm.c"
#define FILENAME_OPS_NZ "m68kopnz.c"

MUSASHI Version4.6の m68kmake.c
/* Default filenames */
#define FILENAME_INPUT "m68k_in.c"
#define FILENAME_PROTOTYPE "m68kops.h"
#define FILENAME_TABLE "m68kops.c"


 そこで
 cpmsim: obj/cpmsim.o obj/m68kcpu.o obj/m68kops.o obj/m68kopac.o obj/m68kopdm.o obj/m68kopnz.o m68kdasm.o
$(CC) $(LFLAGS) obj/sim.o obj/m68kcpu.o obj/m68kops.o obj/m68kopac.o obj/m68kopdm.o obj/m68kopnz.o m68kdasm.o -o cpmsim
 から不要なファイルを除き
 cpmsim: obj/cpmsim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o
$(CC) $(LFLAGS) obj/sim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o -o cpmsim


[2]undefined reference to `float64_to_floatx80'
>/usr/bin/ld: obj/m68kcpu.o: in function `load_pack_float80':
 > m68kcpu.c:(.text+0x480): undefined reference to `float64_to_floatx80'

  float64_to_floatx80はsoftfloat/softfloat.c 内の関数のようだ。68000ではfloatは関係ないのだけど。
  仕方ないのでsoftfloat.cをコンパイルしリンクするように変更

 cpmsim: obj/cpmsim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o softfloat/softfloat.o
$(CC) $(LFLAGS) obj/sim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o softfloat/softfloat.o -o cpmsim

softfloat/softfloat.o: softfloat/softfloat.c softfloat/softfloat.h softfloat/softfloat-specialize softfloat/softfloat-macros m68kcpu.h
$(CC) $(CFLAGS) softfloat/softfloat.c -o softfloat/softfloat.o

[3]undefined reference to `sincos'
  >m68kcpu.c:(.text+0x3fe5): undefined reference to `sincos'
sincosは math ライブラリなので、-lmをつける

cpmsim: obj/cpmsim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o softfloat/softfloat.o
$(CC) $(LFLAGS) obj/sim.o obj/m68kcpu.o obj/m68kops.o m68kdasm.o softfloat/softfloat.o -o cpmsim -lm

[4]コンパイルは成功するが実行するとSegmentation fault
>$ ./cpmsim
>Read 32768 bytes from boot track
>Segmentation fault

ググると http://davesrocketworks.com/electronics/cpm68/simulator.html で
>I received a report of segmentation violations when built using V3.4 of
> the Mushashi source. (I used 3.3) Upon investigation I found a thinly documented change
> to the initialization code. The README doesn't say anything but the example added
> some new code. So if you use V3.4 you need to add this just before the call to
> m68k_pulse_reset() in cpmsim.c:

これに従い
  m68k_init();
  m68k_set_cpu_type(M68K_CPU_TYPE_68000);
 をm68k_pulse_reset()の直前に入れて動くようになった。

とはいうもののwarningはうっとおしい。

[5]overflow
>cpmsim.c:739:11: warning: 'read' writing 16777216 bytes into a region of size 16752640 overflows
> the destination [-Wstringop-overflow=]
>739 | if((i = read(fd, &g_ram[0x6000], MAX_RAM+1)) == -1)

g_ramは「unsigned char g_ram[MAX_RAM+1]」と宣言されているので、これだとオーバーするなあ。
 そこで read(fd, &g_ram[0x6000], MAX_RAM+1-0x6000) とした。(fdはsimbios.bin 32.8KBなので問題ない)

[6]unused-variable
>obj/m68kops.c:36709:13: warning: unused variable 'cycle_cost' [-Wunused-variable

m68k_in.cで以下のようになっている。

>void m68ki_build_opcode_table(void)
>{
> const opcode_handler_struct *ostruct;
> int cycle_cost;
> int instr;
ところが、関数後半部分で
 >/* SBF: don't add it here or the costs are added twice!
  とコメントアウトされており、cycle_costが使用されなくなっている

 そこで宣言をコメントアウト

これでやっとwarningがなくなった。

$ ./cpmsim
Read 32768 bytes from boot track


CP/M-68K(tm) Version 1.2 03/20/84
Copyright (c) 1984 Digital Research, Inc.

CP/M-68K BIOS Version 1.0
Simulated system of April 2014
TPA =16251 K

C>AUTOST.SUB

C>INIT.REL M
Do you really want to init disk M ?
C>
と正常に起動した

新PCセットアップ

2024-11-10 20:03:35 | 日記
ポータブルSSDでしばらくlinuxを使っていたが、不注意で上書きし動かなくなった。
(cp/m68k で遊ぶのにのsdカードの書き込み時を行っているが、SDカードのデバイス名が、ポータブルSSDを接続したことで
以前のPCと変わっていることに気づかなかった。ポータブルSSDにDDで書いてしまった)

元の内蔵SSDには不良セクタがあったことでもあり、この際内蔵SSDを交換してWindowsとのデュアルブートとするようにした。

[1]元あったSSDからWindowsを外部SSDへコピー
 Webで検索するとAOMEIのbackup無料版が使えるという記事がある。
 特にこだわりはないので試してみたが、AOMEI backupperの無料版は使えなかった。
 (昔は使えたが最近のバージョンは使えなくなったという情報が見つかった)

 仕方ないのでclonezillaを使う。
 clonezilla2.7.1-22.zipを ダウンロードし展開後、USBメモリ(fat32)へコピー。
 d:\>\utils\win64\makeboot64.batで起動USBに変更
 再起動でclonezillaが立ち上がる。
 
 通常通りdeviceからdeviceへクローンする。容量が現SSD<新SSDなので特になにも気にしなくてもOK。
 空いているところにdebianを導入する。
  昔はCDROMに焼いて、そこから起動していたがUSBメモリが使えるようになって楽になった。

[2]debian12 netinstallの準備
 https://www.debian.or.jp/cdimage/ からダウンロード

 注意点
 USBメモリへの導入で「# cat debian.iso > /dev/sdX」で書き込むとあったが、
 「$ sudo cat debian.iso > /dev/sdX」とすると、「許可がありません」となる。
 調べてみると、この場合sudo は catだけに影響して >の書き込みはbashが行うのでエラーになるようだ。
 特権ユーザになって書いても良いが、
 「$ sudo sh -c "cat debian.iso > /dev/sdX」として書き込んだ。

[3]USBメモリから起動し通常通りインストール

[4]sudoを使えるように
  $ su -
  # usermod -G sudo xxx
  # visudo /etc/sudoers.d/sudouser
  
  ここで %sudo ALL=(ALL:ALL) ALL
反映は再起動要(ログオフだけじゃだめ)

[5]gnome-flashback導入を忘れていた
  sudo tasksel でGNOME Flashbackを導入

[6]以前ポータブルSSDの時unixbenchを調べたので、内蔵SSDでどうなるか調べた
  gccやmakeを導入しunixbenchをコンパイル
  もっと速くなると思ったのに、ほとんど変わらない。不思議だ。
  
       1_parallel_copy_of_tests 4_parallel_copies_of_tests
  -----------------------------------------------------------------------
  i5-3320M@2.60GHz(内蔵SSD) 1153.5 2822.6
  i5-7300U@2.60GHz(ポータブルSSD) 1128.3 2461.4
  i5-7300U@2.60GHz(内蔵SSD) 1126.8 2475.5

とりあえずこれでwin11とlinuxのデュアルブート出来るようになった

BCPL intcodeインタプリタのバグ?

2024-10-27 14:16:02 | 日記
CP/M68K で intcodeインタプリタで動いたが、それだけではもったいない。
Martin RichardsのBCPLサイト「https://www.cl.cam.ac.uk/~mr10/index.html」に
bcplで記述されたmlisp.bがある。これを動かすことを考えた。

ところがいろいろな問題が発生(*1)。なんとか回避したが、最後にインタプリタのバグ?が判明し諦めた。
(根本は CP/M68KのCにまで遡る。これを回避するのは難しい)

・バグの発見までの経緯
 さまざまな問題を開始したが、どうしてもmlisp.bが動かない。
 コンパイル途中のTREEを見ると、P_LISTが -0 になっていた? ソースでは $80000000 なのに。
 
  ! *--1
*-OP75
*-OP43
! *-OP43
! ! *-OP43
! ! ! *-NIL
! ! ! *-P_LIST
! ! ! *--0
! ! *-B
! ! *-2
 
 そこでテストコードを作成しコンパイルしてみた
===================
 GET "LIBHDR"

 MANIFEST $(
 X =#X7FFFFFFF
 Y =#X80000000
 Z =#X80000001
 $)

 LET START() BE
 $(
 WRITEF("%X8 %X8 %X8*N", X, Y, Z)
 WRITEF("%N %N %N*N", X, Y, Z)
 $)
===================

 OCODEではなぜか #X80000000が -00 になっている
  STACK 2 JUMP L2 ENTRY 5 L1 83 84 65 82 84 SAVE 2 STACK 4 LSTR
  12 37 88 56 32 37 88 56 32 37 88 56 10 LN 2147483647 LN -00 LN
  -2147483647 LG 76 RTAP 2 STACK 4 LSTR 9 37 78 32 37 78 32 37 78
  10 LN 2147483647 LN -00 LN -2147483647 LG 76 RTAP 2 RTRN ENDPROC
  0 STACK 2 LAB L2 STORE GLOBAL 1 1 L1

INTCODEは 0 になっている
  JL2
$ 1 LL499 SP4 L2147483647 SP5 L0 SP6 L-2147483647 SP7 LIG76 K2 LL498 SP/
4 L2147483647 SP5 L0 SP6 L-2147483647 SP7 LIG76 K2 X4 2
499 C12 C37 C88 C56 C32 C37 C88 C56 C32 C37 C88 C56 C10 498 C9 C37 C78 /
C32 C37 C78 C32 C37 C78 C10
G1L1
Z

 実行してみると 
 ===========================
 C>icint test.int


INTCODE SYSTEM ENTERED

PROGRAM SIZE = 644
7FFFFFFF 00000000 80000001
2147483647 0 -2147483647

EXECUTION CYCLES = 2295, CODE = 0
============================

 どうやら0x80000000を表示できないらしい。
 
 今度はCでテストコードを実行
 ===test2.c======================
#include <stdio.h>

int main()
{
long x = 0x80000000L;
int y = 1;
int z = 0;
printf("%08lx\n", x);
printf("%08lx\n", -x);
printf("%08lx\n", x / y);
printf("%08lx\n", x / z);
printf("%d\n", y / z);
}

C>test2

80000000 ==> わかる
80000000 ==> わからないこともない
00000000 ==> 1で割っているのに? わからない
80000000 ==> 0で割っているのに? わからない

Exception $05 at user address $000082A8. Aborted.  ==> わかる(当然)

===test2.s======
.globl __iob
.globl _main
.text
_main:
~~main:
~_EnD__=8
link R14,#-12
~x=-4
*line 5
move.l #$80000000,-4(R14) long x = 0x80000000L;
~y=-6
*line 6
move #1,-6(R14) int y = 1;
~z=-8
*line 7
clr -8(R14) int z = 0;
*line 8
move.l -4(R14),(sp) printf("%08lx\n", x); ==> 80000000
move.l #L2,-(sp)
jsr _printf
addq.l #4,sp
*line 9
move.l -4(R14),R0 printf("%08lx\n", -x); ==> 80000000
neg.l R0
move.l R0,(sp)
move.l #L3,-(sp)
jsr _printf
addq.l #4,sp
*line 10
move -6(R14),R0 printf("%08lx\n", x / y); ==> 00000000
ext.l R0
move.l R0,-(sp)
move.l -4(R14),-(sp)
jsr ldiv
addq.l #8,sp
move.l R0,(sp)
move.l #L4,-(sp)
jsr _printf
addq.l #4,sp
*line 11
move -8(R14),R0 printf("%08lx\n", x / z); ==> 80000000
ext.l R0
move.l R0,-(sp)
move.l -4(R14),-(sp)
jsr ldiv
addq.l #8,sp
move.l R0,(sp)
move.l #L5,-(sp)
jsr _printf
addq.l #4,sp
*line 12
move -6(R14),R0 printf("%d\n", y / z); ==> Exception $05
ext.l R0
divs -8(R14),R0
move R0,(sp)
move.l #L6,-(sp)
jsr _printf
addq.l #4,sp
L1:
unlk R14
rts
.data
L2:
.dc.b $25,$30,$38,$6C,$78,$A,$0
L3:
.dc.b $25,$30,$38,$6C,$78,$A,$0
L4:
.dc.b $25,$30,$38,$6C,$78,$A,$0
L5:
.dc.b $25,$30,$38,$6C,$78,$A,$0
L6:
.dc.b $25,$64,$A,$0
=================================================


 
 CP/MのDDTで確認したところ、
 CP/M68KのCの32ビットの割り算ルーチン(_ldiv)にいろいろ癖があることが判明。
 除数が0だと(エラーではなく)0x80000000になる。
 被除数が16ビット内だと divuを使うが、それ以上だとソフトウエアでの除算
 被除数が0x80000000の場合への考慮がない。
 (被除数が負の場合はnegしているが0x80000000の場合はnegしても0x80000000)

 
---$4(A7)/$8(A7) -> D1/D3 ----------------------------
---D1が 0x80000000の場合は、neg.l D1によりD1= となる。
 _ldiv:
ldiv:
0000AD7A movea.l D3,A0
0000AD7C move.l $4(A7),D1     被除数をD1へ
0000AD80 bge $AD84 被除数が0または正なら分岐
0000AD82 neg.l D1          負の場合は正の数にする
0000AD84 move.l $8(A7),D3     除数をD3へ
0000AD88 bgt $AD98 除数が正なら分岐
0000AD8A blt $AD96 除数が負なら分岐
0000AD8C move.l #$80000000,D0 ここに来るのは除数が0 返り値が$80000000
0000AD92 move.l D0,D1
0000AD94 bra $ADE4
0000AD96 neg.l D3 除数を正の数にする
0000AD98 moveq.l #$0,D0
0000AD9A cmp.l D1,D3        被除数と除数を比較
0000AD9C blt $ADA6 D1>D3(被除数>除数)なら分岐
0000AD9E bgt $ADD2 D1<D3(被除数<除数)なら分岐
0000ADA0 moveq.l #$1,D0     D1=D3(被除数=除数)なら 商=1 余り=0
0000ADA2 moveq.l #$0,D1
0000ADA4 bra $ADD2 符号調整
0000ADA6 moveq.l #$2,D2
0000ADA8 cmp.l #$10000,D1
0000ADAE bge $ADBC 被除数が>=#$10000なら分岐(ソフトウエアで割り算)
0000ADB0 divu D3,D1 d1.l / d3.w => d1.h ... d1.l
0000ADB2 move.w D1,D0         d0=余り
0000ADB4 clr.w D1
0000ADB6 swap D1 d1=商
0000ADB8 bra $ADD2          符号調整
0000ADBA add.l D2,D2
0000ADBC add.l D3,D3
0000ADBE cmp.l D3,D1
0000ADC0 bcc $ADBA 被除数<除数 になるまで除数を左シフトしながらループ
0000ADC2 bra $ADCC
0000ADC4 cmp.l D3,D1
0000ADC6 bcs $ADCC         D1<D3ならブランチ
0000ADC8 or.l D2,D0 商はD0に出来てくる
0000ADCA sub.l D3,D1 D1=D1-D3
0000ADCC lsr.l #1,D3       除数を右シフト
0000ADCE lsr.l #1,D2
0000ADD0 bne $ADC4
0000ADD2 tst.w $4(A7)       被除数が
0000ADD6 bpl $ADDC         正ならブランチ
0000ADD8 neg.l D0         負の場合は、商も余りも符号反転
0000ADDA neg.l D1
0000ADDC tst.w $8(A7) 除数が
0000ADE0 bpl $ADE4         正ならブランチ
0000ADE2 neg.l D0         負なら商を符号反転
0000ADE4 move.l D1,$B294 ._ldivr
0000ADEA move.l A0,D3
0000ADEC rts

商と余りの符号は以下のようになる
正 / 正 = 正 ... 正
負 / 正 = 負 ... 負
正 / 負 = 負 ... 正
負 / 負 = 正 ... 負


・結論
 コンパイラで0x80000000が表示出来ないのはlongの除算の扱いがおかしなためと思われる。
 (BCPLの印字のライブラリでも以下のようになっており、N=0x80000000では問題が起きる)

=================
AND WRITED(N, D) BE

$(1 LET T = VEC 20
AND I, K = 0, N
TEST N<0 THEN D := D-1 ELSE K := -N
T!I, K, I := K REM 10, K/10, I+1 REPEATUNTIL K=0
FOR J = I+1 TO D DO WRCH('*S')
IF N<0 DO WRCH('-')
FOR J = I-1 TO 0 BY -1 DO WRCH('0'-T!J) $)1

AND WRITEN(N) BE WRITED(N, 0)
=================

では、CP/M68KのCの問題かといえば、(CP/M68KのCはANSIではないけれど)
ANSI Cであっても long は <=−2,147,483,647 とのこと。
なので、−2,147,483,647まで扱えれば、-2,147,483,648が扱えなくても文句は言えない。

・大本の原因
 結局 -2,147,483,648が表示出来ると想定しているインタプリタのバグと言えるかも。。。



(*1)
[1]syntaxエラー
 BCPLは歴史的にuppercaseが使用されるが該当プログラムはlowercaseとなっている。
 ソースを置換することも検討した。(cat mlisp.b | tr [a-z] [A-Z] > mlisp2.b)
 ところがunderscore も使用されている。これを受け入れるようにするためsyn.bの変更が必要となった。
 
[2]%演算子
 元のコンパイラでGETBYTE, PUTBYTEという関数があったが、mlisp.bでは%演算子が使用されている。 
 GETBYTE(x,y) は x%y, PUTBYTE(x,y,z) は x%y = zとなる。

[3]領域不足
 コンパイルすると「PROGRAM TOO LARGE」というエラーが出る。
 OPTIONSでL7500としている(もともと設定されていた)が足らない。L9000まで増加すればエラーは出なくなった。
 コンパイル結果を見ると TREE SIZE 8499 となっていた。
 
[4]領域不足
 コンパイルすると「TOO MANY GLOBALS」というエラーが出る。
 trn.bを見ると100に設定されている。これでは足りないようだ。

[5]ライブラリ関数不足
 NAME NOT DECLAREDが出る。RDARGS, STR2NUMB, GETVEC, FREEVECがない。
 GETVECやFREEVECもCのmallocを使いたいところであるが、
 intcodeインタプリタ方式では簡単に追加出来ない
 X(EXECUTEOPERATIONS)に割り振って、LIBHDRで名前定義して、iclib.iで連携することが必要。
 
 実はINTCODE_documentaion.pdfではX1(A:=loc(A))〜X27(output)なのに、
 icint.cではX1(A:=loc(A))〜X39(output)、さらにiclib.iではX41(REWIND)まである。
 (LIBHDRにはGLOBAL変数としてREWINDが用意されているのだが)
 
 要するにintcodeには共通規格があるわけでなく、それぞれの処理系でインタプリタと一緒に
 提供されるもののようだ。

PCの切り替え

2024-09-08 22:30:06 | 日記
普段遣いのPCではLinuxを使っているが、どうしてもWindowsでないと具合の悪いソフト(TL866のプログラムなど)があるため、ハードディスクをSSDに変え、Windows10とdebianのデユアルブートとしている。
(ハードは2022/5 中古で購入 LifeBook E742F 第3世代core i5)

しかしWindows10のサポート期限が近づきつつあるため、今回再度中古PC(Windows11あり)を購入した。
(LifeBook A577/S 第7世代core i5)

このPCも以前と同様ディスクを入れ替えてデユアルブートとすることを考えていたが、
最近のノートPCは以前ほど簡単にディスクの交換が出来ないようだ。
そもそも購入時点でSSD240GBとなっている。わざわざ大きなSSDに変えてパーティション切ってというのも大変なので、
USB接続のポータブルSSD(500GB)を試してみた。(debian-12.4.0-amd64-netinst.iso)
インストールは思ったより簡単。通常通りのインストールで書き込み先を外部SSDにするだけ。

注意点
 実は旧PCでポータブルSSDにインストールして新PCで使うように考えたが、
 「選択したデバイスから起動出来ませんでした」となり起動出来ない。
 セキュアブートの問題かと思いBIOSでOFFにしたが駄目。
 なぜか新PCでSSDにインストールすると起動出来た。逆にそのSSDを旧PCに持っていっても起動しない。
 よくわからない。

注意点2
インストールの「ソフトウエアの選択」でGNOME Flashbackを入れること。
 (昔ながらのデスクトップが良いので)

注意点3
新PCはUSB3.0であり5Gbps(3.2だと10GHz)。速度が気になったので、
 念のために、UnixBenchで確認すると、以下のようになった。
 USBの速度の問題なのか、旧PCより新PCの方が遅くなってしまった。
 まあ速度を追求しているわけではないので良いか。

   1_parallel_copy_of_tests 4_parallel_copies_of_tests
  -----------------------------------------------------------------------
  i5-3320M@2.60GHz 1153.5 2822.6
  i5-7300U@2.60GHz 1128.3 2461.4

その他
 新PCの内蔵SSDに24個も不良セクタがあった。(使用可能とはなっている)
 そのうち壊れるかも。その際は交換して内蔵USBディスクにインストールすることにしよう。

 内蔵SSDは40℃程度だが、ポータブルSSDは55℃程度。ケースを触っても熱い。
 ファンもなにも無いのだからそんなものか。壊れないかなあ。