SSブログ
English Version

レトロマイコン86ボードの構想(その11)xmodemの移植 [8086]

 CP/M-86の環境を整えるためにCP/M-80とCP/M-68Kで自作したxmodemをCP/M-86へ移植しました。
 移植するまではパソコンでソース編集し、pipでpip xmodem.c=con:のコマンドでCP/M-86へ転送していて、TeraTermで1キャラクタ毎に10msのウェイトを入れているので転送に時間が掛かります。

 コンパイラ環境が整ったので最初にxmodemの移植したいと思い、自作したソースなので簡単にいくだろうと思っていましたが、少し手こずりました・・

 CP/M-86本体はTinyモデル(コードセグメントとデータセグメントが共通)なのでBIOSの各機能が RET命令でリターンするため別セグメントで動作するアプリケーションから直にコールする方法がありません。
 DRC(デジタルリサーチ社製C言語)環境で調べてみるとBIOSコールはbios.hの中で次のように宣言されています。

/****************************************************************************
       BIOS86.H - compatibilty header for CP/M-86 & the IBM-PC family

                  (C)1999 Ken Mauro, All Rights Reserved.
                          Free for non-commercial use.
****************************************************************************/

                /* CP/M & IBMPC bios related stuff */


struct{ char fn;
        char cl,ch;
        char dl, dh; } pblk;


bios(p)   unsigned int *p;    { return __BDOS(50,&pblk); }


 BDOS経由では遅くなりそうだと予感しながら移植してみたところ、xmodemが動作しません・・・

 コンソール送信データはPIC側の処理で当時のエスケープシーケンスをANSIのエスケープコードに変換しているのでバイナリデータの透過性を保証するために/pオプションでPUNCH/READERデバイス(コンソールと同じシリアル通信を使いますがコード変換処理無し)を指定できるようにしています。

 READERではBIOSの仕様上、受信データの有無を確認できないのですが、受信データが無い場合には0xffffを返すようにBIOSを拡張実装しています。
 しかし、上記の__BDOS処理部分でリターン値の上位バイトをマスクする実装になっているのでREADERの受信データ有無チェック機能が動作しません。

 次のログがDDT86で確認した__BDOS部分のコードです("***"部分は追加コメント)。

F>a:ddt86 xmodem.cmd
DDT86 1.2
     START      END
CS 662D:0000 662D:638F
DS 6C66:0000 6C66:FFFF
-l0d5                      *** シンボルファイルから確認した__BDOSのアドレス
662D:00D5 PUSH   BP
662D:00D6 MOV    BP,SP
662D:00D8 PUSH   DI
662D:00D9 PUSH   SI
662D:00DA MOV    DX,06[BP]
662D:00DD MOV    CL,04[BP]
662D:00E0 PUSH   ES
662D:00E1 INT    E0
662D:00E3 POP    ES
662D:00E4 MOV    [0FB4],AX *** 0FB4 __cpmrv
662D:00E7 MOV    [0FDE],CX
662D:00EB SUB    AH,AH     *** change 90H x 2
-l
662D:00ED POP    SI
662D:00EE POP    DI
662D:00EF POP    BP
662D:00F0 RET
662D:00F1 MOV    CL,0C
662D:00F3 PUSH   ES
662D:00F4 INT    E0
662D:00F6 POP    ES
662D:00F7 CMP    AH,11
662D:00FA JNZ    0100
662D:00FC INC    BYTE [0050]
662D:0100 MOV    AL,[0050]
-^C
F>


 "SUB AH,AH"部分をNOP(90H)に変更するパッチ当てて確認したところ、READERのデータ有無確認の機能は動作したのでハイバイトをマスクする前に保存している0x0FB4(シンボルファイルでは__cpmrvとなっている)を使い、xmodemのCソース内で__cpmrvを参照するようにして対処しました。

 この対処でCP/M-86からファイル送信はできるようになりましたが、ファイル受信でエラーが発生します。

 ロジアナで受信処理時の状況を確認した波形サンプルが下記で受信処理が間に合わず取りこぼしている状況でした。
 シリアルの通信速度は38400bpsなので1バイト当たり0.26ms(=1000/38400*10)ですが、受信データのポーリング周期が0.34ms程度になってしまっています。

xmodemでのファイル受信時のロジアナ波形例(NGケース)


 READY信号が一瞬 lowになっている部分がV20からPICへサービス要求している部分でBUSREQ信号がhighの部分はPIC側が処理している部分です。

 上述したようにBDOS経由では遅そうなのでBIOSを直にコールすべく、BIOSの先頭の"JMP INIT"部分に一時的に4バイトのfar CALLされるコード(RETFで終わる)を書込みBIOSの機能をコールし、コール後元に戻すようにしました。
 DRCのオブジェクトとリンクするためにリロケータブルアセンブラのRASM86を使い、セグメント名やCの引数の渡し方等を確認し、ソース作成したところ、最初はリンクできなかったのですが、RASM内のラベルは大文字変換されるようなので大文字に変更したらほぼ一発で動作しました^^

★2019/11/01 追記 {
 最初に使ったBDOS経由でのBIOSコールはBDOSコールファクションNo.50の「DIRECT BIOS CALL」というBDOSコールですが逆アセンブルしてみると判るとおりBIOSに辿り着くまで多くのステップ数のマシン語を実行しています。
}

 RASM86のサンプルソースはネット上で中々見つからなかったので、他の人の参考になるかも(ならないかも)と思いソースを貼っておきます。

BIOSコール用の橋渡し処理(アセンブラ)
CP/M RASM-86 1.2 SOURCE: CALLBIOS.A86 ;*********************************** ; direct bios call for CP/M-86 ; for speed up with RASM-86 ; adapt to ; 2:CONST ; 3:CONIN ; 4:CONOUT ; 5:LISTOUT ; 6:PUNCH ; 7:READER ; Ver 0.01 2019/08/24 by skyriver ;*********************************** 0040 BIOSSEG EQU 0040H 2500 BIOSOFT EQU 02500H 00E8 C_CALL EQU 0E8H ; call ope code 00CB C_RETF EQU 0CBH ; retf code 009A C_CALLF EQU 09AH ; callf code PUBLIC GOBIOS,CALBIOS CSEG ; bios call ; CL <- bios parameter ; DL <- function No GOBIOS: 0000 53 PUSH BX 0001 B84000 MOV AX,BIOSSEG 0004 8ED8 MOV DS,AX 0006 BB0025 MOV BX,BIOSOFT 0009 8B07 MOV AX,[BX] 000B 50 PUSH AX 000C 8B4702 MOV AX,2[BX] 000F 50 PUSH AX 0010 FECA DEC DL 0012 8AE2 MOV AH,DL 0014 02E2 ADD AH,DL 0016 02E2 ADD AH,DL ; AH = (func No - 1) * 3 0018 B0E8 MOV AL,C_CALL 001A 8907 MOV [BX],AX 001C B800CB MOV AX,C_RETF * 256 001F 894702 MOV 2[BX],AX 0022 53 PUSH BX 0023 9A DB C_CALLF ; CALLF BIOSSEG:BIOSOFT 0024 00254000 DW BIOSOFT,BIOSSEG 0028 5B POP BX 0029 59 POP CX 002A 894F02 MOV 2[BX],CX 002D 59 POP CX 002E 890F MOV [BX],CX 0030 5B POP BX 0031 C3 RET ; bios call ; BiosCall( char FNo, char CL ) ; FNo <- BIOS function No. ; CL <- C register value CALBIOS: 0032 55 PUSH BP 0033 8BEC MOV BP,SP 0035 57 PUSH DI 0036 56 PUSH SI 0037 8A5604 MOV DL,4[BP] ; get function No 003A 8A4E06 MOV CL,6[BP] ; get bios parameter 003D 1E PUSH DS 003E 06 PUSH ES 003F E8BEFF 0000 CALL GOBIOS 0042 07 POP ES 0043 1F POP DS 0044 5E POP SI 0045 5F POP DI 0046 5D POP BP 0047 C3 RET END END OF ASSEMBLY. NUMBER OF ERRORS: 0. USE FACTOR: 0%


 安全を見て多くのレジスタを保存していますがそれでもBDOS経由よりはかなり早くなり、ファイル受信処理も問題なく動作するようになりました^^

xmodemでのファイル受信時のロジアナ波形例(改善後)


 受信データのポーリング周期は0.34msから0.23msに高速化され連続的なデータ受信時にも取りこぼしが発生しなくなりました。

 メモとして、xmodemのコンパイル&リンク時の操作ログを貼っておきます。

B>rasm86 callbios
--------------------------------------------------
RASM-86 Relocating Assembler           Version 1.2
Serial No. 3073-0000-001282    All Rights Reserved
Copyright (C) 1982,1983     Digital Research, Inc.
--------------------------------------------------

END OF PASS 1
END OF PASS 2

CODE  00048

END OF ASSEMBLY.  NUMBER OF ERRORS:   0.  USE FACTOR:  0%

B>drc f:xmodem
--------------------------------------------------
Digital Research C       04/17/84     Version 1.11
Serial No. 3073-0000-001282    All Rights Reserved
Copyright (c) 1983,1984     Digital Research, Inc.
--------------------------------------------------

Digital Research C  Version 1.11 -- Preprocessor

Digital Research C  Version 1.11 -- Code Gen
f:xmodem.c:      code:  1894 static:   320 extern:   335

B>link86 f:xmodem=xmodem,callbios
--------------------------------------------------
LINK-86 Linkage Editor  19 March 1984  Version 1.4
Serial No. 3073-0000-001282    All Rights Reserved
Copyright (C) 1982-1984     Digital Research, Inc.
--------------------------------------------------

CODE    06366
DATA    01093

USE FACTOR:  19%

B>a:stat f:xmodem.*

 Drive F:                         User :  0
 Recs  Bytes FCBs Attributes      Name
   58     8k    1 Dir RW        F:XMODEM  .C
  234    30k    2 Dir RW        F:XMODEM  .CMD
    6     2k    1 Dir RW        F:XMODEM  .SYM
----------------------------------------------
Total:   40k    4
F: RW, Free Space:     1,866k
B>f:
F>xmodem
usage : xmodem [/s /r /p] FileName
        /s : send[default]
        /r : receive
        /p : use PUN/RDR device
            Ver0.01 2019/10/23 by skyriver
F>xmodem xmodem.cmd /s /p
xmodem.cmd  (PUN/RDR) sent 234 block(s).
F>


 最後に、今回作成したCP/M-86用のxmodemプログラムは下記のリンクからダウンロード可能です(商用目的以外であれば自由に使用可能)

XMODEM_CPM86_001a.zip

・2019/10/23 Ver0.01a
 コンパイラをDRCからAztec Cに変更(サイズ:30KB->10KB)
・2019/10/09 Ver0.01
 日付表示の誤記修正

★2019/11/05 追記
 Aztec CでのBIOS直コール部のアセンブルリストを貼っておきます。

BIOSコール用の橋渡し処理(アセンブラ)
0000 1 ;*********************************** 0000 2 ; direct bios call for CP/M-86 0000 3 ; for speed up with RASM-86 0000 4 ; adapt to 0000 5 ; 2:CONST 0000 6 ; 3:CONIN 0000 7 ; 4:CONOUT 0000 8 ; 5:LISTOUT 0000 9 ; 6:PUNCH 0000 10 ; 7:READER 0000 11 ; Ver 0.01 2019/08/24 by skyriver 0000 12 ; Ver 0.02 2019/10/23 by skyriver 0000 13 ;*********************************** 0000 14 0000 15 0000 16 BIOSSEG EQU 0040H 0000 17 BIOSOFT EQU 02500H 0000 18 0000 19 C_CALL EQU 0E8H ; call ope code 0000 20 C_RETF EQU 0CBH ; retf code 0000 21 C_CALLF EQU 09AH ; callf code 0000 22 0000 23 0000 24 codeseg segment para public 'code' 0000 25 assume cs:codeseg 0000 26 0000 27 public CalBios_ 0000 28 0000 29 0000 30 ; bios call 0000 31 ; CL <- bios parameter 0000 32 ; DL <- function No 0000 33 0000 34 GOBIOS: 0000 b8 40 00 35 MOV AX,BIOSSEG 0003 8e d8 36 MOV DS,AX 0005 bb 00 25 37 MOV BX,BIOSOFT 0008 ff 37 38 PUSH [BX] 000a ff 77 02 39 PUSH 2[BX] 000d fe ca 40 DEC DL 000f 8a e2 41 MOV AH,DL 0011 02 e2 42 ADD AH,DL 0013 02 e2 43 ADD AH,DL ; AH = (func No - 1) * 3 0015 b0 e8 44 MOV AL,C_CALL 0017 89 07 45 MOV [BX],AX 0019 b8 00 cb 46 MOV AX,C_RETF * 256 001c 89 47 02 47 MOV 2[BX],AX 001f 53 48 PUSH BX 0020 9a 49 DB C_CALLF ; CALLF BIOSSEG:BIOSOFT 0021 00 25 40 00 50 DW BIOSOFT,BIOSSEG 0025 5b 51 POP BX 0026 8f 47 02 52 POP 2[BX] 0029 8f 07 53 POP [BX] 002b c3 54 RET 002c 55 002c 56 002c 57 ; bios call 002c 58 ; BiosCall( char FNo, char CL ) 002c 59 002c 60 CalBios_ proc near 002c 55 61 PUSH BP 002d 8b ec 62 MOV BP,SP 002f 57 63 PUSH DI 0030 56 64 PUSH SI 0031 8a 56 04 65 MOV DL,4[BP] ; get function No 0034 8a 4e 06 66 MOV CL,6[BP] ; get bios parameter 0037 1e 67 PUSH DS 0038 06 68 PUSH ES 0039 e8 xx xx 69 CALL GOBIOS 003c 07 70 POP ES 003d 1f 71 POP DS 003e 5e 72 POP SI 003f 5f 73 POP DI 0040 5d 74 POP BP 0041 c3 75 RET 0042 76 0042 77 CalBios_ endp 0042 78 codeseg ends 0042 79 0042 80 END


[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。