2018/03/17

HuBASICのみでInquiry


このBASICプログラムでは、SCSIバスのID0からID6までスキャンして機器名等を表示します。

ボードを作って初期の頃、X1turboでSPCの操作を確認するために作ったもので、SCSI BIOSの造りはこれがベースになっています。ただ、BIOSでは永久ループにならないよう、各所にタイムアウト処理を仕込みました。BASICでは、いつもで[SHIFT]+[BREAK]で止められるので、そういった対応はしていません。
1000 '
1010 INIT:CLS:DEFINT A-Z
1020 '
1030 DIM CDB(12),BUF(512)
1040 TLEN=0                     'Transfer Length
1050 SCSIID=7                   'X1turbo SCSI ID
1060 '
1070 PORT=&HF70                 'MB89352 BASE Address
1080 BDID=PORT+0:SCTL=PORT+1:SCMD=PORT+2:TMOD=PORT+3:INRS=PORT+4
1090 PSNS=PORT+5:SDGC=PORT+5:SSTS=PORT+6:SERR=PORT+7:PCTL=PORT+8
1100 MBC=PORT+9:DREG=PORT+&HA:TEMP=PORT+&HB
1110 TCH=PORT+&HC:TCM=PORT+&HD:TCL=PORT+&HE
1120 '
1130 GOTO "MAIN"
1140 '
1150 '
1160 LABEL"SETTLEN"
1170 OUT TCH,0
1180 OUT TCM,(TLEN AND &HFF00)\&H100
1190 OUT TCL,TLEN AND &HFF
1200 WAIT PSNS,&B10000000       'Wait REQ Assert
1210 RETURN
1220 '
1230 LABEL"WAITCC"
1240 WAIT INRS,&HFF:R=INP(INRS) XOR &B10000:OUT INRS,&HFF
1250 RETURN
1260 '
1270 LABEL"INITSPC"
1280 OUT SCTL,&B10010000        'SPC Reset & Disable
1290 OUT BDID,SCSIID            'X1turbo SCSI ID
1300 OUT SCMD,0
1310 OUT PCTL,0
1320 OUT TEMP,0
1330 OUT TCH,0
1340 OUT TCM,0
1350 OUT TCL,0
1360 OUT SCTL,&B10000           'SPC Enable, Arbitration Enable
1370 RETURN
1380 '
1390 LABEL"SRST"
1400 OUT INRS,&HFF
1410 OUT SCMD,&B10000           'RST On
1420 OUT SCMD,&B0               'RST Off
1430 RETURN
1440 '
1450 LABEL"SELECT"
1460 OUT PCTL,&H0                       'START Selection Phase
1470 WAIT SSTS,&B11110000,&B11111111    'BusFree待ち
1480 OUT SCTL,(INP(SCTL) OR &B10000)    'Arbitration Enable
1490 OUT TEMP,(INP(BDID) OR 2^TARGET)
1500 OUT TCH,&HF
1510 OUT TCM,&H46
1520 OUT TCL,&H4
1530 OUT INRS,&HFF              'Reset Interrupt
1540 OUT SCMD,&B100000          'Command Code = Select
1550 "WAITCC"
1560 'IF R THEN PRINT"Selection Error[";BIN$(R);"]":GOTO"ERR"
1570 RETURN
1580 '
1590 LABEL"COMMAND"
1600 "SETTLEN"
1610 IF (INP(PSNS) AND &B111)<>&B10 THEN PRINT"Command Phase Error":GOTO"ERR"
1620 OUT PCTL,&B10              'Set Command Phase
1630 OUT INRS,&HFF              'Reset Interrupt
1640 OUT SCMD,&B10000100        'Command Code = Transfer
1650 FOR X=0 TO TLEN-1
1660   WAIT SSTS,&B10,&B10      'Check FIFO Full
1670   OUT DREG,CDB(X)
1680 NEXT
1690 "WAITCC"
1700 IF R THEN PRINT"Command Tx Error[";BIN$(R);"]":GOTO"ERR"
1710 RETURN
1720 '
1730 LABEL"DATIN"
1740 "SETTLEN"
1750 IF (INP(PSNS) AND &B111)<>&B1 THEN PRINT"Data In Phase Error":GOTO"ERR"
1760 OUT PCTL,&B1               'Set Data In Phase
1770 OUT INRS,&HFF              'Reset Interrupt
1780 OUT SCMD,&B10000100        'Command Code = Transfer
1790 FOR X=0 TO TLEN-1
1800   WAIT SSTS,&B1,&B1        'Check FIFO Empty
1810   BUF(X)=INP(DREG)
1820 NEXT
1830 "WAITCC"
1840 IF R THEN PRINT"Data In Error[";BIN$(R);"]":GOTO"ERR"
1850 RETURN
1860 '
1870 LABEL"STSMSG"
1880 WAIT PSNS,&B10000000       'Wait REQ Assert
1890 IF (INP(PSNS) AND &B111)<>&B11 THEN PRINT"Status Phase Error":GOTO"ERR"
1900 OUT PCTL,&B11              'Set Status Phase
1910 OUT SCMD,&B11100100        'Set ACK/REQ
1920 WAIT PSNS,&B10000000,&B10000000    'Wait REQ Negate
1930 STAT=INP(TEMP)
1940 OUT SCMD,&B11000100        'Reset ACK/REQ
1950 WAIT PSNS,&B10000000       'Wait REQ Assert
1960 IF (INP(PSNS) AND &B111)<>&B111 THEN PRINT"Message Phase Error":GOTO"ERR"
1970 OUT PCTL,&B111             'Set Message In Phase
1980 OUT SCMD,&B11100100        'Set ACK/REQ
1990 WAIT PSNS,&B10000000,&B10000000    'Wait REQ Negate
2000 MESG=INP(TEMP)
2010 OUT SCMD,&B11000100        'Reset ACK/REQ
2020 RETURN
2030 '
2040 LABEL"ERR":PRINT"SCSI ERROR"
2050 BEEP:"INITSPC":"SRST"
2060 END
2070 '
2080 LABEL"SETCDB"
2090 READ TLEN:FOR R=0 TO TLEN-1:READ CDB(R):NEXT:RETURN
2100 '
2110 LABEL"TESTUNIT"
2120 DATA 6,0,0,0,0,0,0 'testunit
2130 RESTORE"TESTUNIT"
2140 "SETCDB"
2150 "SELECT"
2160 IF R THEN RETURN
2170 "COMMAND"
2180 "STSMSG"
2190 RETURN
2200 '
2210 LABEL"INQUIRY"
2220 DATA 6,&h12,0,0,0,36,0 'inquiry
2230 RESTORE"INQUIRY"
2240 "SETCDB"
2250 "SELECT"
2260 "COMMAND"
2270 TLEN=CDB(4)
2280 "DATIN"
2290 "STSMSG"
2300 RETURN
2310 '
2320 LABEL"DISPDEV"
2330 "INQUIRY"
2340 R$="":FOR R=8 TO 15:R$=R$+CHR$(BUF(R)):NEXT:PRINT R$;" ";
2350 R$="":FOR R=16 TO 31:R$=R$+CHR$(BUF(R)):NEXT:PRINT R$;" ";
2360 R$="":FOR R=32 TO 35:R$=R$+CHR$(BUF(R)):NEXT:PRINT R$;" ";
2370 PRINT "SCSI";HEX$(BUF(2) AND &B111);" ";
2380 ON (BUF(3) AND &B1111)+2 GOTO 2390,2400,2410,2420
2390 PRINT"Nazo  ";:GOTO2430
2400 PRINT"SCSI1 ";:GOTO2430
2410 PRINT"CSS   ";:GOTO2430
2420 PRINT"SCSI2 ";:GOTO2430
2430 IF (BUF(0) AND &HF)<&HA THEN PRINT DTYPE$(BUF(0) AND &HF); ELSE PRINT"謎";
2440 PRINT
2450 RETURN
2460 '
2470 LABEL"NODEV"
2480 PRINT "-------- ";STRING$(16,"-");" ---- ----- ----- -- 未接続 --"
2490 RETURN
2500 '
2510 LABEL"MAIN"
2520 PRINT"SCSI BUS DEVICE LIST"
2530 RESTORE"MAIN"
2540 FOR R=0 TO 9:READ N$:DTYPE$(R)=N$:NEXT
2550 DATA "ハ-ドディスク","テ-プ","プリンタ","プロセッサ","WONCE","CDROM","スキャナ","光磁気ディスク","メディアチェンジャ","通信"
2560 "INITSPC"
2570 PRINT"--- -------- ---------------- ---- ----- ----- -------------------"
2580 PRINT"No. 製造者   製品名           Rev.             分類"
2590 PRINT"--- -------- ---------------- ---- ----- ----- -------------------"
2600 FOR TARGET=0 TO 6
2610   PRINT"ID";HEX$(TARGET);":";
2620   COLOR5:CFLASH1:PRINT"接続確認中";STRING$(10,&H1D);:CFLASH0:COLOR7
2630   "TESTUNIT"
2640   IF R=0 THEN GOSUB"DISPDEV" ELSE GOSUB"NODEV"
2650 NEXT
2660 PRINT"ID7:SHARP    X1TURBO          0085 SCSI1 CSS   プロセッサ"
2670 PRINT"--- -------- ---------------- ---- ----- ----- -------------------"
実行すると、次のような表示をします。
ID0はMOドライブ、ID1とID2は変換番長、ID6はCDROMドライブ、そしてオマケのID7。

2018/03/12

SCSIに非対応なソフトへの対応

BIOSを普通に呼び出しているソフトであれば従来のもの(SASI)と同様にほぼ動作するわけですが、中には特殊なソフトウェアもあり、特にシャープ純正にそういった曲者が多くあります。
  • 5.25"FDの2DをDMA転送で使用
  • BIOSワークの未公開フラグを使用してFDC-GVRAM間を直接転送
  • BIOSワークに展開されたR/Wルーチンの書き換え
  • BIOSの変な所を呼び出している
など、公然の裏技というか、メーカーならではのやりたい放題(上の二つは有名ですね

HuBASIC, turbo CP/MでSCSIが使えるようになってからも、全く動作せずハングアップしたり謎のエラーが出たりするソフトがひとつだけ存在していて、使わないソフトだったのでずっと放置していました。

その動作しなかったシャープ純正ソフトは"ユーザー辞書確保.Uty"です。
大した事をしてなさそうで、いろいろ際どい事をやっているソフトだったわけです。

調べたところ、動かない原因は次の2つ。
  1. BIOSの変な所を呼び出している
  2. BIOSワークに展開されたR/Wルーチンの書き換え
BIOSの変な所を呼び出している 」への対応
まともなエントリではない所を呼び出されてもいいように、SCSI BIOS内のアドレスをSASIと同じ配置にする事で対応しました。動かないソフトの方を書き換えてもいいのですが、こういったソフトが他にもある可能性を考えて。

BIOSワークに展開されたR/Wルーチンの書き換え」への対応
書き換えている事は分かっていたのですが、なぜ書き込み処理が終わった後のチェック処理で書き込み失敗と判定されるのか当時分からず、このため放置する事に…

書き換えが行われる、BIOSワークに展開されたSASIのR/Wルーチンは次のようになっています。
F929  06 1E     HDDMAS: LD      B,1EH
F92B  ED 41             OUT     (C),B
F92D  F3                DI
F92E  3E 87             LD      A,87H
F930  01 1F80           LD      BC,1F80H
F933  ED 79             OUT     (C),A
F935  1E 10             LD      E,10H
F937  21 0000           LD      HL,0
F93A  01 0FD1           LD      BC,0FD1H
F93D  ED 78     LF93D:  IN      A,(C)
F93F  E6 1F             AND     1FH
F941  FE 0F             CP      0FH
F943  28 09             JR      Z,LF94E
F945  2B                DEC     HL
F946  7C                LD      A,H
F947  B5                OR      L
F948  20 F3             JR      NZ,LF93D
F94A  1D                DEC     E
F94B  20 F0             JR      NZ,LF93D
F94D  37                SCF
F94E  06 1D     LF94E:  LD      B,1DH
F950  ED 41             OUT     (C),B
F952  FB                EI
F953  C9                RET
ここが、次の内容に書き換えられます。
F929  06 1E     HDDMAS: LD      B,1EH
F92B  ED 41             OUT     (C),B
F92D  F3                DI
F92E  00                NOP
F92F  00                NOP
F930  CD DFD0           CALL    LDFD0
F933  00                NOP
F934  00                NOP
F935  1E 10             LD      E,10H
F937  21 0000           LD      HL,0
F93A  01 0FD1           LD      BC,0FD1H
F93D  ED 78     LF93D:  IN      A,(C)
この書き換えられたところから、次のDMA設定処理が呼び出されます。
DFD0  01 1F80   LDFD0:  LD      BC,1F80H
DFD3  3E 34             LD      A,34H
DFD5  ED 79             OUT     (C),A
DFD7  3E 87             LD      A,87H
DFD9  ED 79             OUT     (C),A
DFDB  C9                RET
BASICプログラム中のでは、次のリストです。
2270 POKE &HDF10,&H28,&H79:MEM$(&HDFD0,12)=HEXCHR$("01801F3E34ED793E87ED79C9")
2280 STOP OFF
2290 MEM$(&HF92E,7)=HEXCHR$("0000CDD0DF0000")
書き換えられた部分から呼び出される DFD0H~では、DMA転送のソースとなるメインメモリ(ポートA)側をアドレス固定に再設定しています。こうすることで、同じデータを大量に書き込む際でも、1バイトのメモリだけ設定すれば済むようになります。

初めはSCSI BIOSに何らかの見落としでレジスタ値の齟齬でもあるのかと考えていたのですが、ようやく「ソース側をアドレス固定」という小細工と、SCSI BIOSで256バイト以外のセクタサイズに対応させた事と、ひじょーに相性が悪い事に気付きました。

なぜ、チェック処理で書き込み失敗と判定されるのかと言うと、SCSI BIOSではセクタサイズ256バイト以外にも対応するために、内部的に1セクタごとの処理に分割し、1セクタ分(256バイト)転送したらメモリ側アドレスに256加算という処理を、指定回数だけ繰り返します。この「内部的にメモリ側のアドレスに256加算」で、256バイト先の全く別のデータを参照してしこれを書き込んでいたため、チェック処理で引っ掛かっていたわけです。

問題となる処理は次のようになっています。
2300 FOR I3=0 TO KAISU
2310 IF SL>=256 THEN SECL=255:SL=SL-SECL ELSE SECL=SL
2320 POKE &HDFFD,SECL,FNX2(REC11),FNX1(REC11)
2330 CALL FDWR
2340 REC11=REC11+SECL
2350 NEXT I3
"KAISU"回のループ中で、"SECL"に処理するセクタ数、"REC11"に開始セクタ番号、そして"CALL FDWR"で書き込み。なので、"CALL FDWR"で1セクタだけ書き込むように変更し、これをSECL"回呼び出すようにします。
2330 FOR A=0 TO SECL-1:POKE &HDFFD,1,FNX2(REC11+A),FNX1(REC11+A):CALL FDWR:NEXT
これで動くようになったわけではありますが、いまさらユーザー辞書とか使わないわけで…音訓変換で十分過ぎる気がします。

2018/02/18

SCSIだけでなく、SASIでも使える小ネタ

HuBASICでは10MBまでのHDDを扱えるようになっているわけですが、わずか(でもない?)な小細工で16MBまで拡張することができます。それと、以前に触れたHDDのドライブ番号4~9を使えるようにする方法。

まず、BIOS ROMをレコード番号の最大値チェックを消したものか、SCSIに対応したBIOSに載せ換えます。とりあえず最大値チェックをスルーするには 7A4EH の CDH を 21H に書き換えで対応します。

そして、通常の使用開始手順と同様に"HD FORMAT.Uty"のあと、"HD MAP.Uty"でマッピングをします。

さらに、下記のプログラムを実行します。
100 A$=STRING$(128,0)
110 FOR R=28 TO 39
120  PRINT R;
130   DEVO$"HD4:",R,A$,A$
140 NEXT
"HD4:"の部分は、各自で対象ドライブに変更してね。

ここでは、FAT領域を従来の10MB分(レコード番号8~27)の後方に、6MB分(レコード番号28~39)を初期化(&追加)しています。

でもって、CZ-8FB02の"Start up.Bas"に、下記を追加。
POKE &H32AF,32
これは、FAT領域のレコード数を従来の10MB分(20レコード)から、拡張した16MB分(32レコード)への対応です。

いろいろ書き換えて気持ち悪いので、IPLリセットで再起動し、容量の増加を確認してください。


最後に、ドライブ番号4~9に対応させる方法。
POKE &H32E5,10
ここでは、使用可能なドライブ数を設定しています。

ちなみに、CZ-8FB02における最大デバイス数の対応は下記のよーになっています。
32DC 01H ...SCR
32DD 01H ...CRT
32DE 01H ...KEY
32DF 01H ...LPT
32E0 01H ...CAS
32E1 02H ...MEM(GRAM)
32E2 0AH ...EMM
32E3 04H ...5"or3"FDD
32E4 04H ...8"FDD
32E5 04H ...HDD
32E6 01H ...COM(RS-232C)
CZ-8FB03は全く解析していないので書き換え箇所は不明です。構造はそんなに変わらないと思うので該当箇所の発見は容易だと思われます。

以上です。