tunozemichanの日記 / tunozemichan's diary

SORD社のコンピューターM68やM68MXの解析についての備忘録です。This blog is a memorandum about the analysis of SORD's computers M68 and M68MX.

Porting CP/M-80 to SORD M68 (Part 2)

I am writing the procedure for porting a CP/M-80 to a SORD M68.

 

What you need

CP/M2.2 source code (available at The Unofficial CP/M Web site)

CP/M2.2 binary (available at The Unofficial CP/M Web site)

ZASM.EXE (Absolute assembler that runs on MSDOS, available in VECTOR)

https://www.vector.co.jp/soft/dos/prog/se010314.html

CP/M player for Win32 (software to run CP/M programs on Windows)

http://takeda-toshiya.my.coocan.jp/cpm/index.html

MSDOS player for Win32 (software to run MSDOS programs on Windows)

http://takeda-toshiya.my.coocan.jp/msdos/

l3diskex.exe(Disk image generation and manipulation program)

http://s-sasaji.ddo.jp/bml3mk5/#l3diskex

 

Limitations in booting SORD M68

1. The BOOT ROM reads 2kb of track 1, side 0, and sectors 1-8. Therefore, the loader that loads the entire system must be kept within 2kb. I actually created one and it was less than 400 bytes.

 

2. Due to the limitation of 1, the system cannot fit into the standard system tracks 0 to 1 of CP/M. Therefore, the CP/M system (CPM22.BIN + BIOS.BIN = CPM.SYS) is placed at the appropriate location on the disk. If I devised a way, I could stuff the system into the remaining area of track 0 (single density) and track 1 (double density), but I decided not to do so because it would be too much trouble.

 

Creating a Loader

Nothing special to mention. There is some cutting and pasting in the binary editor after the binary is created, but it is not difficult.

Change the arguments of the disk read routine in the loader to conform to the location (track, side, sector) of the CP/M system (CPM.SYS).

TIPS is that the program may become unstable if you do not clear 0H to 100H of memory properly with 0 before jumping.

 

Determining Disk Parameters

Download the ZIP file containing the CP/M2.2 binary at The Unofficial CP/M Web site.

http://www.cpm.z80.de/download/cpm22-b.zip

Extract DISKDEF.LIB and MAC.COM from the unzipped folder.

 

The following description is written for SORD M68. This is probably identical to the disk parameters of CP/M-68K for SORD M68. It is compatible, but the data block size of 4kb is frankly difficult to use.

 

MACLIB  DISKDEF
ORG $

DISKS 2
DISKDEF 0,1,52,,4096,243,128,128,2

DISKDEF 1,0
DISKDEF 2,0

ORG $

ENDDEF

END
 
Assemble using MAC.COM and copy the necessary parts from the resulting PRN code into CustomBIOS.
 

Creating CustomBIOS

The details are as described in the previous blog post: Assemble with ZASM.EXE to generate a hex file, and convert with hex2bin to create BIOS.BIN. Before assembling, make sure you have the desired memory model; if you change the CP/M memory model, remember to transcribe the address of the host buffer (hstbuf) for blocking/deblocking to the DMA transfer address. If you forget to do this, the file name will not appear in the DIR command. Worst case, it will freeze or run out of control.

 

Assembling the body of CP/M

Download the assembler source code zip file from The Unofficial CP/M Web site.

http://www.cpm.z80.de/download/cpm2-asm.zip

Assemble CPM22.Z80 in the unzipped folder with ZASM.EXE to generate a HEX file, and convert it with hex2bin to create CPM22.BIN. This is BDOS and CPP. Before assembling, set the memory model to the desired size.

 

Create CPM.SYS

Connect CPM22.BIN and BIOS.BIN. At this time, there is an empty jump table at the end of CPM22.BIN, so delete this and connect BIOS.BIN. Specifically, connect after 1600H. Rename the resulting binary to CPM.SYS. This can be easily done with a binary editor. I use Binary Editor BZ.

 

 Now you have a loader (LOADER.BIN) and a CP/M80 system (CPM.SYS). From now on, use l3diskex.

 

Create a boot disk image

Start l3diskex and process as shown in the image below to complete the CP/M image for SORD M68.

 

The language in the images below is Japanese. Please use Google Lens to translate.

 

Press the "New(新規)" button and make your selection as shown on the screen.

f:id:tunozemichan:20220303173300p:plain

 

f:id:tunozemichan:20220303173402p:plain

Click, [OK]

 「BASIC用にフォーマット」mean Format for BASIC.

f:id:tunozemichan:20220303173441p:plain

f:id:tunozemichan:20220303173542p:plain

Select CP/M for SORD

 

Writing CPM.SYS to a CP/M image disk

Drag and drop any CP/M program into the disk image window of l3diskex and it will be copied into the image. Now select the copied CPM.SYS and right-click to see its properties. You will then see where it was saved on the disk, as shown in the screenshot, so make a note of it and change the argument to the loader's disk read routine. In this example, you can see that it occupies track 7, side 0, sectors 13 to 26, and track 7, side 1, sectors 1 to 12.

 

f:id:tunozemichan:20220303173841p:plain

 

Write loader

Switch to raw disk mode(生ディスクモード), select Track 1, Side 0, Sector 1, right-click and select "Import(インポート)". A file selection window will open, select LOADER.BIN. You will be asked for the last sector to be written, so assume it is up to 2 sectors; LOADER.BIN is less than 400 bytes, so it can be stored in 2 sectors (512 bytes).

f:id:tunozemichan:20220303174011p:plain

 

f:id:tunozemichan:20220303174053p:plain

 

The boot disk image of the CP/M system for SORD M68 is now complete. Simply drag and drop the program of your choice to create and run the desired disk image.

If successful, you will see the following on the terminal screen

 

f:id:tunozemichan:20220303174210p:plain

Porting CP/M-80 to SORD M68 (Part 1)

I ported CP/M80 to SORD M68. the Z80SIO I/O address and FDC(MB8877A) read/write processing code also worked so I can write BIOS. The following is a memo description of the problems I had.

 

Blocking/de-blocking process

The CP/M80 sets the capacity of one sector at 128 bytes, but the SORD M68 double-density recording is 256 bytes/sector, so a process called blocking/deblocking is required.

The number of bytes per sector was already a problem in CP/M2.2, and there is an official conversion code (axg.asm). However, this code is written in 8080 style and cannot be assembled with my ZASM.EXE, so I use a converter named TOZ.EXE to convert it. The macro will not work, but it is easy because it only calculates secshf=log2(hstblk). In this case it will be 1. Now that we can assemble it, all we need to do is write the readhst and writehst routines.

For example, the readhst subroutine is processed as follows. First, set the track number set by CP/M as the target track in the track register and execute the SEEK command. Then, simply set the target sector number to the sector register and execute the READ command. This READ command should be a DMA-based command; I have written about DMA and the READ command in a previous blog.

The writehst subroutine is the same as the readhst subroutine, just with a different command number.

 

SIDE 0 and 1 processing

In CP/M80, there is no special process for double-sided recording; CP/M does not distinguish sides, so logically they are all considered the same side, and only the number of tracks increases. Therefore, logical and physical tracks have the following relationship.

 

Logical track    Physical track    Side

           2                     2             0

           3                     2             1

           4                     3             0

           5                     3             1

           6                     4             0

           7                     4             1

 

Therefore, the number of logical tracks is shifted one bit to the right and +1 is the physical track. If the carry flag is up in this operation, we know that the logical track was odd, and we can write code to specify that side 1 should be read/write.

 

Apart from this, there was another problem, possibly a SORD M68 CP/M68K formatting issue, where sectors were shifted by 1. I solved this by adding a +1 instruction to the sector register setting code in the writehst and readhst subroutines.

 

f:id:tunozemichan:20220227200549p:plain

SORD M68にCP/M-80を移植する(その2)

SORD M68にCP/M-80を移植する手順を書いておきます。

 

必要なもの

CP/M2.2のソースコード(The Unofficial CP/M Web siteにあります)

CP/M2.2のバイナリ(The Unofficial CP/M Web siteにあります)

ZASM.EXE(MSDOSで動くアブソリュートアセンブラです。VECTORにあります)

https://www.vector.co.jp/soft/dos/prog/se010314.html

CP/M player for Win32(WIndows上でCP/Mのプログラムを実行するソフトウェア)

http://takeda-toshiya.my.coocan.jp/cpm/index.html

MSDOS player for Win32(Windows上でMSDOSのプログラムを実行するソフトウェア)

http://takeda-toshiya.my.coocan.jp/msdos/

l3diskex(ディスクイメージ生成・操作プログラム。超多数のイメージを操作できる)

http://s-sasaji.ddo.jp/bml3mk5/#l3diskex

 

 

SORD M68の起動における制限について

1. BOOT ROMはトラック1、サイド0、セクタ1~8の2kbを読み込みます。よって、システム全体を読み込ませるローダーは2kb以内に収める必要があります。実際に作成したとこと400バイト未満でした。

 

2. 1の制限により、CP/Mの標準システムトラック0~1にシステムが入りきりません。よって、CP/Mシステム(CPM22.BIN+BIOS.BIN=CPM.SYS)は、ディスクの適当な位置に配置します。あれこれやるとトラック0(単密度)とトラック1(倍密度)の残りに入れられそうですが面倒なので、やめました。

 

ローダーの作成

特記すべきことはありません。バイナリを作った後にバイナリエディタで切り貼りがありますが難しくありません。CP/Mシステム(CPM.SYS)の配置場所(トラック、サイド、セクタ)に適合するように、ローダー内のディスクリードルーチンの引数を変更します。TIPSは、メモリの0H~100Hまでをちゃんとクリアしてからジャンプしないと動作が不安定になることがあることです。

 

ディスクパラメータの決定

The Unofficial CP/M Web siteにあるCP/M2.2のバイナリが含まれるZIPファイル

http://www.cpm.z80.de/download/cpm22-b.zip

をダウンロードして、中にあるDISKDEF.LIBとMAC.COMを取り出します。

 

SORD M68用に以下のように記述しました。これはSORD M68用CP/M-68Kのディスクパラメータとおそらく同一です。互換性はありますが、データブロックサイズが4kbは正直使いにくいと思います。


MACLIB  DISKDEF
ORG $

DISKS 2
DISKDEF 0,1,52,,4096,243,128,128,2

DISKDEF 1,0
DISKDEF 2,0

ORG $

ENDDEF

END

MAC.COMでアセンブルして、得られたPRNコードから必要個所を以下に記載するCustomBIOSにコピーします。

 

CustomBIOSの作成

前回説明しました。ZASMでアセンブルして、hex2binでBIOS.BINを作ります。アセンブルする前に、望みのメモリモデルにしておきます。CP/Mのメモリモデルを変更したときは、ブロッキング/デブロッキング用のホストバッファ(hstbuf)のアドレスを、DMAの転送アドレスに転記することを忘れないようにします。これを忘れると、DIRコマンドでファイル名が出ません。最悪フリーズか暴走します。

 

CP/Mの本体をアセンブルする

The Unofficial CP/M Web siteからアセンブラソースコードのZIPファイル

http://www.cpm.z80.de/download/cpm2-asm.zip

をダウンロードします。中にあるCPM22.Z80をZASMでアセンブルして、hex2binで変換するとバイナリCPM22.BINが出来上がります。これがBDOSとCPPです。アセンブルする前にメモリモデルを望むサイズにしておきます。

 

CPM.SYSを作る

CPM22.BINの後ろにBIOS.BINを繋げます。この時、CPM22.BINの最後には空のジャンプテーブルが入っていますので、これを削除してBIOS.BINを繋げます。具体的には1600H以降につなげます。出来上がったバイナリはCPM.SYSとリネームします。この作業はバイナリエディタで簡単にできます。私はBinary Editor BZを使っています。

 

これで、ローダー(LOADER.BIN)、CP/M80システム(CPM.SYS)が出来ました。以後は、l3diskexを使います。

 

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

l3diskexを起動して、以下、画像の通りに処理すれば、SORD M68用のCP/Mイメージが完成します。

 

f:id:tunozemichan:20220303173300p:plain

「新規」ボタンを押して、画面のように選択する。

f:id:tunozemichan:20220303173402p:plain

OKをクリック

f:id:tunozemichan:20220303173441p:plain

BASIC用にフォーマットを選択。

f:id:tunozemichan:20220303173542p:plain

CP/M for SORD」を選択

 

 

CPM.SYSをCP/Mイメージディスクに書き込む

イメージのウインドウにドラッグアンドドロップすればコピーされます。ここで、コピーされたCPM.SYSを選択して、右クリックしてプロパティを見ます。すると画像のようにディスクのどこに保存されたか分かりますので、メモして、ローダーのディスクリードルーチンの引数を変更します。画面の例では、トラック7、サイド0、セクタ13~26、トラック7、サイド1、セクタ1~12までを占有していることがわかります。

f:id:tunozemichan:20220303173841p:plain



ローダーを書き込む

生ディスクモードに切り替えて、トラック1、サイド0、セクタ1を選択し、右クリックして「インポート」を選びます。ファイル選択ウインドウが開くので、LOADER.BINを選択します。どこまで書くのか聞かれるので、2セクタまでとします。LOADER.BINは400バイト未満なので、2セクタ(512バイト)で格納できます。

f:id:tunozemichan:20220303174011p:plain

生ディスクモードへ

 

f:id:tunozemichan:20220303174053p:plain

該当セクターにローダーを書き込む

以上で、SORD M68用CP/Mシステムの起動ディスクイメージは完成です。好みのプログラムをドラッグアンドドロップして、望みのディスクイメージを作成して、実行するだけです。

成功すれば、ターミナル画面に以下のように表示されます。

f:id:tunozemichan:20220303174210p:plain

CP/M‐80 for SORDの起動画面



 

SORD M68にCP/M80を移植する(その1)

SORD M68にCP/M80を移植しました。Z80SIOのI/OアドレスとFDC(MB8877A)の各処理コードも動作したので、BIOSを書くことができます。ハマった点をメモ的に記載します。

 

ブロッキング/デブロッキング処理

CP/M80は、1セクタの容量を128バイトに設定していますが、SORD M68の倍密度記録は256バイト/セクタですので、ブロッキング/デブロッキングという処理が必要です。これはCP/M2.2のときにすでに問題だったらしく、オフィシャルに変換コードがあります(axg.asm)。しかし、このコードは8080風に書いてあり、私が使っているZASMではアセンブルできないので、TOZ.EXEというコンバーターを使って変換します。マクロが動かなくなりますが、secshf=log2(hstblk)を計算するだけなので、簡単です。今回の場合は1になります。これでアセンブルできますので、あとは、readhstとwritehstのルーチンを書くだけです。

例えば、readhstには設定されたトラック番号を目標にSEEKコマンドを発行して、その後、やはり設定されたセクタ番号をトラックレジスタにセットしてREADコマンドを発行するだけです。このリードコマンドは、DMAを利用したコマンドにしておきます。

writehstはコマンド番号が違うだけで、readhstと同じです。

 

SIDE0と1の処理

CP/M80では、両面記録用に特別な処理はありません。ここでハマりました。サイドを区別しないので、論理上は全て同じサイドでトラックだけが増えていきます。よって、論理トラックと物理トラックは以下のような関係にあります。

 

論理トラック 物理トラック サイド

         2                         2                  0

         3                         2                  1

         4                         3                  0

         5                         3                  1

         6                         4                  0

         7                         4                  1

 

従って、論理トラック数を右に1ビットシフトして、+1したものが物理トラックになります。この操作でキャリフラグが立っていれば、論理トラックが奇数だったことがわかり、サイド1を読み書きするよう指定するコードを書けばよいことになります。

 

あとは、SORD M68のCP/M68Kのフォーマットの問題かもしれませんが、セクタが1ずれる問題がありましたが、writehstとreadhstのセクタ設定コードにADD A,01H(INC A)を追加するだけで解決しました。

 

f:id:tunozemichan:20220227200549p:plain

モニタプログラムから起動したCP/M80でテキストファイルを出力したところ。正常に表示され、正しい場所を読めていることがわかる。

 

Analysis of BASIC for SORD M23 disk image.

I examined the disk image of BASIC for SORD M23 in the Internet archive.

First, I found the following from this disk image: 
1. 80tracks, 1side, 16sectors, 256byte/sector. 2. all sectors are MFM record type.
2. all sectors are MFM record type.
3. 256 * 16 * 80 = 320kByte/disk

Next, I disassembled and analyzed what I thought were the boot sectors (sectors 0-6). I found the followingSerial I/O is Z80SIO, Counter is Z80CTC, DMA is Z80DMA, Floppy Disk Controller is unknown, but I think it is MB8877.


FDC is MB8877?
0xc0 : FDC command/status reg?
0xc1 : Track reg?
0xc2 : Sector reg?
0xc3 : FDC data reg?
0xc4 : Z80DMA I/O address

Z80SIO
0xf8 : Z80SIO_A_channel Data reg.
0xf9 : Z80SIO_A_channel Control reg.
0xfa : Z80SIO_B_channel Data reg.
0xfb : Z80SIO_B_channel Control reg.

Z80CTC
0xfc : channel0
0xfd : channel1
0xfe : channel2
0xff : channel3

I don't have an M23, so I can't actually verify it, but once I get the model number of the FDC, more will be revealed.
Knowing the model number of the FDC will allow me to write a small monitor program to the boot sector to get more information.

 

SORD M23 BASICディスクイメージの解析

Internet ArchiveにSORD M23用のBASICディスクイメージがあります。私は、M23は持っていないのですが、興味本位でブートセクタと思われるセクタを読んでみました。

 

まず、このディスクイメージからは以下のことがわかりました。
1. 80tracks, 1side, 16sectors, 256byte/sector.
2. all sectors are MFM record type.
3. 256 * 16 * 80 = 320kByte/disk

 

次にブートセクタと思われる部分(セクタ0~6)を逆アセンブルして解析しました。以下のことがわかりました。シリアルI/OはZ80SIO、カウンタはZ80CTC、DMAはZ80DMA、Floppy Disk controllerは不明ですがおそらくMB8877ではないかと思います。

 

FDC is MB8877A?
0xc0 : FDC command/status reg?
0xc1 : Track reg?
0xc2 : Sector reg?
0xc3 : FDC data reg?
0xc4 : Z80DMA I/O address

 

Z80SIO
0xf8 : Z80SIO_A_channel Data reg.
0xf9 : Z80SIO_A_channel Control reg.
0xfa : Z80SIO_B_channel Data reg.
0xfb : Z80SIO_B_channel Control reg.

 

Z80CTC
0xfc : channel0
0xfd : channel1
0xfe : channel2
0xff : channel3

 

M68とかなり似ています。というか、SIO、CTCはI/Oアドレスも一緒です。

私はM23を持っていませんので実際に検証することはできません。FDCの型番が判明すれば、より多くのことが明らかになると思います。

 

 

FDC(MB8877)の制御コードについて(RESTORE,SEEK,READ)

SORD M68のFDCは富士通のMB8877Aです。これはWD系と呼ばれるFDCの系統の一つで、特にMB8877は日本のマイコンに広く用いられています。

今回は、このMB8877の制御コードを具体例を書いていきます。分かりにくくなるため、エラー処理などは書きません。この辺は成書で補ってください。実際のところGOTEKやHxCなどFDDエミュレータを使う場合は、ほぼ確実に動作は成功しますので、エラー処理せずとも何とかなるケースが多いです。

基本的に、RESTORE、SEEK、READ、WRITEが出来れば、ひとまず何とかデバイスドライバの格好はつきます。

 

0. FDCコマンド発行サブルーチン

まずはFDCコマンドを発行するサブルーチンを書いておきます。


;
; FDC COMMAND OUT subroutine
;
FDCOUT:
    OUT (FDC_COMMAND_REG),A
    LD A,30H
WLOOP: DEC A
    JR NZ,WLOOP
LOOP2:
    IN A,(FDC_STATUS_REG)
    BIT 0x0,A ; BUSY IS CLEAR?
    JR NZ,LOOP2
    RET
;

 

コマンドをFDCのコマンドレジスタに入れた後、少しだけ待ちますが、SORD M68のBOOT ROMのコピーです。これは必要なディレイの様です。BUSYフラグがクリアされていれば、リターンします。

 

1.RESTORE

RESTOREはFDDのヘッドをトラック0に移動します。MB8877では、以下のようにすると良いようです。

;
; RESTORE subroutine
;
RESTORE:
RESTORE_LOOP:
    LD A,44H ;  \DDENS is HIGH. Low density mode.
    OUT (FDC_CONTROL_REG),A
    LD A,0CH ; restore command
    CALL FDCOUT
    BIT 7,A ; Not Ready?
    JR NZ,RESTORE_LOOP
    AND 98H
    JR NZ,RESTORE
    RET

 

RESTOREは、基本的にLow density(単密度/FM記録)モードで行うようです。RESTOREコマンドは0xCです。問題なく実行された場合は、00でリターンします。

 

2.SEEK

SEEKは、目標トラックにヘッドを動かす動作です。MB8877では、density(記録密度)をFDDコントロールレジスタに設定した後に、FDCデータレジスタに目標トラックを設定して、SEEKコマンド0x1Cを発行します。

 

SEEK:
    LD A,D
    OUT (FDC_CONTROL_REG),A
    LD A,E
    OUT (FDC_DATA_REG),A
    LD A,1CH ; SEEK COMMAND
    CALL FDCOUT
    AND 98H
    RET

 

成功すると0が返ってきます。

 

3. READ

READは、文字通りフロッピーディスクからデータを取り出す動作です。具体的には、現在ヘッドが置かれているトラックから、指定されたセクタのデータを読み取り、それをFDCデータレジスタに出力します。

DMAがあるマシンでは、DMAを使う方がコードは短くなります。

まずは、DMAを設定、起動するコードを書きます。

 

DMA_ON:
    PUSH HL
    PUSH BC
    LD B,(HL)
    INC HL
    LD C,DMA_ADDRESS
    OTIR
    POP BC
    POP HL
    RET

 

DMAは、コマンドチェーンというコマンドの連なりで設定するのが効率的です。SORD M68の場合は、以下のようになっています。

DMA_COMMANDS:
    DB 15H,0C3H,0C3H,0C3H,0C3H,03CH,0C3H
    DB 0BBH,01H,9BFH
    DB 6DH,0CBH,0FFH,00H,02CH,010H,08DH
    DB 80H,00H ; CP/M defaults dma address is 0080H
    DB 9AH
    DB 0CFH,87H

 

コマンドの詳細は、「試験に出るX1」を参照してください。名著です。最初の0x15はコマンドの数です。最後の二つの命令(0xCF,0x87)でDMAが起動します。

 

;
; DMA setting & FDD read FOR SIDE 0
; C is Sector No.
; D is Control word.
;
GO_DMA_AND_READ0:
    LD A,C
    OUT (FDC_SECTOR_REG),A
    LD A,D
    OUT (FDC_CONTROL_REG),A
    LD HL,DMA_COMMANDS
    CALL DMA_ON
    AND 20H
    LD A,82H ; READ DATA COMMAND for Side 0
    CALL FDCOUT
    AND 0FCH
    RET

 

セクタレジスタにセクタ番号を入れて、FDDコントロールポートには読み取りたいトラックの記録密度とサイドを入力します。SORD M68で、単密度で読むなら、0x44です。その後に、サイド0に対するFDCリードコマンド0x82を発行します。

これだけで、DMAに設定したアドレスに、設定したバイト数(今回は0xFF(256バイト))、データが転送されます。