tunozemichanの日記 / tunozemichan's diary

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

SHARP X68000にCP/M-68Kを移植する(その1)

SHARP X68000CP/M-68Kを移植しようと思います。

 

開発環境

エミュレータ

xm6gを使用しました。X68000で最強と噂されるエミュレータです。デバッグ機能は操作が直感的で痒い所に手が届く素晴らしいソフトウェアです。

retropc.net


CP/M-68Kのソースコード

68kv1_2.zipを使用しました。後に68kv1_3.zipへアップグレードしました。

 

アセンブラ

MSDOS用のAS68K.EXEを使用しました。出力はS2レコードなので、RAWバイナリに変換する必要があります。MOT2BIN.EXEを使用しました。

 

AS68K.EXEは制限が多く、MS-DOSプレイヤーが必要ということで使い勝手が今一つだったので、LEA MACRO ASSEMBLERに変更しました。RAWバイナリ出力ができるので、MOT2BINも必要ありません。

また、ブートローダーだけは、xdev68kのコマンド一群を使いました。

 

puntett.net

 

 


ディスクイメージの操作

l3diskexを使用しました。

s-sasaji.ddo.jp


1. CP/MBIOS以外の部分をRAWバイナリにしておく

68kv1_2.zipを展開して、DISK7フォルダ内のCPM15000.SRをMOT2BINでRAWバイナリ(ここではCPM15000.BINとします)に変換します。

CPM15000.MAPを見て、_cppが$150B8であること、_initが$1B000であることを確認します。つまりBIOSは$1B000から始まります。CPM15000.BINを見ると、$1B000よりだいぶ手前で切れているので、そこまでFFで埋めます。

以後、作成したBIOSは、$1B000以降に張り付けることで、CP/Mのシステム(名前も何でもよいはず。便宜上CPM.SYSまたはcpm68k.sysとしている)となります。

自分でブートローダーを書くなら、ディレクトリトラック以外ならどこにシステムを置いても動くと思います。一般に、ディレクトリのトラックは第2トラックです。


2. ディスクイメージを作る

CP/Mのデフォルトでは、ディスクのトラック0、サイド0は単密度(FM)記録であることを期待しています。
しかし、どうやらX68000のIPLはトラック0、サイド0が倍密度(MFM)記録であることを前提としているようです。実際、単密度のディスクで起動を試みましたが失敗しました。

この制限の為に、他のCP/Mのディスクイメージを転用できません。一からディスクイメージを構築します。


3. l3diskexの設定ファイルを変更する

l3diskexディレクトリ直下のdataディレクトリ内の二つのファイル(basic_types.xml、disk_types.xml)を変更します。

私も詳細不明なままいじっているのでよくわからない点もありますが、以下のようにするとCP/Mで使えるディスクイメージが作れます。

 

basic_types.xmlに以下の項目を加えます。


    <DiskBasicType name="CPM68-2HD-X68" type="10" category="CPM">
        <SectorsPerGroup>8</SectorsPerGroup>
        <SidesPerDisk>2</SidesPerDisk>
        <SectorsPerTrack>8</SectorsPerTrack>
        <ManagedTrackNumber>2</ManagedTrackNumber>
        <DirStartSector>1</DirStartSector>
        <DirEndSector>8</DirEndSector>
        <Description>CP/M-68k for X68K (2HD)</Description>
    </DiskBasicType>

 

disk_types.xmlに以下の変更を加えます。具体的には”CPM68-2HD-X68"を加えただけです。

 

    <DiskType name="2HD-77-8-1">
        <SidesPerDisk>2</SidesPerDisk>
        <TracksPerSide>77</TracksPerSide>
        <SectorsPerTrack>8</SectorsPerTrack>
        <SectorSize>1024</SectorSize>
        <Density>0x20</Density>
        <Interleave>1</Interleave>
        <DiskBasicTypes>
            <Type p="major">HU68K-2HD</Type>
            <Type p="major">MSD98-2HD</Type>
            <Type p="major">CPM68-2HD-X68</Type>
        </DiskBasicTypes>
        <DensityName>2HD</DensityName>
        <DensityName lang="ja">2HD</DensityName>
        <Description>[PC-9801 DOS/Human68k]</Description>
        <Description lang="ja">[PC-9801 DOS/Human68k]</Description>
    </DiskType>
 

 

このディスクの設定は、1024byte/sector,8sector/track,77track,2sideとなっています。これはHuman68kと同じです。


この方法でイメージを作った時の欠点は、CP/MBIOSに必須のディスクパラメータブロック(DPB)のパラメータが、ディスクイメージを調べないと分からない点です。一度、このイメージを作成して、なんでも良いのでファイルをドラッグアンドドロップして、プロパティにある占有しているブロック数をみると、1ブロックが何バイトなのか分かります。このディスクイメージでは、1ブロックが8192バイトでした。DPBについては別項で書きます。


4. ブートローダーを書く

XM6GはRAWバイナリを任意のメモリに書き込んでそこから実行を開始するという機能はないようなので、ディスクイメージにブートローダーを書き込んで、そこから自分のプログラムを動かす必要があります。

このWEBサイトを参考にしました。

zenn.dev


X68000は起動するとドライブ0のトラック0、サイド0、セクタ1から1セクタ分1024byteを読み、$2000番地に書き込んで、$2000から実行を開始します。

ブートローダーの機能は、CP/Mシステムをメモリに書き込んで、CP/Mシステムのinitにジャンプすることです。

今回はメモリの$15000番地からシステムが始まるバイナリを選んだので、ディスクから読み込んだシステムを$15000に書き込みます。

次のようなコードにしました。IOCSを使っています。アセンブルは、xdev68kのものを使いました。

 


    ; DISK READ
    ; SIDE:0, track3, sector1 from 8 sectors read to $15000
    move.l  #$03000001,d2   ; sector len:3(1024), side = 0, sector = 1
    clr.l   d0
    move.w  #$3,d0          ; track number
    swap    d0              ; track:bit23-16
    add.l   d0,d2
    move.l  #$9000,d1       ; drive0
    ori.w   #$0070,d1       ; 0111_0000: MFM, RETRY, SEEK
    move.l  #8*1024,d3      ; size 8 * 1024
    move.l  #$15000,a1      ; to memory address
    IOCS    _B_READ

 

l3diskexにCPM.SYSをドラッグアンドドロップしたら、トラック3、サイド0から配置されたので、そこを読むように書いてあります。
この辺、作業が前後します。ブートローダーを書く前に、文字表示とキー入力を書いたBIOSからCPM.SYSを作って(リードライトルーチンは空にしておきます)、ディスクイメージに書き込みます。この時、l3diskexがどこ書き込むか知る必要があります。希望の場所に書き込ませる方法を筆者は知りませんので、こんなやりかたになってしまっています。

CP/M-68Kのシステムは約25kBなので、4回トラックの読込を繰り返せば良いことになります。

注意すべきなのはブートローダーが最後にジャンプする番地は、BIOS内のinit($1B000)だと言う点です。システムの先頭($15000)ではありません。

 

5. BIOSを書く

CP/M-68Kのソースコード群には色々なBIOSがあって、どれが良いのか迷いますが、今回はDISK7ディレクトリのERGBIOS.Sをひな形にしました。もっともシンプルで理解しやすい内容です。その他には、CP\M-68KのシステムガイドのAppendixにあるサンプルBIOSもシンプルで良いと思います。

最初にcppの位置を明確にします。番地はSR15000.MAPに書いてあります。

 

_ccp:    equ    $150bc

 

BIOSに文字表示とキー入力ルーチンを書く

文字表示とキー入力部分を書きます。IOCSを使うので簡単です。

 


constat:
    moveq.l #$0,d0      * set result to true
    rts

conin:
    moveq.l #B_KEYINP,d0
    trap    #IOCS
    andi.l  #$000000ff,d0 * ascii code
    rts

conout:
    moveq.l #B_PUTC,d0
    trap    #IOCS
    rts

prtstr:
    move.l a6,a1
    moveq.l #$21,d0
    trap #IOCS
    rts
 

 

AS68K.EXEでアセンブルします。SレコードファイルをMOT2BINでRAWバイナリに変換し、前半のゴミ部分をカットしたものを、FFで所定の領域を埋めたSR15000.BINの末尾に加えます。


ここまで出来れば、エミュレータ上でディスクを起動して、画面に起動画面が出ます。

 

次はディスク周りの内容です。