misc/scsi16.s
;========================================================================================
; scsi16.s
; Copyright (C) 2003-2025 Makoto Kamada
;
; This file is part of the XEiJ (X68000 Emulator in Java).
; You can use, modify and redistribute the XEiJ if the conditions are met.
; Read the XEiJ License for more details.
; https://stdkmd.net/xeij/
;========================================================================================
;----------------------------------------------------------------
;
; scsi16in.r / scsi16ex.r
; SCSIINROM 16とSCSIEXROM 16
;
; 最終更新
; 2025-08-03
;
; 作り方
; has060 -i include -o scsi16in.o -w scsi16.s -SSCSIEXROM=0
; lk -b fc0000 -o scsi16in.x -x scsi16in.o
; cv /rn scsi16in.x scsi16in.r
; has060 -i include -o scsi16ex.o -w scsi16.s -SSCSIEXROM=1
; lk -b ea0000 -o scsi16ex.x -x scsi16ex.o
; cv /rn scsi16ex.x scsi16ex.r
;
; 修正箇所
; 接続されているだけで起動できなくなる機器がある
; 起動時のRequest SenseとInquiryのアロケーション長が短すぎる
; 短すぎるアロケーション長に従わない機器が接続されていると起動時に固まる
; アロケーション長を十分な長さにする
; 書き込みに失敗する可能性がある
; DMA転送の書き込みでバスエラーから復帰するときDMACとSPCの残りデータ数が食い違う場合がある
; 食い違ったまま復帰すると同じデータが2回出力され全体の数が合わなくなる
; バスエラーから復帰するときSPCの残りデータ数を用いてDMACのアドレスと残りデータ数を再計算する
; 読み出しに失敗する可能性がある
; データインフェーズからステータスフェーズに移るときACKがネゲートされるのを待たない機器があるらしい
; FIFOが空になる前にフェーズが変わるとService Requiredが発生して異常終了する
; FIFOが空でないときService Requiredを無視する
; SASI HDを接続してSASIフラグをセットすると起動できなくなる
; _B_DSKINIがd5/a2を破壊している
; SCSIデバイスドライバ組み込みルーチンが_B_DSKINIを跨いでa2を使っていてスタックが破壊される
; _B_DSKINIでd5/a2を保護する
;
; 追加機能
; MC68040とMC68060に対応する
; MC68040またはMC68060のときDMA転送開始前にキャッシュをプッシュする
; MC68060の未実装整数命令例外の発生を避けるためMOVEP命令を使わない
; ブロック長が2048の機器のディスクIPLとデバイスドライバを読み出せる
; ディスクIPLの位置は$0400と$0800のどちらでもよい
; S_READなどでd5のブロック長指数が4以上のとき3と見なす
; NetBSD/x68kのインストールCD-ROMから起動できる
; ディスクIPLとデバイスドライバが対応しなければブロック長が2048の機器から起動できないことに変わりはない
; 4096以上は非対応
;
;----------------------------------------------------------------
.include bioswork.equ
.include control2.mac
.include dmac.equ
.include dosconst.equ
.include hdc.equ
.include iocscall.mac
.include mfp.equ
.include misc.mac
.include push2.mac
.include scsicall.mac
.include spc.equ
.include sram.equ
.include sysport.equ
.include vector.equ
.ifndef SCSI_BIOS_LEVEL
SCSI_BIOS_LEVEL equ 16 ;レベル。0=SUPER,3=XVI,4=FORMAT.X,10=X68030,16=XEiJ
.endif
.ifndef SCSIEXROM
SCSIEXROM equ 0 ;拡張か。0=SCSIINROM,1=SCSIEXROM
.endif
.if 16<=SCSI_BIOS_LEVEL
.if SCSIEXROM
SCSI_BIOS_TITLE reg 'SCSIEXROM 16 (2025-08-03)'
.else
SCSI_BIOS_TITLE reg 'SCSIINROM 16 (2025-08-03)'
.endif
.endif
.cpu 68000
.text
;--------------------------------------------------------------------------------
; .include sc01head.s
;--------------------------------------------------------------------------------
.if SCSIEXROM
SPC_BASE equ SPC_EX_BASE ;拡張SPCベースアドレス
.else
SPC_BASE equ SPC_IN_BASE ;内蔵SPCベースアドレス
.endif
.if SCSI_BIOS_LEVEL<=3
abs reg .l ;(xxx)absを絶対ロングにする
.else
abs reg .w ;(xxx)absを絶対ワードにする
.endif
dLEN reg d3 ;データの長さ
dID reg d4 ;(LUN<<16)|SCSI-ID
aBUF reg a1 ;バッファのアドレス
aSPC reg a6 ;SPC_xxx(aSPC)でSPCのレジスタを参照する
scsi_bios_start:
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
.if SCSIEXROM
;----------------------------------------------------------------
;SPC
spc_ex_base:
.dcb.b 32,$FF
.endif
.endif
.if SCSI_BIOS_LEVEL<>4
;----------------------------------------------------------------
;ROM起動ハンドル
rom_boot_handle:
.dc.l rom_boot_routine ;+0
.if SCSI_BIOS_LEVEL<>10
.dc.l rom_boot_routine ;+4
.dc.l rom_boot_routine ;+8
.dc.l rom_boot_routine ;+12
.dc.l rom_boot_routine ;+16
.dc.l rom_boot_routine ;+20
.dc.l rom_boot_routine ;+24
.dc.l rom_boot_routine ;+28
.endif
;----------------------------------------------------------------
;ROM起動ハンドル+32 SCSI初期化ハンドル
scsi_init_handle:
.dc.l scsi_init_routine ;+32
.endif
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
;----------------------------------------------------------------
;ROM起動ハンドル+36 SCSIIN/SCSIEXマジック
scsi_rom_magic:
.if SCSIEXROM
.dc.b 'SCSIEX' ;+36
.else
.dc.b 'SCSIIN' ;+36
.endif
.endif
;--------------------------------------------------------------------------------
; .include sc02boot.s
;--------------------------------------------------------------------------------
.if SCSI_BIOS_LEVEL<>4
;----------------------------------------------------------------
;ROM起動ハンドル+42 SCSI BIOSレベル
scsi_bios_level:
.dc.w SCSI_BIOS_LEVEL ;+42
.if 16<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
scsi_bios_title:
.dc.b SCSI_BIOS_TITLE,0
.even
.endif
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;SPCベースハンドル
; レベル4のSPCベースハンドルはデバイスドライバが内蔵と拡張を選択する
spc_base_handle:
.dc.l SPC_BASE ;SPCベースアドレス
.endif
.if SCSI_BIOS_LEVEL<>4
;----------------------------------------------------------------
;SCSI初期化ルーチン
;?d0-d1/a1
scsi_init_routine:
.if SCSI_BIOS_LEVEL<>10
;_SCSIDRVを登録する
moveq.l #_B_INTVCS,d0
move.l #$100+_SCSIDRV,d1
lea.l iocs_F5_SCSIDRV(pc),a1 ;IOCSコール$F5 _SCSIDRV
trap #15
.if SCSI_BIOS_LEVEL<=10
if <cmp.l a1,d0>,ne ;初回
.else
.if SCSIEXROM
ifor <cmp.l a1,d0>,ne,<btst.b #1,BIOS_SCSI_INITIALIZED.w>,eq
.else
ifor <cmp.l a1,d0>,ne,<btst.b #0,BIOS_SCSI_INITIALIZED.w>,eq
.endif
;_SCSIDRVのベクタが自分を指していなかったまたはSCSI初期化済みフラグがセットされていないとき
.endif
;_S_RESETを呼び出す
moveq.l #_SCSIDRV,d0
moveq.l #_S_RESET,d1
trap #15
.if 16<=SCSI_BIOS_LEVEL
goto <tst.b SRAM_SCSI_SASI_FLAG>,eq,scsi_init_skip ;SASI機器が接続されていない
goto <tst.l BIOS_SCSI_OLD_VERIFY.w>,ne,scsi_init_skip ;既に拡張されている
.endif
;IOCSコール$40~$4Fを登録する
bsr install_sasi_iocs ;SCSIバスに接続されているSASI機器をIOCSコール$40~$4Fで操作できるようにする
;TRAP#11(BREAK)を登録する
moveq.l #_B_INTVCS,d0
moveq.l #OFFSET_TRAP_11/4,d1 ;例外ベクタ$2B TRAP#11(BREAK)
lea.l trap_11_break(pc),a1 ;TRAP#11(BREAK)
trap #15
.if 16<=SCSI_BIOS_LEVEL
;TRAP#11(BREAK)を登録してから元のベクタを保存するまでの間にBREAKキーが押される可能性がゼロではないので手順としては正しくない
move.l d0,BIOS_SCSI_OLD_TRAP11.l ;例外ベクタ$2B TRAP#11(BREAK)の元のベクタ
scsi_init_skip:
.endif
endif
.else
bsr dskini_all ;SASIハードディスクを初期化する
.endif
rts
;----------------------------------------------------------------
;ROM起動ルーチン-20 ROM起動マジック
; ROM 1.3が起動するSCSI-IDを求めるときに確認する
rom_boot_magic:
.dc.l 'SCSI'
;----------------------------------------------------------------
;ROM起動ルーチン-16 SCSIデバイスドライバ組み込みハンドル
; Human68k 3.02がデバイスドライバを組み込むときに参照する
device_installer_handle:
.dc.l device_installer ;SCSIデバイスドライバ組み込みルーチン
;----------------------------------------------------------------
;ROM起動ルーチン-12 SCSIデバイスドライバ組み込みルーチンのパラメータ
; Human68k 3.02がSCSIデバイスドライバを組み込むときに参照する
; FORMAT2.Xがハードディスクに書き込むSCSIデバイスドライバに
; 「指定されたSCSI ROMを用いて_S_RESETを実行し、設定されていなければ_SCSIDRVを設定する」
; という処理があり、ここを参照している
; ここにはIOCSコール$F5 _SCSIDRVのハンドルがなければならない
device_installer_parameter:
.dc.l iocs_F5_SCSIDRV ;IOCSコール$F5 _SCSIDRV
;----------------------------------------------------------------
;ROM起動ルーチン-8 デバイスドライバ識別子
; Human68k 3.02がSCSIデバイスドライバを組み込むときに確認する
device_installer_magic:
.dc.b 'Human68k'
;----------------------------------------------------------------
;ROM起動ルーチン
rom_boot_routine:
;起動するSCSI-IDを求める
.if SCSI_BIOS_LEVEL<>10
IOCS _BOOTINF
.if 3<=SCSI_BIOS_LEVEL
andi.l #$00FFFFFF,d0
.endif
move.l d0,d4
subi.l #rom_boot_handle,d4 ;ROM起動ハンドルからのオフセット
lsr.l #2,d4 ;起動するSCSI-ID
.else
bsr get_scsi_id_to_boot ;起動するSCSI-IDを求める
if <tst.l d0>,mi
moveq.l #0,d0
endif
move.l d0,d4 ;起動するSCSI-ID
.endif
;<d4.l:起動するSCSI-ID。-1=SCSI起動ではない
.if SCSI_BIOS_LEVEL<>10
.if SCSI_BIOS_LEVEL<=10
;_SCSIDRVを登録する
moveq.l #_B_INTVCS,d0
move.l #$100+_SCSIDRV,d1
lea.l iocs_F5_SCSIDRV(pc),a1 ;IOCSコール$F5 _SCSIDRV
trap #15
if <cmp.l a1,d0>,ne ;初回
;_S_RESETを呼び出す
moveq.l #_SCSIDRV,d0
moveq.l #_S_RESET,d1 ;SPCの初期化とSCSIバスリセット
trap #15
;(SCSIから起動したとき)
;IOCSコール$40~$4Fを登録する
bsr install_sasi_iocs ;SCSIバスに接続されているSASI機器をIOCSコール$40~$4Fで操作できるようにする
;TRAP#11(BREAK)を登録する
moveq.l #_B_INTVCS,d0
moveq.l #OFFSET_TRAP_11/4,d1 ;例外ベクタ$2B TRAP#11(BREAK)
lea.l trap_11_break(pc),a1 ;TRAP#11(BREAK)
trap #15
.if 3<=SCSI_BIOS_LEVEL
move.l d0,BIOS_SCSI_OLD_TRAP11.l ;例外ベクタ$2B TRAP#11(BREAK)の元のベクタ
.endif
endif
.else
bsr scsi_init_routine ;SCSI初期化ルーチン
.endif
.else
bsr dskini_all ;SASIハードディスクを初期化する
.endif
;アクセス開始
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,ne,scsi_boot_failed ;起動するSCSI-IDのSASIフラグがセットされているので失敗
.if SCSI_BIOS_LEVEL<=3
moveq.l #10-1,d6 ;10回までリトライする
.else
moveq.l #20-1,d6 ;20回までリトライする
.endif
scsi_boot_redo:
bsr check_confliction_1st ;本体と同じSCSI-IDの機器がないか確認する
;<d0.l:-1=本体と同じSCSI-IDの機器はない
.if SCSI_BIOS_LEVEL<=3
goto <cmp.l #-1,d0>,ne,scsi_boot_failed ;本体と同じSCSI-IDの機器が接続されているので失敗
.else
addq.l #1,d0
goto ne,scsi_boot_failed ;本体と同じSCSI-IDの機器が接続されているので失敗
.endif
;Test Unit Ready
moveq.l #_SCSIDRV,d0
moveq.l #_S_TESTUNIT,d1
trap #15
.if SCSI_BIOS_LEVEL<=3
goto <cmp.l #0,d0>,eq,test_unit_passed ;_S_TESTUNITでCommand Completeが返った
.else
goto <tst.l d0>,eq,test_unit_passed ;_S_TESTUNITでCommand Completeが返った
.endif
goto <cmp.l #-1,d0>,eq,scsi_boot_retry ;エラーのときはリトライ
goto <cmp.l #8,d0>,eq,scsi_boot_retry ;Busyのときはリトライ
goto <cmp.l #2,d0>,ne,scsi_boot_failed ;Check Conditionでなければ失敗
;_S_TESTUNITでCheck Conditionが返った
;Request Sense
moveq.l #_SCSIDRV,d0
moveq.l #_S_REQUEST,d1
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;Request Senseのアロケーション長が足りない
; Request Senseのセンスデータはエラークラスによって4バイトまたは8バイト以上だがアロケーション長が3バイトになっている
; 起動時にアロケーション長よりも多くのデータを返そうとするSCSI機器が接続されて電源が入っているとハングアップする
; 参考: 電脳倶楽部111号 FDS120T.DOC
moveq.l #3,d3 ;アロケーション長
;+++++ BUG +++++
.else
moveq.l #8,d3 ;アロケーション長。8以上
.endif
.if SCSI_BIOS_LEVEL<=3
lea.l $00002000.l,a1
.else
lea.l $2000.w,a1
.endif
trap #15
goto <tst.l d0>,ne,scsi_boot_failed
.if SCSI_BIOS_LEVEL<=3
lea.l $00002000.l,a1
.else
lea.l $2000.w,a1
.endif
move.b (a1),d0 ;センスエラーコード
andi.b #$70,d0
goto <cmpi.b #$70,d0>,ne,scsi_boot_failed ;拡張センスキーがなければ失敗
move.b 2(a1),d0 ;センスキー
goto eq,scsi_boot_redo ;No Senseはリトライ
goto <cmp.b #1,d0>,eq,scsi_boot_redo ;Recovered Errorはリトライ
goto <cmp.b #6,d0>,eq,scsi_boot_redo ;Unit Attentionはリトライ
.if 10<=SCSI_BIOS_LEVEL
goto <cmp.b #2,d0>,eq,scsi_boot_redo ;Not Readyはリトライ
.endif
goto scsi_boot_failed ;それ以外は失敗
;リトライ
scsi_boot_retry:
dbra.w d6,scsi_boot_redo_1
;リトライ回数が上限を超えた
goto scsi_boot_failed
scsi_boot_redo_1:
goto scsi_boot_redo
scsi_boot_failed:
rts
;_S_TESTUNITでCommand Completeが返った
test_unit_passed:
.if SCSI_BIOS_LEVEL<=3
bsr check_confliction_1st ;本体と同じSCSI-IDの機器がないか確認する
.else
bsr check_confliction_2nd ;本体と同じSCSI-IDの機器がないか確認する(確認済みならば何もしない)
.endif
;<d0.l:-1=本体と同じSCSI-IDの機器はない
.if SCSI_BIOS_LEVEL<=3
goto <cmp.l #-1,d0>,ne,scsi_boot_failed ;本体と同じSCSI-IDの機器が接続されているので失敗
.else
addq.l #1,d0
goto ne,scsi_boot_failed ;本体と同じSCSI-IDの機器が接続されているので失敗
.endif
;Inquiry
.if SCSI_BIOS_LEVEL<=3
lea.l $00002000.l,a1
.else
lea.l $2000.w,a1
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_INQUIRY,d1
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;Inquiryのアロケーション長が足りない
; InquiryでEVPDが0のときアロケーション長は5バイト以上でなければならないのに1バイトになっている
; Inquiryは1回目に5バイト要求して2回目に追加データ長+5バイト要求するのが正しい
; 最初から36バイト要求しても良いが2回に分ける方が無難
moveq.l #1,d3
;+++++ BUG +++++
.else
moveq.l #5,d3 ;アロケーション長。5以上
.endif
trap #15
goto <tst.l d0>,ne,scsi_boot_failed ;INQUIRYで失敗
.if SCSI_BIOS_LEVEL<=3
gotoand <cmpi.b #$84,0.w(a1)>,ne,<tst.b 0.w(a1)>,ne,scsi_boot_failed ;SHARP MOとダイレクトアクセスデバイス以外は失敗
.else
ifand <btst.b #SRAM_SCSI_IGNORE_BIT,SRAM_SCSI_MODE>,eq,<tst.b (a1)>,ne,<cmpi.b #$04,(a1)>,ne,<cmpi.b #$05,(a1)>,ne,<cmpi.b #$07,(a1)>,ne,<cmpi.b #$84,(a1)>,ne
;タイプ無視ではなくて
;デバイスタイプが
; $00(ダイレクトアクセスデバイス)
; $04(ライトワンスデバイス(追記型光ディスク))
; $05(CD-ROMデバイス)
; $07(光メモリデバイス(消去可能光ディスク))
; $84(SHARP MO)
;ではない
goto scsi_boot_failed ;失敗
endif
.endif
;Rezero Unit
moveq.l #_SCSIDRV,d0
moveq.l #_S_REZEROUNIT,d1
trap #15
goto <tst.l d0>,ne,scsi_boot_failed ;REZEROUNITで失敗
;Read Capacity
moveq.l #_SCSIDRV,d0
moveq.l #_S_READCAP,d1
trap #15
goto <tst.l d0>,ne,scsi_boot_failed ;READCAPで失敗
.if SCSI_BIOS_LEVEL<=0
;+++++ BUG +++++
;ブロック長が2048以上のとき素通りさせているが正常に動作しない
;+++++ BUG +++++
.elif SCSI_BIOS_LEVEL<=3
goto <cmpi.l #2048,4(a1)>,cc,scsi_boot_failed ;ブロック長が2048以上のときは失敗
.elif SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;ブロック長が2048以上のとき素通りさせているが正常に動作しない
;+++++ BUG +++++
.endif
move.l 4(a1),d5 ;ブロック長
lsr.l #8,d5
lsr.l #1,d5 ;256→0,512→1,1024→2,2048→4,4096→8,…
.if 16<=SCSI_BIOS_LEVEL
goto <cmp.l #4,d5>,hi,scsi_boot_failed ;ブロック長が大きすぎるので失敗
if eq ;2048
moveq.l #3,d5 ;2048→3
endif
.endif
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
.if SCSI_BIOS_LEVEL<=10
;$0000-$03FFを$2000-$23FFに読み込む
moveq.l #$0000/256,d2
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
lsr.l d5,d2
moveq.l #$0400/256,d3
lsr.l d5,d3
.else
moveq.l #$0400/256,d3
bsr adjust_block_number ;ブロック長に応じてブロック番号とブロック数を調整する
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_READ,d1
trap #15
goto <tst.l d0>,ne,scsi_boot_failed ;READで失敗
gotoor <cmpi.l #'X68S',0.w(a1)>,ne,<cmpi.l #'CSI1',4(a1)>,ne,scsi_boot_failed ;装置初期化されていないので失敗
;$0400-$07FFを$2000-$23FFに読み込む
moveq.l #$0400/256,d2
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
lsr.l d5,d2
moveq.l #$0400/256,d3
lsr.l d5,d3
.else
moveq.l #$0400/256,d3
bsr adjust_block_number ;ブロック長に応じてブロック番号とブロック数を調整する
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_READ,d1
trap #15
goto <tst.l d0>,ne,scsi_boot_failed ;READで失敗
goto <cmpi.b #$60,(a1)>,ne,scsi_boot_failed ;IPLの先頭がbraでないので失敗
jsr (a1) ;ディスクIPLを起動する
goto scsi_boot_failed ;ディスクIPLから帰ってきてしまったので失敗
.else
;$0000-$07FFを$2000-$27FFに読み込む
moveq.l #$0000/256,d2
moveq.l #$0800/256,d3
lsr.l d5,d2
lsr.l d5,d3
lea.l $2000.w,a1
SCSI _S_READ
goto <tst.l d0>,ne,scsi_boot_failed ;READで失敗
gotoor <cmpi.l #'X68S',(a1)>,ne,<cmpi.l #'CSI1',4(a1)>,ne,scsi_boot_failed ;装置初期化されていないので失敗
if <cmpi.b #$60,$0400(a1)>,eq ;$0400-$07FFにディスクIPLがある
;$2400-$27FFを$2000-$23FFにコピーする
lea.l $2000.w,a1
move.w #$0400/4-1,d0
for d0
move.l $0400(a1),(a1)+
next
move.w #$0400/4-1,d0
for d0
clr.l (a1)+
next
;2025-08-02 ここでd2.lが0になっているとNetBSDが起動しない
; https://github.com/NetBSD/src/blob/fcd96f7d78eb0d70b7f75be4fa69e46d5420b1b1/sys/arch/x68k/stand/boot_ufs/boot.S#L204C5-L204C54
moveq.l #$0400/256,d2
lsr.l d5,d2
else
;$0400-$07FFにディスクIPLがない
;$0800-$0FFFを$2000-$27FFに読み込む
moveq.l #$0800/256,d2
moveq.l #$0800/256,d3
lsr.l d5,d2
lsr.l d5,d3
lea.l $2000.w,a1
SCSI _S_READ
goto <tst.l d0>,ne,scsi_boot_failed ;READで失敗
goto <cmpi.b #$60,(a1)>,ne,scsi_boot_failed ;$0800-$0FFFにディスクIPLがない
;$0800-$0FFFにディスクIPLがある
endif
bsr cache_flush
moveq.l #0,d0
lea.l $2000.w,a1
jsr (a1) ;ディスクIPLを起動する
goto scsi_boot_failed ;ディスクIPLから帰ってきてしまったので失敗
.endif
.if SCSI_BIOS_LEVEL==10
;----------------------------------------------------------------
;起動するSCSI-IDを求める
;>d0.l:SCSI-ID(0~7,-1=SCSI起動ではない)
get_scsi_id_to_boot:
IOCS _BOOTINF
andi.l #$00FFFFFF,d0
if <cmp.l #$00000100,d0>,cc ;ROM起動またはSRAM起動
;+++++ BUG +++++
;ROM起動アドレス-20を不用意にリードしている
; もしもSRAM起動ならばSRAM起動ルーチンの先頭4バイトの値-20をリードすることになる
; 起動したSCSI ROMが自分でなくてもSCSI-IDを判別できるようにしようとしたように見えるが目的が不明
movea.l d0,a0 ;ROM起動ハンドルまたはSRAM起動アドレス
movea.l (a0),a0 ;ROM起動アドレス
;+++++ BUG +++++
if <cmpi.l #'SCSI',rom_boot_magic-rom_boot_routine(a0)>,eq ;ROM起動マジックを比較。SCSI起動
andi.l #31,d0 ;SCSI ROMの先頭からのオフセット
lsr.l #2,d0 ;起動するSCSI-ID
rts
endif
;SCSI起動ではない
endif
;ROM起動またはSRAM起動ではない
moveq.l #-1,d0
rts
.endif
.if 10<=SCSI_BIOS_LEVEL
;起動できない
next_device:
bset.b d2,BIOS_SCSI_UNBOOTABLE.w
addq.w #1,d2
goto install_device
.endif
;----------------------------------------------------------------
;SCSIデバイスドライバ組み込みルーチン
; Human68kがSCSIデバイスドライバを組み込むとき最初に呼び出す
;<d2.l:(パーティションの数<<16)|組み込むSCSI-ID。初回は0。組み込むSCSI-IDが8のとき終了
;<a1.l:デバイスドライバのコピー先のアドレス
;>d2.l:次回の(パーティションの数<<16)|組み込むSCSI-ID
device_installer:
push d0-d1/d3-d7/a0-a6
;起動したSCSI-IDを求める
.if SCSI_BIOS_LEVEL<>10
IOCS _BOOTINF
.if 3<=SCSI_BIOS_LEVEL
andi.l #$00FFFFFF,d0
.endif
subi.l #rom_boot_handle,d0 ;ROM起動ハンドルからのオフセット
if cc
lsr.l #2,d0 ;起動したSCSI-ID
move.b d0,d7 ;起動したSCSI-ID
goto <cmpi.l #8,d0>,cs,install_device ;SCSI起動
endif
moveq.l #-1,d7
goto <cmpi.l #8,d0>,eq,install_device ;起動したSCSI-IDが8。SASI起動?
goto <tst.b d2>,ne,install_device ;組み込むSCSI-IDが0ではない
;組み込むSCSI-IDが0
movea.l a1,a2
;<a2.l:デバイスドライバのコピー先のアドレス
.if SCSI_BIOS_LEVEL<=10
;_SCSIDRVを登録する
moveq.l #_B_INTVCS,d0
move.l #$100+_SCSIDRV,d1
lea.l iocs_F5_SCSIDRV(pc),a1 ;IOCSコール$F5 _SCSIDRV
trap #15
if <cmp.l a1,d0>,ne ;初回
;_S_RESETを呼び出す
moveq.l #_SCSIDRV,d0
moveq.l #_S_RESET,d1 ;SPCの初期化とSCSIバスリセット
trap #15
;(SCSIから起動しなかったとき)
;IOCSコール$40~$4Fを登録しない
;TRAP#11(BREAK)を登録する
moveq.l #_B_INTVCS,d0
moveq.l #OFFSET_TRAP_11/4,d1 ;例外ベクタ$2B TRAP#11(BREAK)
lea.l trap_11_break(pc),a1 ;TRAP#11(BREAK)
trap #15
.if 3<=SCSI_BIOS_LEVEL
move.l d0,BIOS_SCSI_OLD_TRAP11.l ;例外ベクタ$2B TRAP#11(BREAK)の元のベクタ
.endif
endif
.else
bsr scsi_init_routine ;SCSI初期化ルーチン
.endif
movea.l a2,a1
;<a1.l:デバイスドライバのコピー先のアドレス
.else
bsr get_scsi_id_to_boot ;起動したSCSI-IDを求める
if <tst.l d0>,pl
move.b d0,d7 ;起動したSCSI-ID
goto <cmpi.w #8,d0>,cs,install_device
endif
moveq.l #-1,d7 ;SCSI起動ではない
.endif
;SCSI起動
;<d2.l:(パーティションの数<<16)|組み込むSCSI-ID
;<d7.l:起動したSCSI-ID。-1=SCSI起動ではない
;<a1.l:デバイスドライバのコピー先のアドレス
install_device:
goto <cmp.w #8,d2>,eq,install_finish ;組み込むSCSI-IDが8。終了
;本体と同じSCSI-IDの機器がないか確認する
.if SCSI_BIOS_LEVEL<=3
bsr check_confliction_1st ;本体と同じSCSI-IDの機器がないか確認する
goto <cmp.l #-1,d0>,ne,install_finish ;本体と同じSCSI-IDの機器がある
.else
bsr check_confliction_2nd ;本体と同じSCSI-IDの機器がないか確認する(確認済みならば何もしない)
goto <addq.l #1,d0>,ne,install_finish ;本体と同じSCSI-IDの機器がある
.endif
;本体と同じSCSI-IDの機器はない
wait_device:
moveq.l #0,d4
move.w d2,d4 ;組み込むSCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,ne,next_device ;SASIは失敗
.if 10<=SCSI_BIOS_LEVEL
goto <btst.b d4,BIOS_SCSI_UNBOOTABLE.w>,ne,next_device ;起動できない
.endif
move.b SRAM_SCSI_MODE,d0 ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
andi.b #7,d0 ;本体のSCSI-ID
goto <cmp.b d4,d0>,eq,next_device ;本体は失敗
;Test Unit Ready
moveq.l #_SCSIDRV,d0
moveq.l #_S_TESTUNIT,d1
trap #15
if <cmp.l #2,d0>,ne ;Check Condition以外
goto <cmp.l #8,d0>,eq,wait_device ;Busyは待つ
goto <tst.l d0>,ne,next_device ;Check ConditionとBusy以外のエラーは失敗
endif
;Request Sense
moveq.l #_SCSIDRV,d0
moveq.l #_S_REQUEST,d1
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;Request Senseのアロケーション長が足りない
; 同上
moveq.l #3,d3
;+++++ BUG +++++
.else
moveq.l #8,d3 ;アロケーション長。8以上
.endif
trap #15
goto <tst.l d0>,ne,next_device ;REQUESTで失敗
;Inquiry
moveq.l #_SCSIDRV,d0
moveq.l #_S_INQUIRY,d1
moveq.l #36,d3
trap #15
.if SCSI_BIOS_LEVEL<>10
goto <tst.l d0>,ne,next_device ;INQUIRYで失敗
.else
tst.l d0
;!!! ショートで届くのにワードになっている
bne.w next_device ;INQUIRYで失敗
.endif
.if SCSI_BIOS_LEVEL<=3
gotoand <cmpi.b #$84,0.w(a1)>,ne,<tst.b 0.w(a1)>,ne,next_device ;SHARP MOとダイレクトアクセスデバイス以外は失敗
.else
ifand <btst.b #6,SRAM_SCSI_MODE>,eq,<tst.b (a1)>,ne,<cmpi.b #$04,(a1)>,ne,<cmpi.b #$05,(a1)>,ne,<cmpi.b #$07,(a1)>,ne,<cmpi.b #$84,(a1)>,ne
;タイプ無視ではなくて
;デバイスタイプが
; $00(ダイレクトアクセスデバイス)
; $04(ライトワンスデバイス(追記型光ディスク))
; $05(CD-ROMデバイス)
; $07(光メモリデバイス(消去可能光ディスク))
; $84(SHARP MO)
;ではない
goto next_device ;失敗
endif
.endif
;Read Capacity
moveq.l #_SCSIDRV,d0
moveq.l #_S_READCAP,d1
trap #15
goto <tst.l d0>,ne,next_device ;READCAPで失敗
move.l d2,d6 ;(パーティションの数<<16)|組み込むSCSI-ID
move.l 4(a1),d5 ;ブロック長
lsr.l #8,d5
lsr.l #1,d5 ;256→0,512→1,1024→2,2048→4,4096→8,…
.if 16<=SCSI_BIOS_LEVEL
goto <cmp.l #4,d5>,hi,next_device ;ブロック長が大きすぎるので失敗
if eq ;2048
moveq.l #3,d5 ;2048→3
endif
.endif
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
.if SCSI_BIOS_LEVEL<=10
;$0800-$0BFFをa1-(a1+$03FF)に読み込む
moveq.l #$0800/256,d2
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
lsr.l d5,d2
moveq.l #$0400/256,d3
lsr.l d5,d3
.else
moveq.l #$0400/256,d3
bsr adjust_block_number ;ブロック長に応じてブロック番号とブロック数を調整する
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_READ,d1
trap #15
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
goto <cmpi.l #'X68K',(a1)>,ne,next_device ;パーティションテーブルがない。装置初期化されていない
;SCSI起動のときは起動したSCSI-IDの自動起動のパーティションまでの自動起動または使用可能なパーティションの数を数える
;SCSI起動でないときはすべてのSCSI-IDの自動起動または使用可能なパーティションの数を数える
swap.w d2 ;(組み込むSCSI-ID<<16)|パーティションの数
if <cmp.b d7,d4>,ls ;(現在のSCSI-ID)-(起動したSCSI-ID)
;SCSI起動のときは組み込むSCSI-IDが起動したSCSI-ID以下。SCSI起動でないときはすべて
.if SCSI_BIOS_LEVEL<=3
if ne ;組み込むSCSI-IDが起動したSCSI-IDと違う
bsr count_partition_1 ;自動起動または使用可能なパーティションの数を数える
add.w d3,d2 ;パーティションの数を加算
else ;組み込むSCSI-IDが起動したSCSI-IDと同じ
bsr count_partition_2 ;自動起動または使用可能なパーティションの数を自動起動のパーティションが見つかるまで数える
add.w d3,d2 ;パーティションの数を加算
endif
.else
bsr count_partition ;自動起動または起動可能なパーティションを数える
add.w d3,d2 ;パーティションの数を加算
.endif
endif
swap.w d2 ;(パーティションの数<<16)|組み込むSCSI-ID
move.l d2,d6 ;(パーティションの数<<16)|組み込むSCSI-ID
;$0000-$03FFを(a1)-(a1+$03FF)に読み込む
moveq.l #$0000/256,d2
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
lsr.l d5,d2
moveq.l #$0400/256,d3
lsr.l d5,d3
.else
moveq.l #$0400/256,d3
bsr adjust_block_number ;ブロック長に応じてブロック番号とブロック数を調整する
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_READ,d1
trap #15
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
gotoor <cmpi.l #'X68S',0.w(a1)>,ne,<cmpi.l #'CSI1',4(a1)>,ne,next_device ;装置初期化されていない
;$0C00-$3FFFを(a1)-(a1+$33FF)に読み込む
moveq.l #$0C00/256,d2
.if (SCSI_BIOS_LEVEL<=3)|(16<=SCSI_BIOS_LEVEL)
lsr.l d5,d2
moveq.l #$3400/256,d3
lsr.l d5,d3
.else
moveq.l #$3400/256,d3
bsr adjust_block_number ;ブロック長に応じてブロック番号とブロック数を調整する
.endif
moveq.l #_SCSIDRV,d0
moveq.l #_S_READ,d1
trap #15
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
.else
;<d6.l:(パーティションの数<<16)|組み込むSCSI-ID
movea.l a1,a2
;<a2.l:デバイスドライバのコピー先のアドレス
;$0000-$07FFを(a2)-(a2+$07FF)に読み込む
moveq.l #$0000/256,d2
moveq.l #$0800/256,d3
lsr.l d5,d2
lsr.l d5,d3
movea.l a2,a1
SCSI _S_READ
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
gotoor <cmpi.l #'X68S',0.w(a1)>,ne,<cmpi.l #'CSI1',4(a1)>,ne,next_device ;装置初期化されていない
;$0800-$0FFFを(a2)-(a2+$07FF)に読み込む
moveq.l #$0800/256,d2
moveq.l #$0800/256,d3
lsr.l d5,d2
lsr.l d5,d3
movea.l a2,a1
SCSI _S_READ
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
goto <cmpi.l #'X68K',(a1)>,ne,next_device ;パーティションテーブルがない。装置初期化されていない
;SCSI起動のときは起動したSCSI-IDの自動起動のパーティションまでの自動起動または使用可能なパーティションの数を数える
;SCSI起動でないときはすべてのSCSI-IDの自動起動または使用可能なパーティションの数を数える
swap.w d2 ;(組み込むSCSI-ID<<16)|パーティションの数
if <cmp.b d7,d4>,ls ;(現在のSCSI-ID)-(起動したSCSI-ID)
;SCSI起動のときは組み込むSCSI-IDが起動したSCSI-ID以下。SCSI起動でないときはすべて
bsr count_partition ;自動起動または起動可能なパーティションを数える
add.w d3,d2 ;パーティションの数を加算
endif
swap.w d2 ;(パーティションの数<<16)|組み込むSCSI-ID
move.l d2,d6 ;(パーティションの数<<16)|組み込むSCSI-ID
;(a2+$0400)-(a2+$07FF)を(a2)-(a2+$03FF)にコピーする
movea.l a2,a1
move.w #$0400/4-1,d0
for d0
move.l $0400(a1),(a1)+
next
;$1000-$3FFFを(a2+$0400)-(a2+$33FF)に読み込む
moveq.l #$1000/256,d2
moveq.l #$3000/256,d3
lsr.l d5,d2
lsr.l d5,d3
lea.l $0400(a2),a1
SCSI _S_READ
move.l d6,d2 ;(パーティションの数<<16)|組み込むSCSI-ID
goto <tst.l d0>,ne,next_device ;READで失敗
movea.l a2,a1
.endif
;デバイスヘッダをリロケートする
do
gotoor <cmpi.l #($01.shl.24)|'SCH',14(a1)>,ne,<cmpi.l #'DISK',18(a1)>,ne,next_device ;SCSIデバイスドライバがない
move.l a1,d0
add.l d0,6(a1) ;ストラテジハンドルをリロケートする
add.l d0,10(a1) ;インタラプトハンドルをリロケートする
move.l (a1),d0 ;ネクストデバイスドライバハンドル
break <cmp.l #-1,d0>,eq ;最後のデバイスドライバ
add.l a1,d0 ;ネクストデバイスドライバハンドルをリロケートする
move.l d0,(a1)
movea.l d0,a1
while t
swap.w d2 ;(組み込むSCSI-ID<<16)|パーティションの数
move.b d2,22(a1) ;最後のデバイスドライバにパーティションの数を設定する
swap.w d2 ;(パーティションの数<<16)|組み込むSCSI-ID
.if SCSI_BIOS_LEVEL<=3
pop_test
addq.w #1,d2 ;次の組み込むSCSI-ID
rts
;次のSCSI-IDへ
next_device:
addq.w #1,d2 ;次の組み込むSCSI-ID
goto install_device
install_finish:
pop
moveq.l #-1,d2
rts
.else
bclr.b d2,BIOS_SCSI_UNBOOTABLE.w ;このSCSI-IDは起動可能
addq.w #1,d2 ;次の組み込むSCSI-ID
device_installer_end:
pop
rts
install_finish:
moveq.l #-1,d2
goto device_installer_end
.endif
.if SCSI_BIOS_LEVEL<=3
;----------------------------------------------------------------
;自動起動または使用可能なパーティションを数える
;<a1.l:パーティションテーブルの先頭
;>d3.w:パーティションの数
count_partition_1:
push d2/a1
moveq.l #15-1,d2
moveq.l #0,d3
for d2
lea.l 16(a1),a1
continue <tst.b (a1)>,eq ;パーティションがない
continue <cmpi.l #'Huma',(a1)>,ne ;Human68kのパーティションではない
continue <cmpi.l #'n68k',4(a1)>,ne ;Human68kのパーティションではない
move.b 8(a1),d0 ;0=自動起動,1=使用不可,2=使用可能
continue <btst.l #0,d0>,ne ;使用不可
addq.w #1,d3 ;自動起動または使用可能
next
pop
rts
;----------------------------------------------------------------
;自動起動または使用可能なパーティションを数える
; 自動起動のパーティションで終了する
;<a1.l:パーティションテーブルの先頭
;>d3.w:パーティションの数
count_partition_2:
push d2/a1
moveq.l #15-1,d2
moveq.l #0,d3
for d2
lea.l 16(a1),a1
continue <tst.b (a1)>,eq ;パーティションがない
continue <cmpi.l #'Huma',(a1)>,ne ;Human68kのパーティションではない
continue <cmpi.l #'n68k',4(a1)>,ne ;Human68kのパーティションではない
move.b 8(a1),d0 ;0=自動起動,1=使用不可,2=使用可能
continue <btst.l #0,d0>,ne ;使用不可
addq.w #1,d3 ;自動起動または使用可能
break <tst.b d0>,eq ;自動起動
next
pop
rts
.else
;----------------------------------------------------------------
;自動起動または使用可能なパーティションを数える
; 起動したSCSI-IDのときは自動起動のパーティションで終了する
;<ccr:(現在のSCSI-ID)-(起動したSCSI-ID)
;<a1.l:パーティションテーブルの先頭
;>d3.w:パーティションの数
count_partition:
push d1/d2/a1
seq.b d1 ;-1=(現在のSCSI-ID)==(起動したSCSI-ID)
moveq.l #15-1,d2
moveq.l #0,d3
for d2
lea.l 16(a1),a1
continue <tst.b (a1)>,eq ;パーティションがない
continue <cmpi.l #'Huma',(a1)>,ne ;Human68kのパーティションではない
continue <cmpi.l #'n68k',4(a1)>,ne ;Human68kのパーティションではない
move.b 8(a1),d0 ;0=自動起動,1=使用不可,2=使用可能
continue <btst.l #0,d0>,ne ;使用不可
addq.w #1,d3 ;自動起動または使用可能
continue <tst.b d1>,eq ;起動したSCSI-IDではない
break <tst.b d0>,eq ;起動したSCSI-IDで自動起動のとき終了
next
pop
rts
.endif
.if 10<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;本体と同じSCSI-IDの機器がないか確認する(確認済みならば何もしない)
;>d0.l:本体と同じSCSI-IDの機器がないか。0=ある,-1=ない
check_confliction_2nd:
moveq.l #-1,d0
goto <tst.b BIOS_SCSI_NOT_CONFLICT.w>,ne,check_confliction_end
.endif
;----------------------------------------------------------------
;本体と同じSCSI-IDの機器がないか確認する
;>d0.l:本体と同じSCSI-IDの機器がないか。0=ある,-1=ない
check_confliction_1st:
.if SCSI_BIOS_LEVEL<=3
movem.l d4,-(sp)
.else
move.l d4,-(sp)
st.b BIOS_SCSI_NOT_CONFLICT.w
.endif
move.b SRAM_SCSI_MODE,d4 ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
andi.b #7,d4 ;本体のSCSI-ID
moveq.l #_SCSIDRV,d0
moveq.l #_S_TESTUNIT,d1
trap #15
move.l (sp)+,d4
check_confliction_end:
rts
.if SCSI_BIOS_LEVEL==10
;----------------------------------------------------------------
;ブロック長に応じてブロック番号とブロック数を調整する
;<d2.l:ブロック番号。256バイト/ブロック
;<d3.l:ブロック数。256バイト/ブロック
;<d5.w:ブロック長指数。0=256,1=512,2=1024,3=2048
;>d2.l:ブロック番号
;>d3.l:ブロック数
adjust_block_number:
if <cmpi.w #3,d5>,cs
lsr.l d5,d2
lsr.l d5,d3
rts
endif
lsr.l #2,d2
lsr.l #2,d3
rts
.endif
.endif
;--------------------------------------------------------------------------------
; .include sc03break.s
;--------------------------------------------------------------------------------
.if SCSI_BIOS_LEVEL<>4
;----------------------------------------------------------------
;TRAP#11(BREAK)
; FDとHD関連のIOCSコール($40~$4F,$F5)の処理中でなければシッピングを行う
;<d0.b:bit0:0=BREAK(CTRL+C),1=SHIFT+BREAK(CTRL+S)
trap_11_break:
push d0-d7/a0-a6
if <btst.l #0,d0>,eq ;BREAK。SHIFT+BREAKではない
move.w (BIOS_IOCS_NUMBER)abs,d0 ;実行中のIOCSコールの番号。-1=なし
goto <cmp.w #$0040,d0>,cs,do_eject_all
ifand <cmp.w #$0050,d0>,cc,<cmp.w #_SCSIDRV,d0>,ne
do_eject_all:
bsr eject_all ;シッピングする
endif
endif
pop
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;SASIハードディスク内蔵機にSCSIボードを取り付けるとBREAKキーでSASIハードディスクをシッピングする機能が失われる
;X68000 PRO[HD]の取扱説明書に「コンピュータ本体の動作中に[BREAK]キーを押したときにも、磁気ヘッドの退避作業を行うことができます」という記述がある
;+++++ BUG +++++
rte
.else
move.l BIOS_SCSI_OLD_TRAP11.w,-(sp) ;TRAP#11(BREAK)の元のベクタ
rts
.endif
.endif
;--------------------------------------------------------------------------------
; .include sc04eject.s
;--------------------------------------------------------------------------------
.if SCSI_BIOS_LEVEL<>4
;----------------------------------------------------------------
;シッピングする
eject_all:
move.w #$8000,d1
do
bsr iocs_4F_B_EJECT ;IOCSコール$4F _B_EJECT
add.w #$0100,d1
while <cmp.w #$9000,d1>,cs
rts
.endif
;--------------------------------------------------------------------------------
; .include sc05iocs1.s
;--------------------------------------------------------------------------------
;----------------------------------------------------------------
;IOCSコール$F5 _SCSIDRV
;<d1.l:SCSIコール番号
iocs_F5_SCSIDRV:
push d1/dLEN/aBUF/a2/aSPC
.if SCSI_BIOS_LEVEL<=4
goto <cmp.l #$00000010,d1>,cs,scsi_00_0F ;SCSIコール$00~$0F
goto <cmp.l #$00000020,d1>,cs,scsi_10_1F ;SCSIコール$10~$1F
goto <cmp.l #$00000040,d1>,cs,scsi_20_3F ;SCSIコール$20~$3F
;+++++ BUG +++++
;SCSIコール$40以上を指定するとSCSIコール$00~$0Fのジャンプテーブルから外れて暴走する
goto <cmp.l #$00000020,d1>,cs,scsi_10_1F
;本来は
; goto <cmp.l #$00000050,d1>,cs,scsi_40_4F ;SCSIコール$40~$4F
; goto scsi_10_1F ;SCSIコール$50~
;+++++ BUG +++++
.else
moveq.l #$10,d0
goto <cmp.l d0,d1>,cs,scsi_00_0F ;SCSIコール$00~$0F
add.l d0,d0
goto <cmp.l d0,d1>,cs,scsi_10_1F ;SCSIコール$10~$1F
add.l d0,d0
goto <cmp.l d0,d1>,cs,scsi_20_3F ;SCSIコール$20~$3F
moveq.l #$50,d0
goto <cmp.l d0,d1>,cs,scsi_40_4F ;SCSIコール$40~$4F
goto scsi_10_1F ;SCSIコール$50~
.endif
;SCSIコール$00~$0F
scsi_00_0F:
lea.l jump_00_0F(pc),a2 ;SCSIコール$00~$0Fのジャンプテーブル
goto scsi_go
;SCSIコール$20~$3F
scsi_20_3F:
.if SCSI_BIOS_LEVEL<=4
sub.l #$00000020,d1
.else
moveq.l #$20,d0
sub.l d0,d1
.endif
lea.l jump_20_3F(pc),a2 ;SCSIコール$20~$3Fのジャンプテーブル
goto scsi_go
;SCSIコール$40~$4F
scsi_40_4F:
.if SCSI_BIOS_LEVEL<=4
sub.l #$00000040,d1
.else
moveq.l #$40,d0
sub.l d0,d1
.endif
lea.l jump_40_4F(pc),a2 ;SCSIコール$40~$4Fのジャンプテーブル
scsi_go:
lsl.l #2,d1
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_IN_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
move.l (a2,d1.w),d1
adda.l d1,a2
jsr (a2)
pop_test
rts
;SCSIコール$10~$1F
;SCSIコール$50~
scsi_10_1F:
moveq.l #-1,d0
pop
rts
;未定義のSCSIコール
scsi_XX_undefined:
moveq.l #-1,d0
rts
;SCSIコール$00~$0Fのジャンプテーブル
jump_00_0F:
.dc.l scsi_00_S_RESET-jump_00_0F ;SCSIコール$00 _S_RESET
.dc.l scsi_01_S_SELECT-jump_00_0F ;SCSIコール$01 _S_SELECT
.dc.l scsi_02_S_SELECTA-jump_00_0F ;SCSIコール$02 _S_SELECTA
.dc.l scsi_03_S_CMDOUT-jump_00_0F ;SCSIコール$03 _S_CMDOUT
.dc.l scsi_04_S_DATAIN-jump_00_0F ;SCSIコール$04 _S_DATAIN
.dc.l scsi_05_S_DATAOUT-jump_00_0F ;SCSIコール$05 _S_DATAOUT
.dc.l scsi_06_S_STSIN-jump_00_0F ;SCSIコール$06 _S_STSIN
.dc.l scsi_07_S_MSGIN-jump_00_0F ;SCSIコール$07 _S_MSGIN
.dc.l scsi_08_S_MSGOUT-jump_00_0F ;SCSIコール$08 _S_MSGOUT
.dc.l scsi_09_S_PHASE-jump_00_0F ;SCSIコール$09 _S_PHASE
.dc.l scsi_0A_S_LEVEL-jump_00_0F ;SCSIコール$0A _S_LEVEL
.dc.l scsi_0B_S_DATAINI-jump_00_0F ;SCSIコール$0B _S_DATAINI
.dc.l scsi_0C_S_DATAOUTI-jump_00_0F ;SCSIコール$0C _S_DATAOUTI
.if SCSI_BIOS_LEVEL<=4
.dc.l scsi_XX_undefined-jump_00_0F ;SCSIコール$0D _S_MSGOUTEXT
.else
.dc.l scsi_0D_S_MSGOUTEXT-jump_00_0F ;SCSIコール$0D _S_MSGOUTEXT
.endif
.dc.l scsi_XX_undefined-jump_00_0F ;SCSIコール$0E
.dc.l scsi_XX_undefined-jump_00_0F ;SCSIコール$0F
;SCSIコール$20~$3Fのジャンプテーブル
jump_20_3F:
.dc.l scsi_20_S_INQUIRY-jump_20_3F ;SCSIコール$20 _S_INQUIRY
.dc.l scsi_21_S_READ-jump_20_3F ;SCSIコール$21 _S_READ
.dc.l scsi_22_S_WRITE-jump_20_3F ;SCSIコール$22 _S_WRITE
.dc.l scsi_23_S_FORMAT-jump_20_3F ;SCSIコール$23 _S_FORMAT
.dc.l scsi_24_S_TESTUNIT-jump_20_3F ;SCSIコール$24 _S_TESTUNIT
.dc.l scsi_25_S_READCAP-jump_20_3F ;SCSIコール$25 _S_READCAP
.dc.l scsi_26_S_READEXT-jump_20_3F ;SCSIコール$26 _S_READEXT
.dc.l scsi_27_S_WRITEEXT-jump_20_3F ;SCSIコール$27 _S_WRITEEXT
.dc.l scsi_28_S_VERIFYEXT-jump_20_3F ;SCSIコール$28 _S_VERIFYEXT
.dc.l scsi_29_S_MODESENSE-jump_20_3F ;SCSIコール$29 _S_MODESENSE
.dc.l scsi_2A_S_MODESELECT-jump_20_3F ;SCSIコール$2A _S_MODESELECT
.dc.l scsi_2B_S_REZEROUNIT-jump_20_3F ;SCSIコール$2B _S_REZEROUNIT
.dc.l scsi_2C_S_REQUEST-jump_20_3F ;SCSIコール$2C _S_REQUEST
.dc.l scsi_2D_S_SEEK-jump_20_3F ;SCSIコール$2D _S_SEEK
.dc.l scsi_2E_S_READI-jump_20_3F ;SCSIコール$2E _S_READI
.dc.l scsi_2F_S_STARTSTOP-jump_20_3F ;SCSIコール$2F _S_STARTSTOP
.dc.l scsi_30_S_SEJECT-jump_20_3F ;SCSIコール$30 _S_SEJECT
.dc.l scsi_31_S_REASSIGN-jump_20_3F ;SCSIコール$31 _S_REASSIGN
.dc.l scsi_32_S_PAMEDIUM-jump_20_3F ;SCSIコール$32 _S_PAMEDIUM
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$33
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$34
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$35
.dc.l scsi_36_S_DSKINI-jump_20_3F ;SCSIコール$36 _S_DSKINI
.dc.l scsi_37_S_FORMATB-jump_20_3F ;SCSIコール$37 _S_FORMATB
.dc.l scsi_38_S_BADFMT-jump_20_3F ;SCSIコール$38 _S_BADFMT
.dc.l scsi_39_S_ASSIGN-jump_20_3F ;SCSIコール$39 _S_ASSIGN
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3A
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3B
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3C
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3D
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3E
.dc.l scsi_XX_undefined-jump_20_3F ;SCSIコール$3F
;SCSIコール$40~$4Fのジャンプテーブル
jump_40_4F:
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$40
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$41
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$42
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$43
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$44
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$45
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$46
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$47
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$48
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$49
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4A
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4B
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4C
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4D
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4E
.dc.l scsi_XX_undefined-jump_40_4F ;SCSIコール$4F
;--------------------------------------------------------------------------------
; .include sc06iocs2.s
;--------------------------------------------------------------------------------
;----------------------------------------------------------------
;SCSIコール$00 _S_RESET SPCの初期化とSCSIバスリセット
scsi_00_S_RESET:
push d1/a1/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
;ハードウェアリセットを開始する
move.b #SPC_SCTL_RD|SPC_SCTL_AE,SPC_SCTL(aSPC) ;アービトレーションフェーズあり(SCSI)
.if 10<=SCSI_BIOS_LEVEL
sf.b BIOS_SCSI_NOT_CONFLICT.w ;SCSI-ID衝突確認。$00=未確認,$FF=確認済み
.endif
;SRAMを初期化する
move.b SRAM_SCSI_MAGIC,d0 ;SCSIマジック。'V'($56)=初期化済み
if <cmpi.b #'V',d0>,ne ;SRAM未初期化
move.b #$31,SYSPORT_SRAM ;SRAM書き込み制御。$31=許可,その他=禁止
.if (SCSI_BIOS_LEVEL<=0)|(10<=SCSI_BIOS_LEVEL)
.if SCSIEXROM
move.b #$0F,SRAM_SCSI_MODE ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
.else
move.b #$07,SRAM_SCSI_MODE ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
.endif
.else
if <cmpa.l #SPC_IN_BASE,aSPC>,eq ;内蔵
move.b #$07,SRAM_SCSI_MODE ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
else ;拡張
move.b #$0F,SRAM_SCSI_MODE ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
endif
.endif
move.b #$00,SRAM_SCSI_SASI_FLAG ;SASIフラグ
move.b #'V',SRAM_SCSI_MAGIC ;SCSIマジック。'V'($56)=初期化済み
move.b #$00,SYSPORT_SRAM ;SRAM書き込み制御。$31=許可,その他=禁止
endif
;SRAM初期化済み
;本体のSCSI-IDを設定する
move.b SRAM_SCSI_MODE,d0 ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
andi.b #7,d0 ;本体のSCSI-ID
move.b d0,SPC_BDID(aSPC)
;SPCのレジスタをクリアする
moveq.l #0,d0
move.b d0,SPC_SCMD(aSPC)
move.b d0,SPC_PCTL(aSPC)
move.b d0,SPC_TCH(aSPC)
move.b d0,SPC_TCM(aSPC)
move.b d0,SPC_TCL(aSPC)
move.b d0,SPC_TEMP(aSPC)
.if 10<=SCSI_BIOS_LEVEL
move.b #$00,SPC_SDGC(aSPC)
move.w #512,BIOS_SCSI_BLOCK_SIZE.w ;SCSI機器のブロックサイズ
.endif
;SPC割り込みを設定する
.if SCSI_BIOS_LEVEL<=4
moveq.l #_B_INTVCS,d0
.if SCSI_BIOS_LEVEL<=0
moveq.l #OFFSET_SPC_IN/4,d1 ;内蔵SPC割り込みベクタ
.else
if <cmpa.l #SPC_IN_BASE,aSPC>,eq ;内蔵
moveq.l #OFFSET_SPC_IN/4,d1 ;内蔵SPC割り込みベクタ
else ;拡張
move.l #OFFSET_SPC_EX/4,d1 ;拡張SPC割り込みベクタ
endif
.endif
lea.l spc_interrupt_routine(pc),a1 ;SPC割り込みルーチン
trap #15
.else
.if SCSIEXROM
moveq.l #OFFSET_SPC_EX/4,d1 ;拡張SPC割り込みベクタ
.else
moveq.l #OFFSET_SPC_IN/4,d1 ;内蔵SPC割り込みベクタ
.endif
lea.l spc_interrupt_routine(pc),a1 ;SPC割り込みルーチン
IOCS _B_INTVCS
.endif
;ハードウェアリセットを終了する
move.b #SPC_SCTL_AE,SPC_SCTL(aSPC) ;アービトレーションフェーズあり(SCSI)
.if SCSI_BIOS_LEVEL<=4
move.b #$00,SPC_SDGC(aSPC)
.endif
.if SCSI_BIOS_LEVEL<=3
move.w d0,-(sp)
.if SCSI_BIOS_LEVEL<=0
move.w #81-1,d0 ;97.2us@10MHz
.else
move.w #129-1,d0 ;154.8us@10MHz
.endif
for d0
next
move.w (sp)+,d0
.endif
.if 4<=SCSI_BIOS_LEVEL
moveq.l #100/50,d0 ;100us
bsr wait_50us ;50us単位のウェイト
.endif
;SCSIバスリセットを開始する
move.b #SPC_SCMD_RO,SPC_SCMD(aSPC)
.if SCSI_BIOS_LEVEL<=3
move.w d0,-(sp)
.if SCSI_BIOS_LEVEL<=0
move.w #201-1,d0 ;241.2us@10MHz
.else
move.w BIOS_MPU_SPEED_ROM.l,d0 ;MPUクロック。X68000は10MHz*250/3=833、X68030は25MHz*500/3=4167。1ms間にdbraの空ループが何回回るか
lsr.w #2,d0 ;250us
.endif
for d0
next
move.w (sp)+,d0
.endif
.if 4<=SCSI_BIOS_LEVEL
moveq.l #250/50,d0 ;250us
bsr wait_50us ;50us単位のウェイト
.endif
;SCSIバスリセットを終了する
move.b #$00,SPC_SCMD(aSPC)
.if SCSI_BIOS_LEVEL<=3
move.w #2000/10,d0 ;2s
for d0
move.w d0,-(sp)
.if SCSI_BIOS_LEVEL<=0
move.w #1000*10,d0 ;10ms
.else
move.w BIOS_MPU_SPEED_ROM.l,d0 ;MPUクロック。X68000は10MHz*250/3=833、X68030は25MHz*500/3=4167。1ms間にdbraの空ループが何回回るか
mulu.w #10,d0 ;10ms
.endif
for d0
next
move.w (sp)+,d0
next
.else
move.l #2000000/50,d0 ;2s
bsr wait_50us ;50us単位のウェイト
.endif
.if 16<=SCSI_BIOS_LEVEL
;SCSI初期化済みフラグをセットする
.if SCSIEXROM
bset.b #1,BIOS_SCSI_INITIALIZED.w
.else
bset.b #0,BIOS_SCSI_INITIALIZED.w
.endif
.endif
pop
rts
;----------------------------------------------------------------
;SPC割り込みルーチン
spc_interrupt_routine:
push d0/d1/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
move.b SPC_INTS(aSPC),d0
move.b d0,SPC_INTS(aSPC) ;INTSをクリア
pop
rte
;----------------------------------------------------------------
;SCSIコール$02 _S_SELECTA
; アービトレーションフェーズとセレクションフェーズ(メッセージアウトフェーズあり)
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:終了コード。0=正常終了,その他=(INTS<<16)|PSNS
scsi_02_S_SELECTA:
.if SCSI_BIOS_LEVEL<=4
ints reg SPC_INTS(aSPC)
push dID/d7/aSPC
.else
aINTS reg a0
ints reg (a0)
push dID/d7/aINTS/aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
.if 10<=SCSI_BIOS_LEVEL
lea.l SPC_INTS(aSPC),aINTS
.endif
move.b #SPC_PCTL_SR_S,SPC_PCTL(aSPC) ;Selectコマンドはセレクション
;現在のコマンドが終了するまで待つ
do
move.b SPC_SSTS(aSPC),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP|SPC_SSTS_SRIN,d0
while ne
.if 10<=SCSI_BIOS_LEVEL
move.b ints,ints ;INTSをクリア
.endif
move.b #SPC_SCMD_CC_SA,SPC_SCMD(aSPC) ;Set ATN
.if SCSI_BIOS_LEVEL<=0
jmp select_common ;ここから_S_SELECT、_S_SELECTA共通
.else
goto select_common ;ここから_S_SELECT、_S_SELECTA共通
.endif
;----------------------------------------------------------------
;SCSIコール$01 _S_SELECT
; アービトレーションフェーズとセレクションフェーズ(メッセージアウトフェーズなし)
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:終了コード。0=正常終了,その他=(INTS<<16)|PSNS
scsi_01_S_SELECT:
push_again
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
.if 10<=SCSI_BIOS_LEVEL
lea.l SPC_INTS(aSPC),aINTS
.endif
move.b #SPC_PCTL_SR_S,SPC_PCTL(aSPC) ;Selectコマンドはセレクション
;現在のコマンドが終了するまで待つ
do
move.b SPC_SSTS(aSPC),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP|SPC_SSTS_SRIN,d0
while ne
;ここから_S_SELECT、_S_SELECTA共通
select_common:
andi.w #7,dID ;ターゲットのSCSI-ID
.if SCSI_BIOS_LEVEL<=4
move.b #1,d0
.else
moveq.l #1,d0
.endif
lsl.b dID,d0
if <btst.b dID,SRAM_SCSI_SASI_FLAG>,eq ;SCSI機器
or.b SPC_BDID(aSPC),d0 ;ターゲットのSCSI-IDと本体のSCSI-IDを合わせる
.if SCSI_BIOS_LEVEL<=4
move.b #SPC_SCTL_AE,SPC_SCTL(aSPC) ;アービトレーションフェーズあり(SCSI)
.else
bset.b #SPC_SCTL_AE_BIT,SPC_SCTL(aSPC) ;アービトレーションフェーズあり(SCSI)
.endif
else ;SASI機器
.if SCSI_BIOS_LEVEL<=4
move.b #$00,SPC_SCTL(aSPC) ;アービトレーションフェーズなし(SASI)
.else
bclr.b #SPC_SCTL_AE_BIT,SPC_SCTL(aSPC) ;アービトレーションフェーズなし(SASI)
.endif
endif
;応答待ち時間とアービトレーション開始遅延時間を設定する
; 応答待ち時間
; (9*65536+196*256+15)*200ns*2=256.006us
; アービトレーション開始遅延時間
; (3+6)*200ns~(3+7)*200ns=1.8us~2us
.if (SCSI_BIOS_LEVEL<=4)|(16<=SCSI_BIOS_LEVEL)
move.b d0,SPC_TEMP(aSPC) ;ターゲットのSCSI-IDと自分のSCSI-IDを合わせたもの
move.w #(9<<8)|196,d0
move.b d0,SPC_TCM(aSPC) ;196
lsr.w #8,d0
move.b d0,SPC_TCH(aSPC) ;9
move.b #3,SPC_TCL(aSPC) ;3
.else
swap.w d0 ;mask<<16
move.w #(9<<8)|196,d0 ;(mask<<16)|(9<<8)|196
lsl.l #8,d0 ;(mask<<24)|(9<<16)|(196<<8)
move.b #3,d0 ;(mask<<24)|(9<<16)|(196<<8)|3
movep.l d0,SPC_TEMP(aSPC) ;ターゲットのSCSI-IDと自分のSCSI-IDを合わせたもの
;9
;196
;3
.endif
move.b ints,ints ;INTSをクリア
;セレクション開始
move.b #SPC_SCMD_CC_SL,SPC_SCMD(aSPC)
.if SCSI_BIOS_LEVEL<=3
move.w d0,-(sp)
.if SCSI_BIOS_LEVEL<=0
move.w #13-1,d0 ;15.6us@10MHz
.else
move.w #25-1,d0 ;30us@10MHz
.endif
for d0
next
move.w (sp)+,d0
.endif
.if 4<=SCSI_BIOS_LEVEL
moveq.l #50/50,d0 ;50us
bsr wait_50us ;50us単位のウェイト
.endif
.if SCSI_BIOS_LEVEL<=3
move.b SPC_INTS(aSPC),d0
if eq
move.b SPC_SSTS(aSPC),d0
goto <btst.l #SPC_SSTS_INIT_BIT,d0>,eq,select_common ;イニシエータになっていない。セレクション失敗。アービトレーションからやり直す
endif
.elif SCSI_BIOS_LEVEL==4
;割り込みを待つ
do
move.b ints,d0
break ne ;割り込みあり
;+++++ BUG +++++
;BUSY=0でも止まるようにしたかったようだがbtst.bがmove.bになっている
;SSTSのビット5をテストするつもりでSSTSに5を書き込んでいる
;常にneなのでBUSY=0では止まらない
;ループの出口がもう1つあるので無限ループにならずに済んでいる
move.b #SPC_SSTS_BUSY_BIT,SPC_SSTS(aSPC)
;+++++ BUG +++++
while ne
.else
;BUSY=0または割り込みを待つ
do
move.b ints,d0
break ne ;割り込みあり
redo <btst.b #SPC_SSTS_BUSY_BIT,SPC_SSTS(aSPC)>,ne
goto <tst.b SPC_SSTS(aSPC)>,pl,select_common ;SPC_SSTS_INIT_BIT
;BUSY=0だがイニシエータになっていない。セレクション失敗。アービトレーションからやり直す
while f
.endif
;割り込みを待つ
do
.if SCSI_BIOS_LEVEL==4
move.b SPC_SSTS(aSPC),d0
goto <btst.l #SPC_SSTS_INIT_BIT,d0>,eq,select_common ;イニシエータになっていない。セレクション失敗。アービトレーションからやり直す
.endif
move.b ints,d0
while eq
goto <cmp.b #SPC_INTS_TO,d0>,eq,selection_timeout ;セレクションタイムアウト
.if SCSI_BIOS_LEVEL<=4
move.b d0,ints ;INTSをクリア
.else
move.b ints,ints ;INTSをクリア
.endif
goto <cmp.b #SPC_INTS_CC,d0>,eq,selection_no_error ;コマンド終了。セレクション正常終了
;セレクションエラー終了
selection_error:
swap.w d0
move.b SPC_PSNS(aSPC),d0
;セレクション終了
selection_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
;セレクション正常終了
selection_no_error:
moveq.l #0,d0
.if SCSI_BIOS_LEVEL<=4
pop_test
rts
.else
goto selection_end ;セレクション終了
.endif
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;どこからも参照されていない
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto selection_end ;セレクション終了
.endif
;+++++ BUG +++++
.endif
;セレクションタイムアウト
; セレクション応答待ち監視時間
; ((0<<16)|(2<<8)|88)*200ns*2=240us
selection_timeout:
.if SCSI_BIOS_LEVEL==4
moveq.l #50/50,d0
bsr wait_50us ;50us単位のウェイト
.endif
.if (SCSI_BIOS_LEVEL<=4)|(16<=SCSI_BIOS_LEVEL)
move.b #0,SPC_TEMP(aSPC) ;0
move.l #(0<<16)|(2<<8)|88,d0
move.b d0,SPC_TCL(aSPC) ;88
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC) ;2
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC) ;0
.else
move.l #(0<<16)|(2<<8)|88,d0
movep.l d0,SPC_TEMP(aSPC) ;0
;0
;2
;88
.endif
move.b #SPC_INTS_TO,ints ;タイムアウトをクリア
.if 4<=SCSI_BIOS_LEVEL
moveq.l #100/50,d0 ;100us
bsr wait_50us ;50us単位のウェイト
.endif
;割り込みを待つ
do
move.b ints,d0
while eq
.if SCSI_BIOS_LEVEL<=4
move.b d0,ints ;INTSをクリア
.else
move.b ints,ints ;INTSをクリア
.endif
goto <cmp.b #SPC_INTS_TO,d0>,eq,selection_timeout_2nd ;セレクションタイムアウト(2回目)
goto <cmp.b #SPC_INTS_CC,d0>,eq,selection_no_error ;コマンド終了。セレクション正常終了
;コマンド終了ではない
goto selection_error ;セレクションエラー終了
;セレクションタイムアウト(2回目)
selection_timeout_2nd:
;BUSY=0を待つ
do
btst.b #SPC_SSTS_BUSY_BIT,SPC_SSTS(aSPC)
while ne
move.b ints,ints ;INTSをクリア
.if SCSI_BIOS_LEVEL<=4
goto <btst.b #SPC_SSTS_INIT_BIT,SPC_SSTS(aSPC)>,ne,selection_no_error ;イニシエータ。セレクション正常終了
.else
goto <tst.b SPC_SSTS(aSPC)>,mi,selection_no_error ;SPC_SSTS_INIT_BIT
;イニシエータ。セレクション正常終了
.endif
;イニシエータではない
goto selection_error ;セレクションエラー終了
;----------------------------------------------------------------
;SCSIコール$03 _S_CMDOUT
; コマンドアウトフェーズ
;<dLEN.l:コマンドの長さ。グループ0,1,5は不要。グループ0は6バイト、グループ1は10バイト、グループ5は12バイト
;<a1.l:コマンドのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_03_S_CMDOUT:
push dLEN/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
move.b (a1),d0
andi.b #7<<5,d0
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.b #0.shl.5,d0>,eq,cmdout_group_0 ;グループ0($00-$1F)
.else
goto eq,cmdout_group_0 ;グループ0($00-$1F)
.endif
goto <cmp.b #1.shl.5,d0>,eq,cmdout_group_1 ;グループ1($20-$3F)
goto <cmp.b #5.shl.5,d0>,eq,cmdout_group_5 ;グループ5($A0-$BF)
goto cmdout_go
;グループ0($00-$1F)
cmdout_group_0:
moveq.l #6,dLEN ;グループ0のコマンドは6バイト
goto cmdout_go
;グループ1($20-$3F)
cmdout_group_1:
moveq.l #10,dLEN ;グループ1のコマンドは10バイト
goto cmdout_go
;グループ5($A0-$BF)
cmdout_group_5:
moveq.l #12,dLEN ;グループ5のコマンドは12バイト
cmdout_go:
;REQ=1を待つ
do
.if SCSI_BIOS_LEVEL<=4
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,cmdout_disconnected ;切断
.else
goto <btst.b #SPC_INTS_DC_BIT,SPC_INTS(aSPC)>,ne,cmdout_disconnected ;切断
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
goto <cmpi.b #SPC_CMDOUT_PHASE,d0>,ne,cmdout_error ;コマンドアウトフェーズではない。エラー終了
bsr dataout_cpu ;CPU転送で出力する
swap.w d0
goto ne,cmdout_error ;転送失敗。エラー終了
cmdout_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
;エラー終了
cmdout_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
pop_test
rts
.else
goto cmdout_end
.endif
;切断
cmdout_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto cmdout_end
.endif
;----------------------------------------------------------------
;SCSIコール$0C _S_DATAOUTI
; データアウトフェーズ(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_0C_S_DATAOUTI:
.if SCSI_BIOS_LEVEL<=10
pushm aSPC
.else
push aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
;REQ=1を待つ
do
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,dataouti_disconnected ;切断
.if 10<=SCSI_BIOS_LEVEL
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,dataouti_error
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0 ;SPC_DATAOUT_PHASE
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_DATAOUT_PHASE,d0>,ne,dataouti_error ;データアウトフェーズではない。エラー終了
.else
goto ne,dataouti_error ;データアウトフェーズではない。エラー終了
.endif
bsr dataouti_transfer ;SCSI出力(ソフト転送)
swap.w d0
goto ne,dataouti_error ;転送失敗。エラー終了
dataouti_end:
.if SCSI_BIOS_LEVEL<=4
popm_test
.elif SCSI_BIOS_LEVEL<=10
popm
.else
pop
.endif
rts
;エラー終了
dataouti_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto dataouti_end
.endif
;切断
dataouti_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
popm
rts
.else
goto dataouti_end
.endif
;----------------------------------------------------------------
;SCSIコール$0B _S_DATAINI
; データインフェーズ(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_0B_S_DATAINI:
.if SCSI_BIOS_LEVEL<=10
pushm aSPC
.else
push aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
;REQ=1を待つ
do
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,dataini_disconnected ;切断
.if 10<=SCSI_BIOS_LEVEL
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,dataini_error
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_DATAIN_PHASE,d0>,ne,dataini_error ;データインフェーズではない。エラー終了
.else
goto <cmpi.b #SPC_DATAIN_PHASE,d0>,ne,dataini_error ;データインフェーズではない。エラー終了
.endif
bsr dataini_transfer ;SCSI入力(ソフト転送)
swap.w d0
goto ne,dataini_error ;転送失敗。エラー終了
dataini_end:
.if SCSI_BIOS_LEVEL<=4
popm_test
.elif SCSI_BIOS_LEVEL<=10
popm
.else
pop
.endif
rts
;エラー終了
dataini_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto dataini_end
.endif
;切断
dataini_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
popm
rts
.else
goto dataini_end
.endif
;----------------------------------------------------------------
;SCSIコール$06 _S_STSIN
; ステータスインフェーズ
; ステータスバイト
; $00 --00000- Good
; $02 --00001- Check Condition
; $04 --00010- Condition Met
; $08 --00100- Busy
; $10 --01000- Intermediate
; $14 --01010- Intermediate-Condition Met
; $18 --01100- Reservation Conflict
; $22 --10001- Command Terminated
; $28 --10100- Queue Full
; その他 リザーブ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_06_S_STSIN:
push dLEN/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
;REQ=1を待つ
do
.if SCSI_BIOS_LEVEL<=4
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,stsin_disconnected ;切断
.else
goto <btst.b #SPC_INTS_DC_BIT,SPC_INTS(aSPC)>,ne,stsin_disconnected ;切断
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_STSIN_PHASE,d0>,ne,stsin_error ;ステータスインフェーズではない。エラー終了
.else
goto <cmpi.b #SPC_STSIN_PHASE,d0>,ne,stsin_error ;ステータスインフェーズではない。エラー終了
.endif
;転送する
moveq.l #1,dLEN ;データの長さ
bsr datain_cpu ;CPU転送で入力する
swap.w d0
goto ne,stsin_error ;転送失敗。エラー終了
stsin_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
;エラー終了
stsin_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
pop_test
rts
.else
goto stsin_end
.endif
;切断
stsin_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto stsin_end
.endif
;----------------------------------------------------------------
;SCSIコール$07 _S_MSGIN
; メッセージインフェーズ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_07_S_MSGIN:
push dLEN/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
.if 10<=SCSI_BIOS_LEVEL
moveq.l #1,dLEN ;データの長さ
.endif
;REQ=1を待つ
do
.if SCSI_BIOS_LEVEL<=4
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,msgin_disconnected ;切断
.else
goto <btst.b #SPC_INTS_DC_BIT,SPC_INTS(aSPC)>,ne,msgin_disconnected ;切断
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_MSGIN_PHASE,d0>,ne,msgin_error ;メッセージインフェーズではない。エラー終了
.else
goto <cmpi.b #SPC_MSGIN_PHASE,d0>,ne,msgin_error ;メッセージインフェーズではない。エラー終了
.endif
;転送する
.if SCSI_BIOS_LEVEL<=4
moveq.l #1,dLEN ;データの長さ
.endif
bsr datain_cpu ;CPU転送で入力する
swap.w d0
goto ne,msgin_error ;転送失敗。エラー終了
msgin_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
;エラー終了
msgin_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
pop_test
rts
.else
goto msgin_end
.endif
;切断
msgin_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto msgin_end
.endif
;----------------------------------------------------------------
;SCSIコール$08 _S_MSGOUT
; メッセージアウトフェーズ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_08_S_MSGOUT:
push dLEN/aSPC
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,aSPC
.else
movea.l spc_base_handle(pc),aSPC
.endif
.if 10<=SCSI_BIOS_LEVEL
moveq.l #1,dLEN ;データの長さ
.endif
;ここから_S_MSGOUT、_S_MSGOUTEXT共通
msgout_common:
;REQ=1を待つ
do
.if SCSI_BIOS_LEVEL<=4
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,msgout_disconnected ;切断
.else
goto <btst.b #SPC_INTS_DC_BIT,SPC_INTS(aSPC)>,ne,msgout_disconnected ;切断
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_MSGOUT_PHASE,d0>,ne,msgout_error ;メッセージアウトフェーズではない。エラー終了
.else
goto <cmpi.b #SPC_MSGOUT_PHASE,d0>,ne,msgout_error ;メッセージアウトフェーズではない。エラー終了
.endif
;転送する
.if SCSI_BIOS_LEVEL<=4
moveq.l #1,dLEN ;データの長さ
.endif
bsr dataouti_transfer ;SCSI出力(ソフト転送)
swap.w d0
goto ne,msgout_error
msgout_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
;エラー終了
msgout_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
pop_test
rts
.else
goto msgout_end
.endif
;切断
msgout_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto msgout_end
.endif
.if 10<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;SCSIコール$0D _S_MSGOUTEXT
; 拡張メッセージアウトフェーズ
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,-1=切断,その他=(INTS<<16)|PSNS
scsi_0D_S_MSGOUTEXT:
push dLEN/aSPC
movea.l spc_base_handle(pc),aSPC ;SPCベースハンドル
move.b 2(aBUF),d0
goto eq,msgoutext_0
subq.b #2,d0
goto cs,msgoutext_1
goto eq,msgoutext_2
subq.b #1,d0
goto eq,msgoutext_2
goto msgout_common ;ここから_S_MSGOUT、_S_MSGOUTEXT共通
msgoutext_0:
moveq.l #5,dLEN
goto msgoutext_go
msgoutext_1:
moveq.l #3,dLEN
goto msgoutext_go
msgoutext_2:
moveq.l #2,dLEN
msgoutext_go:
move.b #1,(aBUF)
move.b dLEN,1(aBUF)
addq.l #2,dLEN
goto msgout_common ;ここから_S_MSGOUT、_S_MSGOUTEXT共通
.endif
;----------------------------------------------------------------
;SCSIコール$09 _S_PHASE
; フェーズセンス
;>d0.l:現在のフェーズ
scsi_09_S_PHASE:
.if SCSI_BIOS_LEVEL<=10
pushm aSPC
.else
push aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,a6
.else
movea.l spc_base_handle(pc),aSPC
.endif
moveq.l #0,d0
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=10
popm
.else
pop
.endif
rts
;----------------------------------------------------------------
;SCSIコール$0A _S_LEVEL
; バージョン
; バージョンが3以下のときFORMAT.XがSCSIハードディスクに書き込んだSCSIデバイスドライバがバージョン4に差し替える
;>d0.l:バージョン
scsi_0A_S_LEVEL:
moveq.l #SCSI_BIOS_LEVEL,d0
rts
.if SCSI_BIOS_LEVEL<=4
;----------------------------------------------------------------
;SCSI出力(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,その他=INTS
dataouti_transfer:
push dLEN/aBUF
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
;イニシエータで転送中を待つ
do
move.b SPC_SSTS(aSPC),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0
break <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq ;ターゲットで転送中?
while <cmp.b #SPC_SSTS_INIT|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,ne
;1バイトずつ転送する
do
break <tst.b SPC_INTS(aSPC)>,ne ;割り込みあり
redo <btst.b #SPC_SSTS_DF_BIT,SPC_SSTS(aSPC)>,ne ;FIFOがフルでなくなるまで待つ
move.b (aBUF)+,SPC_DREG(aSPC)
subq.l #1,dLEN
while ne
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b d0,SPC_INTS(aSPC) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,ne
pop_test
rts
endif
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;SCSI入力(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,その他=INTS
dataini_transfer:
push dLEN/aBUF
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
;イニシエータで転送中を待つ
dataini_wait:
do
move.b SPC_SSTS(aSPC),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0
break <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq ;ターゲットで転送中?
while <cmp.b #SPC_SSTS_INIT|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,ne
;1バイトずつ転送する
dataini_loop:
;+++++ BUG +++++
;Service Requiredに対応していない
; 最後のデータを送信した後、ACKがFalseになるのを待たずにステータスインフェーズに移行してしまうハードディスクがあるらしい
; 最後のデータをFIFOから取り出し終わるまで本体はデータインフェーズなので、
; フェーズの不一致で割り込み要因のService Requiredがセットされる可能性がある
; Service Requiredがセットされると転送が中断してしまい、FIFOに残っていた最後のデータを受け取り損ねる可能性がある
;+++++ BUG +++++
do
;FIFOが空でなくなるまで待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataini_interrupted ;割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;FIFOから1バイト読み込む
move.b SPC_DREG(aSPC),(aBUF)+
subq.l #1,dLEN
while ne
dataini_interrupted:
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b d0,SPC_INTS(aSPC) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,ne
pop_test
rts
endif
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;CPU転送で出力する
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0
dataout_cpu:
push dLEN/aBUF
dataout_cpu_loop:
do
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
dataout_cpu_wait_1:
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;1バイト出力する
move.b (aBUF)+,SPC_TEMP(aSPC)
move.b #SPC_SCMD_CC_SR|SPC_SCMD_IT|SPC_SCMD_PT,SPC_SCMD(aSPC) ;Set ACK
;REQ=0を待つ
dataout_cpu_wait_2:
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,ne
move.b #SPC_SCMD_CC_RR|SPC_SCMD_IT|SPC_SCMD_PT,SPC_SCMD(aSPC) ;Reset ACK
subq.l #1,dLEN
while ne
moveq.l #0,d0
dataout_cpu_end:
pop
rts
;----------------------------------------------------------------
;CPU転送で入力する
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0
datain_cpu:
push dLEN/aBUF
datain_cpu_loop:
do
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
datain_cpu_wait_1:
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
move.b #SPC_SCMD_CC_SR|SPC_SCMD_IT|SPC_SCMD_PT,SPC_SCMD(aSPC) ;Set ACK
;REQ=0を待つ
datain_cpu_wait_2:
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,ne
;1バイト入力する
move.b SPC_TEMP(aSPC),(aBUF)+
move.b #SPC_SCMD_CC_RR|SPC_SCMD_IT|SPC_SCMD_PT,SPC_SCMD(aSPC) ;Reset ACK
subq.l #1,dLEN
while ne
moveq.l #0,d0
pop
rts
.else
;----------------------------------------------------------------
;SCSI出力(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,その他=INTS
dataouti_transfer:
aINTS reg a2
aSSTS reg a3
aDREG reg a4
push d1/d2/dLEN/dID/aBUF/aINTS/aSSTS/aDREG
lea.l SPC_INTS(aSPC),aINTS
lea.l SPC_SSTS(aSPC),aSSTS
lea.l SPC_DREG(aSPC),aDREG
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;長さをセットする
.if SCSI_BIOS_LEVEL<=10
move.l #$00FFFFFF,d0
and.l dLEN,d0
movep.l d0,SPC_TEMP(aSPC)
.else
move.b #0,SPC_TEMP(aSPC)
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
.endif
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
while <tst.b SPC_PSNS(aSPC)>,pl ;SPC_PSNS_REQ_BIT
;転送開始
move.b (aINTS),(aINTS) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
;イニシエータで転送中を待つ
do
move.b (aSSTS),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;ターゲットのときループカウンタのd2を設定せずにループに飛び込んでいる
goto <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq,dataouti_target ;ターゲットで転送中?
;+++++ BUG +++++
.else
break <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq ;ターゲットで転送中?
.endif
while <cmp.b #SPC_SSTS_INIT|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,ne ;イニシエータで転送中を待つ
.if SCSI_BIOS_LEVEL<=10
;イニシエータで転送中
move.l dLEN,d0
lsr.l #3,d0 ;長さ/8
goto eq,dataouti_less_than_8 ;8バイト未満
;8バイト以上
;<d0.l:長さ/8
move.l d0,d2
dataouti_target:
;8バイトずつ転送する
do
;FIFOが空になるまで待つ
do
goto <tst.b (aINTS)>,ne,dataouti_finish ;割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,(aSSTS)>,eq ;FIFOが空になるまで待つ
;FIFOに8バイト書き込む
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l (aBUF)+,d0
move.b d0,d1
rol.l #8,d0
move.b d0,(aDREG)
rol.l #8,d0
move.b d0,(aDREG)
rol.l #8,d0
move.b d0,(aDREG)
move.b d1,(aDREG)
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l (aBUF)+,d0
move.b d0,d1
rol.l #8,d0
move.b d0,(aDREG)
rol.l #8,d0
move.b d0,(aDREG)
rol.l #8,d0
move.b d0,(aDREG)
move.b d1,(aDREG)
subq.l #1,d2
while ne
;8バイト未満
dataouti_less_than_8:
and.w #7,dLEN
beq dataouti_finish
;1バイトずつ転送する
subq.w #1,dLEN
for dLEN
break <tst.b (aINTS)>,ne ;割り込みあり
redo <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,ne ;FIFOがフルでなくなるまで待つ
move.b (aBUF)+,(aDREG)
next
;後始末
dataouti_finish:
do
move.b (aINTS),d0
while eq ;割り込みを待つ
move.b d0,(aINTS) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq
moveq.l #0,d0
endif
;+++++ BUG +++++
;INTSを返すときd0.lの上位バイトにゴミが入る
;+++++ BUG +++++
pop
rts
.else
move.w aBUF,d0
gotoand <lsr.w #1,d0>,cs,<is68000 d0>,eq,dataouti_1byte ;aBUFが奇数かつ68000である。1バイトずつ転送する
;aBUFが偶数または68000でない
;8バイトずつ転送する
while <subq.l #8,dLEN>,hs
goto <tst.b (aINTS)>,ne,dataouti_finish ;割り込みあり
redo <btst.b #SPC_SSTS_DE_BIT,(aSSTS)>,eq ;FIFOが空になるまで待つ
;8バイト転送する。途中でFIFOがフルになっていないか確認しない
.rept 2
move.l (aBUF)+,d0
.rept 4
rol.l #8,d0
move.b d0,(aDREG)
.endm
.endm
endwhile
addq.l #8,dLEN
;1バイトずつ転送する
dataouti_1byte:
while <subq.l #1,dLEN>,hs
goto <tst.b (aINTS)>,ne,dataouti_finish ;割り込みあり
redo <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,ne ;FIFOがフルでなくなるまで待つ
;1バイト転送する
move.b (aBUF)+,(aDREG)
endwhile
;後始末
dataouti_finish:
moveq.l #0,d0
do
move.b (aINTS),d0
while eq ;割り込みを待つ
move.b d0,(aINTS) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq ;Command Complete
moveq.l #0,d0
endif
pop
rts
.endif
;----------------------------------------------------------------
;SCSI入力(ソフト転送)
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0=正常終了,その他=INTS
dataini_transfer:
aINTS reg a2
aSSTS reg a3
aDREG reg a4
push d1/d2/dLEN/aBUF/aINTS/aSSTS/aDREG
lea.l SPC_INTS(aSPC),aINTS
lea.l SPC_SSTS(aSPC),aSSTS
lea.l SPC_DREG(aSPC),aDREG
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
.if SCSI_BIOS_LEVEL<=10
move.l #$00FFFFFF,d0
and.l dLEN,d0
movep.l d0,SPC_TEMP(aSPC)
.else
move.b #0,SPC_TEMP(aSPC)
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
.endif
;転送開始
move.b (aINTS),(aINTS) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
;イニシエータで転送中を待つ
do
move.b (aSSTS),d0
andi.b #SPC_SSTS_INIT|SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;ターゲットのときループカウンタのd2を設定せずにループに飛び込んでいる
goto <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq,dataini_target ;ターゲットで転送中?
;+++++ BUG +++++
.else
break <cmp.b #SPC_SSTS_TARG|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,eq ;ターゲットで転送中?
.endif
while <cmp.b #SPC_SSTS_INIT|SPC_SSTS_BUSY|SPC_SSTS_TRIP,d0>,ne ;イニシエータで転送中を待つ
.if SCSI_BIOS_LEVEL<=10
;イニシエータで転送中
goto <tst.b SRAM_SCSI_MODE>,mi,dataini_block_transfer ;SCSI設定。ブロック|タイプ無視|バースト|ソフト|拡張|本体###
;ブロック転送
;バイト転送
dataini_byte_transfer:
move.l dLEN,d0
lsr.l #3,d0 ;長さ/8
goto eq,dataini_less_than_8 ;8バイト未満
;8バイト以上
;<d0.l:長さ/8
move.l d0,d2
dataini_target:
;8バイトずつ転送する
do
;FIFOがフルになるまで待つ
do
goto <tst.b (aINTS)>,ne,dataini_finish ;割り込みあり
while <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,eq
;FIFOから8バイト読み込む
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
subq.l #1,d2
while ne
;8バイト未満
dataini_less_than_8:
and.w #7,dLEN
goto eq,dataini_finish
;1バイトずつ転送する
;+++++ BUG +++++
;Service Requiredに対応していない
; 最後のデータを送信した後、ACKがFalseになるのを待たずにステータスインフェーズに移行してしまうハードディスクがあるらしい
; 最後のデータをFIFOから取り出し終わるまで本体はデータインフェーズなので、
; フェーズの不一致で割り込み要因のService Requiredがセットされる可能性がある
; Service Requiredがセットされると転送が中断してしまい、FIFOに残っていた最後のデータを受け取り損ねる可能性がある
;+++++ BUG +++++
subq.w #1,dLEN
for dLEN
goto <tst.b (aINTS)>,ne,dataini_finish ;割り込みあり
redo <btst.b #SPC_SSTS_DE_BIT,(aSSTS)>,ne ;FIFOが空
move.b (aDREG),(aBUF)+ ;FIFOから1バイト読み込む
next
;後始末
dataini_finish:
do
move.b (aINTS),d0
while eq ;割り込みを待つ
move.b d0,(aINTS) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq
moveq.l #0,d0
endif
;+++++ BUG +++++
;INTSを返すときd0.lの上位バイトにゴミが入る
;+++++ BUG +++++
pop
rts
;ブロック転送
dataini_block_transfer:
moveq.l #0,d2
move.w BIOS_SCSI_BLOCK_SIZE.w,d2 ;SCSI機器のブロックサイズ
goto <cmp.l d2,dLEN>,cs,dataini_byte_transfer ;ブロックサイズ未満。バイト転送
divu.w d2,dLEN ;端数*$10000+ブロック数
lsr.l #4,d2 ;ブロックサイズ/16
;1ブロックずつ転送する
subq.l #1,d2 ;ブロックサイズ/16-1
do
;FIFOがフルになるまで待つ
do
goto <tst.b (aINTS)>,ne,dataini_finish ;割り込みあり
while <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,eq
;FIFOから1ブロック読み込む。途中でFIFOが空になっていないか確認しない
move.w d2,d1
for d1
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
lsl.l #8,d0
move.b (aDREG),d0
;+++++ BUG +++++
;68000でバッファのアドレスが奇数のときアドレスエラーが発生する
;+++++ BUG +++++
move.l d0,(aBUF)+
next
subq.w #1,dLEN
while ne
swap.w dLEN ;0*$10000+端数
goto dataini_byte_transfer ;バイト転送
.else
move.w aBUF,d0
gotoand <lsr.w #1,d0>,cs,<is68000 d0>,eq,dataini_1byte ;aBUFが奇数かつ68000である。1バイトずつ転送する
;aBUFが偶数または68000でない
goto <tst.b SRAM_SCSI_MODE>,pl,dataini_8bytes ;SRAM_SCSI_BLOCK_BIT。ブロック転送しない。8バイトずつ転送する
;ブロック転送する
moveq.l #0,d2
move.w BIOS_SCSI_BLOCK_SIZE.w,d2 ;SCSI機器のブロックサイズ。0でなく16で割り切れること
while <sub.l d2,dLEN>,hs
move.b (aINTS),d0
if ne ;割り込みあり
add.l d2,dLEN
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,dataini_1byte ;Service RequiredのときFIFOが空になるまで1バイトずつ転送する
goto dataini_finish ;それ以外は中止
endif
redo <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,eq ;FIFOがフルになるまで待つ
;1ブロック転送する。途中でFIFOが空になっていないか確認しない
move.w d2,d1
lsr.w #4,d1
subq.w #1,d1 ;ブロックサイズ/16-1
for d1
;16バイト転送する
.rept 4
move.b (aDREG),d0
lsl.w #8,d0
move.b (aDREG),d0
swap.w d0
move.b (aDREG),d0
lsl.w #8,d0
move.b (aDREG),d0
move.l d0,(aBUF)+
.endm
next
endwhile
add.l d2,dLEN
;8バイトずつ転送する
dataini_8bytes:
while <subq.l #8,dLEN>,hs
move.b (aINTS),d0
if ne ;割り込みあり
addq.l #8,dLEN
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,dataini_1byte ;Service RequiredのときFIFOが空になるまで1バイトずつ転送する
goto dataini_finish ;それ以外は中止
endif
redo <btst.b #SPC_SSTS_DF_BIT,(aSSTS)>,eq ;FIFOがフルになるまで待つ
;8バイト転送する。途中でFIFOが空になっていないか確認しない
.rept 2
move.b (aDREG),d0
lsl.w #8,d0
move.b (aDREG),d0
swap.w d0
move.b (aDREG),d0
lsl.w #8,d0
move.b (aDREG),d0
move.l d0,(aBUF)+
.endm
endwhile
addq.l #8,dLEN
;1バイトずつ転送する
dataini_1byte:
while <subq.l #1,dLEN>,hs
move.b (aINTS),d0
if ne ;割り込みあり
ifor <btst.l #SPC_INTS_SR_BIT,d0>,eq,<btst.b #SPC_SSTS_DE_BIT,(aSSTS)>,ne ;Service RequiredでないまたはFIFOが空のとき
addq.l #1,dLEN
goto dataini_finish
endif
;Service RequiredかつFIFOが空でないとき割り込みを無視する
endif
redo <btst.b #SPC_SSTS_DE_BIT,(aSSTS)>,ne ;FIFOが空でなくなるまで待つ
;1バイト転送する
move.b (aDREG),(aBUF)+
endwhile
addq.l #1,dLEN
;後始末
dataini_finish:
moveq.l #0,d0
do
move.b (aINTS),d0
while eq ;割り込みを待つ
move.b d0,(aINTS) ;INTSをクリア
moveq.l #.notb.(SPC_INTS_CC|SPC_INTS_SR),d1
and.b d0,d1
ifand <>,eq,<tst.l dLEN>,eq ;Command CompleteまたはService Requiredで最後まで転送した
moveq.l #0,d0
endif
pop
rts
.endif
;----------------------------------------------------------------
;CPU転送で出力する
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0
dataout_cpu:
aPSNS reg a2
aSCMD reg a3
push d1/d2/dLEN/aBUF/aPSNS/aSCMD
lea.l SPC_PSNS(aSPC),aPSNS
lea.l SPC_SCMD(aSPC),aSCMD
moveq.l #SPC_SCMD_CC_SR|SPC_SCMD_IT|SPC_SCMD_PT,d1 ;Set ACK
moveq.l #SPC_SCMD_CC_RR|SPC_SCMD_IT|SPC_SCMD_PT,d2 ;Reset ACK
do
;フェーズをセットする
move.b (aPSNS),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
while <tst.b (aPSNS)>,pl ;SPC_PSNS_REQ_BIT
;1バイト出力する
move.b (aBUF)+,SPC_TEMP(aSPC)
move.b d1,(aSCMD) ;Set ACK
;REQ=0を待つ
do
while <tst.b (aPSNS)>,mi ;SPC_PSNS_REQ_BIT
move.b d2,(aSCMD) ;Reset ACK
subq.l #1,dLEN
while ne
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;CPU転送で入力する
;<dLEN.l:データの長さ
;<a1.l:バッファのアドレス
;>d0.l:0
datain_cpu:
aPSNS reg a2
aSCMD reg a3
push d1/d2/dLEN/aBUF/aPSNS/aSCMD
lea.l SPC_PSNS(aSPC),aPSNS
lea.l SPC_SCMD(aSPC),aSCMD
moveq.l #SPC_SCMD_CC_SR|SPC_SCMD_IT|SPC_SCMD_PT,d1 ;Set ACK
moveq.l #SPC_SCMD_CC_RR|SPC_SCMD_IT|SPC_SCMD_PT,d2 ;Reset ACK
do
;フェーズをセットする
move.b (aPSNS),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
while <tst.b (aPSNS)>,pl ;SPC_PSNS_REQ_BIT
move.b d1,(aSCMD) ;Set ACK
;REQ=0を待つ
do
while <tst.b (aPSNS)>,mi ;SPC_PSNS_REQ_BIT
;1バイト入力する
move.b SPC_TEMP(aSPC),(aBUF)+
move.b d2,(aSCMD) ;Reset ACK
subq.l #1,dLEN
while ne
moveq.l #0,d0
pop
rts
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Test Unit Readyコマンド
test_unit_ready_command:
.dc.b $00 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$24 _S_TESTUNIT
; 動作テスト
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_24_S_TESTUNIT:
link.w a5,#-16
push d1/dLEN/d6/a1/a2/a3
.if SCSI_BIOS_LEVEL<=0
lea.l test_unit_ready_command,a2 ;Test Unit Readyコマンド
.else
lea.l test_unit_ready_command(pc),a2 ;Test Unit Readyコマンド
.endif
bsr no_dataio_command ;データインフェーズ/データアウトフェーズのない6バイトのコマンド
pop
unlk a5
rts
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Rezero Unitコマンド
rezero_unit_command:
.dc.b $01 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2B _S_REZEROUNIT
; 状態設定
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2B_S_REZEROUNIT:
link.w a5,#-16
push d1/dLEN/d6/a1/a2/a3
.if SCSI_BIOS_LEVEL<=0
lea.l rezero_unit_command,a2 ;Rezero Unitコマンド
.else
lea.l rezero_unit_command(pc),a2 ;Rezero Unitコマンド
.endif
bsr no_dataio_command ;データインフェーズ/データアウトフェーズのない6バイトのコマンド
pop
unlk a5
rts
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Read(6)コマンド
read_6_command_2nd:
.dc.b $08 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2E _S_READI
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<a1.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2E_S_READI:
link.w a5,#-16
push d1/dLEN/d6/a1/a2/a3
movea.l a1,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l read_6_command_2nd,a2 ;Read(6)コマンド
.else
lea.l read_6_command_2nd(pc),a2 ;Read(6)コマンド
.endif
lea.l -16(a5),a1
.else
lea.l -16(a5),a1
lea.l read_6_command_2nd(pc),a2 ;Read(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(a1)+
next
.if SCSI_BIOS_LEVEL<=4
move.l d2,d6
lea.l -16(a5),a1
move.b d6,3(a1) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(a1) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(a1) ;ブロック番号(上位)
.else
lea.l -16(a5),a1
move.l d2,d6
and.l #$00FFFFFF,d6
or.l d6,(a1) ;ブロック番号
.endif
move.b dLEN,4(a1) ;ブロック数
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
goto <tst.l d0>,ne,readcap_error
;データインフェーズ
lsl.l #8,dLEN
.if SCSI_BIOS_LEVEL<=10
lsl.l d5,dLEN
.else
;ブロック長指数が4以上のとき3と見なす
moveq.l #3,d0
if <cmp.l d0,d5>,lo
move.l d5,d0
endif
lsl.l d0,dLEN
.endif
movea.l a3,a1
.if SCSI_BIOS_LEVEL<=0
bsr scsi_0B_S_DATAINI ;SCSIコール$0B _S_DATAINI
.else
bsr scsi_04_S_DATAIN ;SCSIコール$04 _S_DATAIN
.endif
;ステータスインフェーズとメッセージインフェーズ
goto <cmpi.l #-1,d0>,eq,readcap_error
.if 3<=SCSI_BIOS_LEVEL
if <cmpi.l #-2,d0>,ne
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
readi_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
unlk a5
rts
endif
.endif
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
.if 3<=SCSI_BIOS_LEVEL
if <tst.l d0>,eq
moveq.l #-2,d0
endif
.endif
pop
unlk a5
rts
.else
goto <tst.l d0>,ne,readi_end
moveq.l #-2,d0
goto readi_end
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Read Capacityコマンド
read_capacity_command:
.dc.b $25 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 Reserved
.dc.b $00 ;8 Reserved#######|PMI
.dc.b $00 ;9 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$25 _S_READCAP
; 容量確認
;<dID.l:(LUN<<16)|SCSI-ID
;<a1.l:バッファのアドレス
; 0 論理ブロックアドレス(上位)
; 1 :
; 2 :
; 3 論理ブロックアドレス(下位)
; 4 ブロック長(上位)
; 5 :
; 6 :
; 7 ブロック長(下位)
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_25_S_READCAP:
link.w a5,#-16
push d1/dLEN/d6/a1/a2/a3
movea.l a1,a3
;コマンドを作る
lea.l -16(a5),a1
.if SCSI_BIOS_LEVEL<=0
lea.l read_capacity_command,a2 ;Read Capacityコマンド
.else
lea.l read_capacity_command(pc),a2 ;Read Capacityコマンド
.endif
moveq.l #10-1,d1
for d1
move.b (a2)+,(a1)+
next
;セレクションフェーズとコマンドアウトフェーズ
lea.l -16(a5),a1
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
goto <tst.l d0>,ne,readcap_error
;データインフェーズ
movea.l a3,a1
moveq.l #8,dLEN ;データの長さ
bsr scsi_0B_S_DATAINI ;SCSIコール$0B _S_DATAINI
goto <cmpi.l #-1,d0>,eq,readcap_error
;ステータスインフェーズとメッセージインフェーズ
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
readcap_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
unlk a5
rts
readcap_error:
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
pop
unlk a5
rts
.else
goto readcap_end
.endif
;----------------------------------------------------------------
;セレクションフェーズとコマンドアウトフェーズ
;<dID.l:(LUN<<16)|SCSI-ID
;<a1.l:コマンド
;>d0.l:0=成功,-1=失敗
select_and_cmdout:
push d1/dID
;セレクションフェーズ
move.w #2-1,d1
for d1
bsr scsi_01_S_SELECT ;SCSIコール$01 _S_SELECT
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,eq,select_and_cmdout_cmdout
next
goto select_and_cmdout_error
.else
next <tst.l d0>,ne
goto ne,select_and_cmdout_error
.endif
;コマンドアウトフェーズ
select_and_cmdout_cmdout:
swap.w dID
lsl.b #5,dID ;LUN<<5
or.b dID,1(a1) ;LUN
bsr scsi_03_S_CMDOUT ;SCSIコール$03 _S_CMDOUT
goto <tst.l d0>,ne,select_and_cmdout_error
moveq.l #0,d0 ;成功
select_and_cmdout_end:
.if SCSI_BIOS_LEVEL<=4
pop_test
.else
pop
.endif
rts
select_and_cmdout_error:
moveq.l #-1,d0 ;失敗
.if SCSI_BIOS_LEVEL<=4
pop
rts
.else
goto select_and_cmdout_end
.endif
;----------------------------------------------------------------
;データインフェーズ/データアウトフェーズのない6バイトのコマンド
;<a2.l:コマンドのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
no_dataio_command:
lea.l -16(a5),a1
moveq.l #6-1,d1
for d1
move.b (a2)+,(a1)+
next
lea.l -16(a5),a1
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
goto <tst.l d0>,ne,stsin_and_msgin_error
;----------------------------------------------------------------
;ステータスインフェーズとメッセージインフェーズ
;>d0.l:(MSGIN<<16)|STSIN
stsin_and_msgin:
lea.l -1(a5),a1
bsr scsi_06_S_STSIN ;SCSIコール$06 _S_STSIN
goto <tst.l d0>,ne,stsin_and_msgin_error
lea.l -2(a5),a1
bsr scsi_07_S_MSGIN ;SCSIコール$07 _S_MSGIN
goto <tst.l d0>,ne,stsin_and_msgin_error
move.b -2(a5),d0 ;MSGIN
swap.w d0
move.b -1(a5),d0 ;(MSGIN<<16)|STSIN
rts
stsin_and_msgin_error:
moveq.l #-1,d0
rts
.if 4<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;50us単位のウェイト
;<d0.l:時間(50us単位)
wait_50us:
aTCDR reg a0
push d0/d1/d2/aTCDR
lea.l MFP_TCDR,aTCDR
moveq.l #0,d1
move.b (aTCDR),d1
move.b (aTCDR),d1
do
moveq.l #0,d2
move.b (aTCDR),d2
redo <cmp.b (aTCDR),d2>,cs
sub.w d2,d1
if cs
add.w #200,d1
endif
exg.l d1,d2
sub.l d2,d0
while hi
pop
rts
.endif
;--------------------------------------------------------------------------------
; .include sc07iocs3.s
;--------------------------------------------------------------------------------
;----------------------------------------------------------------
;SCSIコール$05 _S_DATAOUT データアウトフェーズ
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_05_S_DATAOUT:
.if SCSI_BIOS_LEVEL<=10
pushm aSPC
.else
push aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,a6
.else
movea.l spc_base_handle(pc),aSPC
.endif
;REQ=1を待つ
dataout_wait:
do
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,dataout_disconnected ;切断
.if 10<=SCSI_BIOS_LEVEL
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,dataout_error
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0 ;SPC_DATAOUT_PHASE
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_DATAOUT_PHASE,d0>,ne,dataout_error ;データアウトフェーズではない。エラー終了
.else
goto ne,dataout_error ;データアウトフェーズではない。エラー終了
.endif
;転送開始
bsr dataout_transfer ;SCSI出力(DMA転送)
swap.w d0
if eq
dataout_end:
.if SCSI_BIOS_LEVEL<=4
popm_test
.elif SCSI_BIOS_LEVEL<=10
popm
.else
pop
.endif
rts
endif
.if 3<=SCSI_BIOS_LEVEL
if <tst.w d0>,ne
swap.w d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto dataout_end
.endif
endif
.endif
;エラー終了
dataout_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto dataout_end
.endif
;切断
dataout_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
popm
rts
.else
goto dataout_end
.endif
;----------------------------------------------------------------
;SCSIコール$04 _S_DATAIN
; データインフェーズ
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_04_S_DATAIN:
.if SCSI_BIOS_LEVEL<=10
pushm aSPC
.else
push aSPC
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l SPC_BASE,a6
.else
movea.l spc_base_handle(pc),aSPC
.endif
;REQ=1を待つ
do
move.b SPC_INTS(aSPC),d0
goto <btst.l #SPC_INTS_DC_BIT,d0>,ne,datain_disconnected ;切断
.if 10<=SCSI_BIOS_LEVEL
goto <btst.l #SPC_INTS_SR_BIT,d0>,ne,datain_error
.endif
move.b SPC_PSNS(aSPC),d0 ;SPC_PSNS_REQ_BIT
.if SCSI_BIOS_LEVEL<=4
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
.else
while pl
.endif
;フェーズを確認する
andi.b #SPC_PHASE_MASK,d0
.if SCSI_BIOS_LEVEL<=4
;+++++ BUG +++++
;余分な命令
andi.b #SPC_PHASE_MASK,d0
;+++++ BUG +++++
.endif
.if SCSI_BIOS_LEVEL<=4
goto <cmp.b #SPC_DATAIN_PHASE,d0>,ne,datain_error ;データインフェーズではない。エラー終了
.else
goto <cmpi.b #SPC_DATAIN_PHASE,d0>,ne,datain_error ;データインフェーズではない。エラー終了
.endif
;転送開始
bsr datain_transfer ;SCSI入力(DMA転送)
swap.w d0
if eq
datain_end:
.if SCSI_BIOS_LEVEL<=4
popm_test
.elif SCSI_BIOS_LEVEL<=10
popm
.else
pop
.endif
rts
endif
.if 3<=SCSI_BIOS_LEVEL
goto <tst.w d0>,eq,datain_error
swap.w d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto datain_end
.endif
.endif
;エラー終了
datain_error:
move.b SPC_PSNS(aSPC),d0
.if SCSI_BIOS_LEVEL<=4
popm_test
rts
.else
goto datain_end
.endif
;切断
datain_disconnected:
bsr scsi_00_S_RESET ;SCSIコール$00 _S_RESET
moveq.l #-1,d0
.if SCSI_BIOS_LEVEL<=4
popm
rts
.else
goto datain_end
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Inquiryコマンド
inquiry_command:
.dc.b $12 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|EVPD
.dc.b $00 ;2 ページコード
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$20 _S_INQUIRY
; INQUIRYデータの要求
; 最初にアロケーション長に5を指定して追加データ長を得る
; 続いてアロケーション長に5+追加データ長を指定して追加データを得る
;<dLEN.l:アロケーション長
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
; 0 クォリファイア###|デバイスタイプコード#####
; クォリファイア
; 0 ロジカルユニットが接続されている
; 1 ロジカルユニットが接続されていない
; 3 ロジカルユニットが存在しない
; デバイスタイプコード
; $00 ダイレクトアクセスデバイス。磁気ディスクなど
; $01 シーケンシャルアクセスデバイス。磁気テープなど
; $02 プリンタデバイス
; $03 プロセッサデバイス
; $04 ライトワンスデバイス。追記型光ディスクなど
; $05 CD-ROMデバイス
; $06 スキャナデバイス
; $07 光メモリデバイス。イレーザブル光ディスクなど
; $08 メディアチェンジャデバイス。磁気テープライブラリ、光ディスクライブラリなど
; $09 コミュニケーションデバイス
; $84 SHARP MO
; 1 RMB|デバイスタイプ修飾子#######
; RMB
; 0 固定
; 1 可換
; 2 ISOバージョン##|ECMAバージョン###|ANSIバージョン###
; bit7-6 ISOバージョン(通常は0)
; bit5-3 ECMAバージョン(通常は0)
; bit2-0 ANSIバージョン
; 0 未適合
; 1 SCSI-1。ANSI X3.131-1986準拠
; 2 SCSI-2。ANSI X3T9.2/86-109準拠
; 3 AENC|TrmlOP|Reserved##|レスポンスデータ形式####
; 4 追加データ長(なければ0)
; 5~ 追加データ
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_20_S_INQUIRY:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l inquiry_command,a2 ;Inquiryコマンド
.else
lea.l inquiry_command(pc),a2 ;Inquiryコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l inquiry_command(pc),a2 ;Inquiryコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.b dLEN,4(aBUF) ;アロケーション長
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データインフェーズ
movea.l a3,aBUF
bsr scsi_0B_S_DATAINI ;SCSIコール$0B _S_DATAINI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Request Senseコマンド
request_sense_command:
.dc.b $03 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2C _S_REQUEST
; センスデータの要求
;<dLEN.l:アロケーション長
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2C_S_REQUEST:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l request_sense_command,a2 ;Request Senseコマンド
.else
lea.l request_sense_command(pc),a2 ;Request Senseコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l request_sense_command(pc),a2 ;Request Senseコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.b dLEN,4(aBUF) ;アロケーション長
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データインフェーズ
movea.l a3,aBUF
bsr scsi_0B_S_DATAINI ;SCSIコール$0B _S_DATAINI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Mode Sense(6)コマンド
mode_sense_6_command:
.dc.b $1A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|R|DBD|Reserved###
.dc.b $00 ;2 PC##|ページコード######
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$29 _S_MODESENSE
; モードセンス
;<d2.l:(PC<<6)|ページコード
; PC 0 現在
; 1 変更可能ビットマスク
; 2 デフォルト
; 3 保存
; ページコード63はすべてのパラメータページを取得
;<dLEN.l:アロケーション長。4以上
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
; モードパラメータヘッダ
; 0 モードパラメータ長
; 返却できるパラメータリストのバイト数。モードパラメータヘッダを含まない。8の倍数
; 1 メディアタイプ
; 2 デバイス固有パラメータ
; ダイレクトアクセスデバイスのデバイス固有パラメータ
; WP#|Reserved##|DPOFUA|Reserved####
; ビット7が1のとき書き込み禁止
; 3 ブロックディスクリプタ長
; 返却されたパラメータリストのバイト数。モードパラメータヘッダを含まない。8の倍数
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_29_S_MODESENSE:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l mode_sense_6_command,a2 ;Mode Sense(6)コマンド
.else
lea.l mode_sense_6_command(pc),a2 ;Mode Sense(6)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l mode_sense_6_command(pc),a2 ;Mode Sense(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.b dLEN,4(aBUF) ;アロケーション長
.if 3<=SCSI_BIOS_LEVEL
move.b d2,2(aBUF) ;(PC<<6)|ページコード。PC:0=現在,1=変更可能ビットマスク,2=デフォルト,3=保存
.endif
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データインフェーズ
movea.l a3,aBUF
bsr scsi_0B_S_DATAINI ;SCSIコール$0B _S_DATAINI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Mode Select(6)コマンド
mode_select_6_command:
.dc.b $15 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|PF|Reserved###|SP
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 パラメータリスト長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2A _S_MODESELECT
; モードセレクト
;<d2.l:PF<<4|SP
; PF 0 SCSI-1
; 1 SCSI-2
; SP 0 保存しない
; 1 保存する
;<dLEN.l:パラメータリスト長
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2A_S_MODESELECT:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l mode_select_6_command,a2 ;Mode Select(6)コマンド
.else
lea.l mode_select_6_command(pc),a2 ;Mode Select(6)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l mode_select_6_command(pc),a2 ;Mode Select(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.b dLEN,4(aBUF) ;パラメータリスト長
.if 3<=SCSI_BIOS_LEVEL
move.b d2,1(aBUF) ;PF<<4|SP。PF:0=SCSI-1,1=SCSI-2。SP:0=保存しない,1=保存する
.endif
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
movea.l a3,aBUF
bsr scsi_0C_S_DATAOUTI ;SCSIコール$0C _S_DATAOUTI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Reassign Blocksコマンド
reassign_blocks_command:
.dc.b $07 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$31 _S_REASSIGN
; 再配置
;
;ディフェクトリスト
; ヘッダ
; 0 Reserved
; 1 Reserved
; 2 ディフェクトリスト長4*n(上位)
; 3 ディフェクトリスト長4*n(下位)
; ディフェクトディスクリプタ
; 4+4*0+0 不良ブロックの論理ブロックアドレス(上位)
; 4+4*0+1 :
; 4+4*0+2 :
; 4+4*0+3 不良ブロックの論理ブロックアドレス(下位)
; :
; 4+4*(n-1)+0 不良ブロックの論理ブロックアドレス(上位)
; 4+4*(n-1)+1 :
; 4+4*(n-1)+2 :
; 4+4*(n-1)+3 不良ブロックの論理ブロックアドレス(下位)
;
;<dLEN.l:データの長さ
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_31_S_REASSIGN:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l reassign_blocks_command,a2 ;Reassign Blocksコマンド
.else
lea.l reassign_blocks_command(pc),a2 ;Reassign Blocksコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l reassign_blocks_command(pc),a2 ;Reassign Blocksコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
;セレクションフェーズとコマンドアウトフェーズ
lea.l -16(a5),aBUF
.if SCSI_BIOS_LEVEL<=3
;+++++ BUG +++++
;Reservedのフィールドに書き込んでいる
move.b #8,4(aBUF)
;+++++ BUG +++++
.endif
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
movea.l a3,aBUF
bsr scsi_0C_S_DATAOUTI ;SCSIコール$0C _S_DATAOUTI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Read(6)コマンド
read_6_command:
.dc.b $08 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$21 _S_READ
; 読み込み
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_21_S_READ:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l read_6_command,a2 ;Read(6)コマンド
.else
lea.l read_6_command(pc),a2 ;Read(6)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l read_6_command(pc),a2 ;Read(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if SCSI_BIOS_LEVEL<=4
move.l d2,d6
lea.l -16(a5),aBUF
move.b d6,3(aBUF) ;ブロック番号(上位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(下位)
.else
lea.l -16(a5),aBUF
move.l d2,d6
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
move.b dLEN,4(aBUF) ;ブロック数
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データインフェーズ
lsl.l #8,dLEN
.if SCSI_BIOS_LEVEL<=10
lsl.l d5,dLEN
.else
;ブロック長指数が4以上のとき3と見なす
moveq.l #3,d0
if <cmp.l d0,d5>,lo
move.l d5,d0
endif
lsl.l d0,dLEN
.endif
movea.l a3,aBUF
.if SCSI_BIOS_LEVEL<=4
bsr scsi_04_S_DATAIN ;SCSIコール$04 _S_DATAIN
.else
lea.l scsi_04_S_DATAIN(pc),a0 ;SCSIコール$04 _S_DATAIN
if <btst.b #SRAM_SCSI_SOFT_BIT,SRAM_SCSI_MODE>,ne ;ソフト
lea.l scsi_0B_S_DATAINI(pc),a0 ;SCSIコール$0B _S_DATAINI
endif
jsr (a0)
.endif
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
.if 3<=SCSI_BIOS_LEVEL
goto <cmpi.l #-2,d0>,eq,writeext_error_2
.endif
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_2 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Write(6)コマンド
write_6_command:
.dc.b $0A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$22 _S_WRITE
; 書き出し
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_22_S_WRITE:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l write_6_command,a2 ;Write(6)コマンド
.else
lea.l write_6_command(pc),a2 ;Write(6)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l write_6_command(pc),a2 ;Write(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if SCSI_BIOS_LEVEL<=4
move.l d2,d6
lea.l -16(a5),aBUF
move.b d6,3(aBUF) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(上位)
.else
lea.l -16(a5),aBUF
move.l d2,d6
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
move.b dLEN,4(aBUF) ;ブロック数
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
lsl.l #8,dLEN
.if SCSI_BIOS_LEVEL<=10
lsl.l d5,dLEN
.else
;ブロック長指数が4以上のとき3と見なす
moveq.l #3,d0
if <cmp.l d0,d5>,lo
move.l d5,d0
endif
lsl.l d0,dLEN
.endif
movea.l a3,aBUF
.if SCSI_BIOS_LEVEL<=4
bsr scsi_05_S_DATAOUT ;SCSIコール$05 _S_DATAOUT
.else
lea.l scsi_05_S_DATAOUT(pc),a0 ;SCSIコール$05 _S_DATAOUT
if <btst.b #SRAM_SCSI_SOFT_BIT,SRAM_SCSI_MODE>,ne ;ソフト
lea.l scsi_0C_S_DATAOUTI(pc),a0 ;SCSIコール$0C _S_DATAOUTI
endif
jsr (a0)
.endif
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
.if 3<=SCSI_BIOS_LEVEL
goto <cmpi.l #-2,d0>,eq,writeext_error_2
.endif
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_2 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Read(10)コマンド
read_10_command:
.dc.b $28 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|FUA|Reserved##|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$26 _S_READEXT
; 拡張読み込み
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_26_S_READEXT:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
.if 10<=SCSI_BIOS_LEVEL
goto <tst.w dLEN>,eq,writeext_error_1
.endif
movea.l aBUF,a3
;コマンドを作る
lea.l -16(a5),aBUF
.if SCSI_BIOS_LEVEL<=0
lea.l read_10_command,a2 ;Read(10)コマンド
.else
lea.l read_10_command(pc),a2 ;Read(10)コマンド
.endif
moveq.l #10-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if SCSI_BIOS_LEVEL<=4
move.l dLEN,d6
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
move.l dLEN,d6
.endif
move.l d2,2(aBUF) ;ブロック番号
move.b dLEN,8(aBUF) ;ブロック数(下位)
lsr.l #8,dLEN
move.b dLEN,7(aBUF) ;ブロック数(上位)
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データインフェーズ
move.l d6,dLEN
lsl.l #8,dLEN
.if SCSI_BIOS_LEVEL<=10
lsl.l d5,dLEN
.else
;ブロック長指数が4以上のとき3と見なす
moveq.l #3,d0
if <cmp.l d0,d5>,lo
move.l d5,d0
endif
lsl.l d0,dLEN
.endif
movea.l a3,aBUF
.if SCSI_BIOS_LEVEL<=4
bsr scsi_04_S_DATAIN ;SCSIコール$04 _S_DATAIN
.else
lea.l scsi_04_S_DATAIN(pc),a0 ;SCSIコール$04 _S_DATAIN
if <btst.b #SRAM_SCSI_SOFT_BIT,SRAM_SCSI_MODE>,ne ;ソフト
lea.l scsi_0B_S_DATAINI(pc),a0 ;SCSIコール$0B _S_DATAINI
endif
jsr (a0)
.endif
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
.if 3<=SCSI_BIOS_LEVEL
goto <cmpi.l #-2,d0>,eq,writeext_error_2
.endif
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_2 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Write(10)コマンド
write_10_command:
.dc.b $2A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|FUA|Reserved##|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$27 _S_WRITEEXT
; 拡張書き出し
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_27_S_WRITEEXT:
link.w a5,#-16
push d1/dLEN/d6/aBUF/a2/a3
.if 10<=SCSI_BIOS_LEVEL
goto <tst.w dLEN>,eq,writeext_error_1
.endif
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l write_10_command,a2 ;Write(10)コマンド
.else
lea.l write_10_command(pc),a2 ;Write(10)コマンド
.endif
;ここから_S_WRITEEXT、_S_VERIFYEXT共通
writeext_verifyext_common:
movea.l aBUF,a3
.else
movea.l aBUF,a3
.endif
;コマンドを作る
lea.l -16(a5),aBUF
.if 10<=SCSI_BIOS_LEVEL
lea.l write_10_command(pc),a2 ;Write(10)コマンド
.endif
moveq.l #10-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if 10<=SCSI_BIOS_LEVEL
lea.l -16(a5),aBUF
;ここから_S_WRITEEXT、_S_VERIFYEXT共通
writeext_verifyext_common:
.endif
move.l dLEN,d6
.if SCSI_BIOS_LEVEL<=4
lea.l -16(a5),aBUF
.endif
move.l d2,2(aBUF) ;ブロック番号
move.b dLEN,8(aBUF) ;ブロック数(下位)
lsr.l #8,dLEN
move.b dLEN,7(aBUF) ;ブロック数(上位)
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
move.l d6,dLEN
lsl.l #8,dLEN
.if SCSI_BIOS_LEVEL<=10
lsl.l d5,dLEN
.else
;ブロック長指数が4以上のとき3と見なす
moveq.l #3,d0
if <cmp.l d0,d5>,lo
move.l d5,d0
endif
lsl.l d0,dLEN
.endif
movea.l a3,aBUF
.if SCSI_BIOS_LEVEL<=4
bsr scsi_05_S_DATAOUT ;SCSIコール$05 _S_DATAOUT
.else
lea.l scsi_05_S_DATAOUT(pc),a0 ;SCSIコール$05 _S_DATAOUT
if <btst.b #SRAM_SCSI_SOFT_BIT,SRAM_SCSI_MODE>,ne ;ソフト
lea.l scsi_0C_S_DATAOUTI(pc),a0 ;SCSIコール$0C _S_DATAOUTI
endif
jsr (a0)
.endif
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
.if 3<=SCSI_BIOS_LEVEL
goto <cmpi.l #-2,d0>,eq,writeext_error_2
.endif
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop_test
unlk a5
rts
.else
writeext_stsin_2:
goto <cmpi.l #-1,d0>,eq,writeext_error_1
goto <cmpi.l #-2,d0>,eq,writeext_error_2
goto writeext_stsin_0
;ステータスインフェーズとメッセージインフェーズ
writeext_stsin_x:
goto <tst.l d0>,ne,writeext_error_1
writeext_stsin_0:
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
writeext_end:
pop_test
unlk a5
rts
;ステータスインフェーズとメッセージインフェーズ
writeext_stsin_1:
goto <cmpi.l #-1,d0>,ne,writeext_stsin_0
writeext_error_1:
moveq.l #-1,d0
goto writeext_end
.endif
.if 3<=SCSI_BIOS_LEVEL
writeext_error_2:
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
if <tst.l d0>,eq
moveq.l #-2,d0
endif
pop
unlk a5
rts
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Verify(10)コマンド
verify_10_command:
.dc.b $2F ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|Reserved##|BytChk|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$28 _S_VERIFYEXT
; 拡張ベリファイ
;<d2.l:ブロック番号
;<dLEN.l:ブロック数
;<dID.l:(LUN<<16)|SCSI-ID
;<d5.l:ブロック長指数。0=256,1=512,2=1024,3=2048
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_28_S_VERIFYEXT:
link.w a5,#-16
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.if 10<=SCSI_BIOS_LEVEL
goto <tst.w dLEN>,eq,writeext_error_1
.endif
.if SCSI_BIOS_LEVEL<=0
lea.l verify_10_command,a2 ;Verify(10)コマンド
.elif SCSI_BIOS_LEVEL<=4
lea.l verify_10_command(pc),a2 ;Verify(10)コマンド
.else
movea.l aBUF,a3
;コマンドを作る
lea.l -16(a5),aBUF
lea.l verify_10_command(pc),a2 ;Verify(10)コマンド
moveq.l #10-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
.endif
;ここから_S_WRITEEXT、_S_VERIFYEXT共通
goto writeext_verifyext_common
;----------------------------------------------------------------
;Format Unitコマンド
format_unit_command:
.dc.b $04 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|FmtData|CmpLst|ディフェクトリスト形式###
.dc.b $00 ;2 ベンダ固有
.dc.b $00 ;3 インタリーブ(上位)
.dc.b $00 ;4 インタリーブ(下位)
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;SCSIコール$23 _S_FORMAT
; フォーマット
;<dLEN.l:インタリーブ
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_23_S_FORMAT:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l format_unit_command,a2 ;Format Unitコマンド
.else
lea.l format_unit_command(pc),a2 ;Format Unitコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l format_unit_command(pc),a2 ;Format Unitコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.b dLEN,4(aBUF) ;インタリーブ(下位)
lsr.l #8,dLEN
move.b dLEN,3(aBUF) ;インタリーブ(上位)
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Prevent-Allow Medium Removalコマンド
prevent_allow_command:
.dc.b $1E ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved#######|Prevent
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$32 _S_PAMEDIUM
; イジェクト許可/イジェクト禁止
;<dLEN.l:0=イジェクト許可,1=イジェクト禁止
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_32_S_PAMEDIUM:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l prevent_allow_command,a2 ;Prevent-Allow Medium Removalコマンド
.else
lea.l prevent_allow_command(pc),a2 ;Prevent-Allow Medium Removalコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l prevent_allow_command(pc),a2 ;Prevent-Allow Medium Removalコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
andi.b #1,dLEN
move.b dLEN,4(aBUF) ;0=イジェクト許可,1=イジェクト禁止
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Start-Stop Unit(Eject SONY MO)コマンド
start_stop_unit_command:
.dc.b $1B ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|Immed
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved######|LoEj|Start
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2F _S_STARTSTOP
; 操作許可/操作禁止
;<dLEN.l:0=操作禁止,1=操作許可,2=アンロード,3=ロード
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2F_S_STARTSTOP:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l start_stop_unit_command,a2 ;Start-Stop Unit(Eject SONY MO)コマンド
.else
lea.l start_stop_unit_command(pc),a2 ;Start-Stop Unit(Eject SONY MO)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l start_stop_unit_command(pc),a2 ;Start-Stop Unitコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
andi.b #3,dLEN
move.b dLEN,4(aBUF) ;0=操作禁止,1=操作許可,2=アンロード,3=ロード
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Load/Unload SHARP MOコマンド
load_unload_command:
.dc.b $C1 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|#####
.dc.b $00 ;2
.dc.b $00 ;3
.dc.b $00 ;4 #######|LoEj
.dc.b $00 ;5
.endif
;----------------------------------------------------------------
;SCSIコール$30 _S_SEJECT
; イジェクト(SHARP MO)
; SUSIE.Xでは_S_EJECT6MO1と呼ばれている
;<dLEN.l:0=アンロード,1=ロード
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_30_S_SEJECT:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l load_unload_command,a2 ;Load/Unload SHARP MOコマンド
.else
lea.l load_unload_command(pc),a2 ;Load/Unload SHARP MOコマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l load_unload_command(pc),a2 ;Load/Unload SHARP MOコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
andi.b #1,dLEN
move.b dLEN,4(aBUF) ;0=アンロード,1=ロード
;セレクションフェーズとコマンドアウトフェーズ
moveq.l #6,dLEN ;長さ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Seek(6)コマンド
seek_6_command:
.dc.b $0B ;0 オペレーションコード
.dc.b $00 ;1 LUN###|ブロック番号(上位)#####
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$2D _S_SEEK
; シーク
;<d2.l:ブロック番号
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_2D_S_SEEK:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l seek_6_command,a2 ;Seek(6)コマンド
.else
lea.l seek_6_command(pc),a2 ;Seek(6)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l seek_6_command(pc),a2 ;Seek(6)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if SCSI_BIOS_LEVEL<=4
move.l d2,d6
lea.l -16(a5),aBUF
move.b d6,3(aBUF) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(上位)
.else
lea.l -16(a5),aBUF
move.l d2,d6
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=3
;+++++ BUG +++++
;Reservedのフィールドに書き込んでいる
move.b dLEN,4(aBUF)
;+++++ BUG +++++
.endif
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Assign Drive(SASI)コマンド
assign_drive_sasi_command:
.dc.b $C2 ;0 オペレーションコード
.dc.b $00 ;1
.dc.b $00 ;2
.dc.b $00 ;3
.dc.b $00 ;4
.dc.b $00 ;5 データの長さ
.endif
;----------------------------------------------------------------
;SCSIコール$36 _S_DSKINI
; Assign Drive(SASI)
;<dLEN.l:データの長さ
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_36_S_DSKINI:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l assign_drive_sasi_command,a2 ;Assign Drive(SASI)コマンド
.else
lea.l assign_drive_sasi_command(pc),a2 ;Assign Drive(SASI)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l assign_drive_sasi_command(pc),a2 ;Assign Drive(SASI)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
.if SCSI_BIOS_LEVEL<=4
move.l dLEN,d1
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
move.l dLEN,d1
.endif
move.b d1,5(aBUF) ;データの長さ
;セレクションフェーズとコマンドアウトフェーズ
moveq.l #6,dLEN
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
move.l d1,dLEN
movea.l a3,aBUF
bsr scsi_0C_S_DATAOUTI ;SCSIコール$0C _S_DATAOUTI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Format Block(SASI)コマンド
format_block_sasi_command:
.dc.b $06 ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5
.endif
;----------------------------------------------------------------
;SCSIコール$37 _S_FORMATB
; Format Block(SASI)
;<d2.l:ブロック番号
;<dLEN.l:インタリーブ
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_37_S_FORMATB:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l format_block_sasi_command,a2 ;Format Block(SASI)コマンド
.else
lea.l format_block_sasi_command(pc),a2 ;Format Block(SASI)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l format_block_sasi_command(pc),a2 ;Format Blockコマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.l d2,d6
.if SCSI_BIOS_LEVEL<=4
move.b d6,3(aBUF) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(上位)
.else
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
move.b dLEN,4(aBUF) ;インタリーブ
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Bad Track Format(SASI)コマンド
bad_track_format_sasi_command:
.dc.b $07 ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5 コントロールバイト
.endif
;----------------------------------------------------------------
;SCSIコール$38 _S_BADFMT
; Bad Track Format(SASI)
;<d2.l:ブロック番号
;<dLEN.l:インタリーブ
;<dID.l:(LUN<<16)|SCSI-ID
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_38_S_BADFMT:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l bad_track_format_sasi_command,a2 ;Bad Track Format(SASI)コマンド
.else
lea.l bad_track_format_sasi_command(pc),a2 ;Bad Track Format(SASI)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l bad_track_format_sasi_command(pc),a2 ;Bad Track Format(SASI)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.l d2,d6
.if SCSI_BIOS_LEVEL<=4
move.b d6,3(aBUF) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(上位)
.else
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
move.b dLEN,4(aBUF) ;インタリーブ
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop
unlk a5
rts
.else
goto writeext_stsin_x
.endif
.if 3<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;Assign Track(SASI)コマンド
assign_track_sasi_command:
.dc.b $0E ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5
.endif
;----------------------------------------------------------------
;SCSIコール$39 _S_ASSIGN
; Assign Track(SASI)
;<d2.l:ブロック番号
;<dLEN.l:インタリーブ
;<dID.l:(LUN<<16)|SCSI-ID
;<aBUF.l:バッファのアドレス
;>d0.l:0=成功,-1=失敗,その他=(MSGIN<<16)|STSIN
scsi_39_S_ASSIGN:
link.w a5,#-16
.if SCSI_BIOS_LEVEL<=4
push d1/dLEN/d6/aBUF/a2/a3
.else
movem.l d1/dLEN/d6/aBUF/a2/a3,-(sp)
.endif
movea.l aBUF,a3
;コマンドを作る
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l assign_track_sasi_command,a2 ;Assign Track(SASI)コマンド
.else
lea.l assign_track_sasi_command(pc),a2 ;Assign Track(SASI)コマンド
.endif
lea.l -16(a5),aBUF
.else
lea.l -16(a5),aBUF
lea.l assign_track_sasi_command(pc),a2 ;Assign Track(SASI)コマンド
.endif
moveq.l #6-1,d1
for d1
move.b (a2)+,(aBUF)+
next
lea.l -16(a5),aBUF
move.l d2,d6
.if SCSI_BIOS_LEVEL<=4
move.b d6,3(aBUF) ;ブロック番号(下位)
lsr.l #8,d6
move.b d6,2(aBUF) ;ブロック番号(中位)
lsr.l #8,d6
move.b d6,1(aBUF) ;ブロック番号(上位)
.else
and.l #$00FFFFFF,d6
or.l d6,(aBUF) ;ブロック番号
.endif
move.b dLEN,4(aBUF) ;インタリーブ
;セレクションフェーズとコマンドアウトフェーズ
bsr select_and_cmdout ;セレクションフェーズとコマンドアウトフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <tst.l d0>,ne,assign_error
.else
goto <tst.l d0>,ne,writeext_error_1
.endif
;データアウトフェーズ
moveq.l #4,dLEN ;長さ
movea.l a3,aBUF
bsr scsi_0C_S_DATAOUTI ;SCSIコール$0C _S_DATAOUTI
;ステータスインフェーズとメッセージインフェーズ
.if SCSI_BIOS_LEVEL<=4
goto <cmpi.l #-1,d0>,eq,assign_error
bsr stsin_and_msgin ;ステータスインフェーズとメッセージインフェーズ
pop_test
unlk a5
rts
assign_error:
moveq.l #-1,d0
pop
unlk a5
rts
.else
goto writeext_stsin_1 ;ステータスインフェーズとメッセージインフェーズ
.endif
.if SCSI_BIOS_LEVEL<=3
;----------------------------------------------------------------
;SCSI出力(DMA転送)
; MC68040またはMC68060のときはデータキャッシュをプッシュしてから呼び出す必要がある
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
dataout_transfer:
push dLEN/aBUF
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC) ;転送開始
bsr dataout_dma ;SCSI出力(DMA転送)実行
goto <tst.l d0>,ne,dataout_transfer_end ;転送失敗。終了
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
goto <cmp.b #SPC_INTS_CC,d0>,eq,dataout_transfer_no_error
dataout_transfer_end:
pop_test
rts
dataout_transfer_no_error:
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
datain_transfer:
push dLEN/aBUF
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC)
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
;転送開始
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
bsr datain_dma ;SCSI入力(DMA転送)実行
goto <tst.l d0>,ne,datain_transfer_end
;割り込みを待つ
datain_transfer_wait:
do
move.b SPC_INTS(aSPC),d0
while eq
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
goto <cmp.b #SPC_INTS_CC,d0>,eq,datain_transfer_no_error
datain_transfer_end:
pop_test
rts
datain_transfer_no_error:
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;SCSI出力(DMA転送)実行
;<dLEN.l:長さ
;<aBUF.l:アドレス
dataout_dma:
aDMAC reg a0
push aDMAC/a3
;DMAを設定する
lea.l DMAC_1_BASE,aDMAC
move.b #$FF,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
move.b #DMAC_MEMORY_TO_DEVICE|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX,DMAC_OCR(aDMAC)
move.w #0,DMAC_BTC(aDMAC)
move.b #DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT,DMAC_DCR(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
lea.l SPC_DREG(aSPC),a3
move.l a3,DMAC_DAR(aDMAC)
;256バイトずつ転送する
do
;<dLEN.l:今回の残りのデータの長さ
;<aBUF.l:今回のバッファのアドレス
goto <cmp.l #256,dLEN>,ls,dataout_dma_last ;残り1~256バイト
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w #256,DMAC_MTC(aDMAC) ;データの長さ
dataout_dma_continue:
;FIFOが空になるまで待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,eq
;REQ=1を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;DMA転送開始
move.b #-1,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
nop
nop
nop
.if 3<=SCSI_BIOS_LEVEL
nop
.endif
;DMA転送終了を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(aDMAC)>,eq
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,dataout_dma_continue
;+++++ BUG +++++
goto <tst.b DMAC_CER(aDMAC)>,ne,dataout_dma_error ;DMAエラーあり
adda.l #256,aBUF ;次回のバッファのアドレス
sub.l #256,dLEN ;次回の残りのデータの長さ
while ne
moveq.l #0,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop_test
rts
;残り1~256バイト
dataout_dma_last:
move.l aBUF,DMAC_MAR(aDMAC)
move.w dLEN,DMAC_MTC(aDMAC)
dataout_dma_last_start:
;FIFOが空になるまで待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,eq
;REQ=1を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;DMA転送開始
move.b #-1,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
nop
nop
nop
.if 3<=SCSI_BIOS_LEVEL
nop
.endif
;DMA転送終了を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(aDMAC)>,eq
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
.if SCSI_BIOS_LEVEL<=0
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,dataout_dma_continue
.else
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,dataout_dma_last_start
.endif
;+++++ BUG +++++
goto <tst.b DMAC_CER(aDMAC)>,ne,dataout_dma_error ;DMAエラーあり
moveq.l #0,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop_test
rts
;DMAエラーあり
dataout_dma_error:
moveq.l #-1,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)実行
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a6.l:SPCベースアドレス
datain_dma:
aDMAC reg a0
push aDMAC/a3
;DMAを設定する
lea.l DMAC_1_BASE,aDMAC
move.b #$FF,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
move.b #DMAC_DEVICE_TO_MEMORY|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX,DMAC_OCR(aDMAC)
move.w #0,DMAC_BTC(aDMAC)
move.b #DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT,DMAC_DCR(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
lea.l SPC_DREG(aSPC),a3
move.l a3,DMAC_DAR(aDMAC)
;256バイトずつ転送する
do
;<dLEN.l:今回の残りのデータの長さ
;<aBUF.l:今回のバッファのアドレス
goto <cmp.l #256,dLEN>,ls,datain_dma_last ;残り1~256バイト
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w #256,DMAC_MTC(aDMAC) ;データの長さ
datain_dma_continue:
;FIFOが空でなくなるまで待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;DMA転送開始
move.b #$FF,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
nop
nop
nop
.if 3<=SCSI_BIOS_LEVEL
nop
.endif
;DMA転送終了を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(aDMAC)>,eq
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,datain_dma_continue
;+++++ BUG +++++
goto <tst.b DMAC_CER(aDMAC)>,ne,datain_dma_error ;DMAエラーあり
adda.l #256,aBUF ;次回のバッファのアドレス
sub.l #256,dLEN ;次回の残りのデータの長さ
while ne
moveq.l #0,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop_test
rts
;残り1~256バイト
datain_dma_last:
move.l aBUF,DMAC_MAR(aDMAC)
move.w dLEN,DMAC_MTC(aDMAC)
datain_dma_last_start:
;FIFOが空でなくなるまで待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;DMA転送開始
move.b #$FF,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
nop
nop
nop
.if 3<=SCSI_BIOS_LEVEL
nop
.endif
;DMA転送終了を待つ
do
goto <tst.b SPC_INTS(aSPC)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(aDMAC)>,eq
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,datain_dma_last_start
;+++++ BUG +++++
goto <tst.b DMAC_CER(aDMAC)>,ne,datain_dma_error ;DMAエラーあり
moveq.l #0,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop_test
rts
;DMAエラーあり
datain_dma_error:
moveq.l #-1,d0
.if 3<=SCSI_BIOS_LEVEL
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
.endif
pop_test
rts
;SPC割り込みあり
dataio_interrupted:
.if SCSI_BIOS_LEVEL<=0
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA動作中止
moveq.l #0,d0
pop
rts
.else
move.b SPC_INTS(aSPC),d0
goto <cmpi.b #SPC_INTS_CC,d0>,ne,dataio_abort ;SPCが転送終了していない
;SPCが転送終了した
goto <tst.w DMAC_MTC(aDMAC)>,ne,dataio_abort_2 ;DMAが転送終了していない
moveq.l #0,d0
goto dataio_abort
;DMAが転送終了していない
dataio_abort_2:
moveq.l #-2,d0
;SPCが転送終了していない
dataio_abort:
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA動作中止
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
pop
rts
.endif
.elif SCSI_BIOS_LEVEL<=4
;----------------------------------------------------------------
;SCSI出力(DMA転送)
; MC68040またはMC68060のときはデータキャッシュをプッシュしてから呼び出す必要がある
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
dataout_transfer:
move.l a3,-(sp)
lea.l dataout_dma(pc),a3 ;SCSI出力(DMA転送)実行
bsr dataio_transfer ;SCSI入出力(DMA転送)
movea.l (sp)+,a3
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
datain_transfer:
move.l a3,-(sp)
lea.l datain_dma(pc),a3 ;SCSI入力(DMA転送)実行
bsr dataio_transfer ;SCSI入出力(DMA転送)
;キャッシュクリア
;!!! 機種がX68030のとき転送後にCACRを直接操作してデータキャッシュだけクリアしている
push d0/d1
move.b SYSPORT_MODEL,d0
lsr.b #4,d0
if <cmpi.b #14,d0>,cs ;X68030
.cpu 68030
movec.l cacr,d0
move.l d0,d1
bset.l #11,d0 ;データキャッシュをクリア
movec.l d0,cacr
movec.l d1,cacr
.cpu 68000
endif
pop
movea.l (sp)+,a3
rts
;----------------------------------------------------------------
;SCSI入出力(DMA転送)
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;<a3.l:dataout_dmaまたはdatain_dma
;<a6.l:SPCベースアドレス
dataio_transfer:
aDMAC reg a2
push aBUF/aDMAC
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PSNS_MSG|SPC_PSNS_CD|SPC_PSNS_IO,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC) ;データの長さ(下位)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC) ;データの長さ(中位)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC) ;データの長さ(上位)
;REQ=1を待つ
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;DMAを設定する
lea.l DMAC_1_BASE,aDMAC
;<a2.l:DMAチャンネルベースアドレス
move.b #$FF,DMAC_CSR.w(aDMAC) ;DMAC_CSRをクリア
move.w #0,DMAC_BTC(aDMAC)
move.b #DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT,DMAC_DCR(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
lea.l SPC_DREG(aSPC),a0
move.l a0,DMAC_DAR(aDMAC)
;REQ=1を待つ
do
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;転送開始
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC) ;転送開始
jsr (a3) ;dataout_dmaまたはdatain_dma
goto <tst.l d0>,ne,dataio_transfer_end ;転送失敗。終了
;転送終了を待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,dataio_transfer_phase ;フェーズ不一致
while <btst.b #SPC_INTS_CC_BIT,SPC_INTS(aSPC)>,eq
;転送終了
bset.b #SPC_INTS_CC_BIT,SPC_INTS(aSPC) ;Command Completeをクリア
moveq.l #0,d0
goto dataio_transfer_end
;フェーズ不一致
dataio_transfer_phase:
bset.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC) ;Service Requiredをクリア
moveq.l #-3,d0
goto dataio_transfer_end
;+++++ BUG +++++
;どこからも参照されていない
moveq.l #-1,d0
;+++++ BUG +++++
;終了
dataio_transfer_end:
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
pop
rts
;----------------------------------------------------------------
;SCSI出力(DMA転送)実行
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a2.l:DMAチャンネルベースアドレス
;<a6.l:SPCベースアドレス
dataout_dma:
push d1/d2/dLEN/d4/d5/aBUF
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
move.b #DMAC_MEMORY_TO_DEVICE|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX,DMAC_OCR(aDMAC)
move.l dLEN,d4
;256バイトずつ転送する
do
if <cmp.l #256,dLEN>,hi
move.l #256,d5
else
move.l dLEN,d5
endif
;<dLEN.l:残りのデータの長さ
;<d4.l:残りのデータの長さ
;<d5.l:今回転送する長さ
;<aBUF.l:バッファのアドレス
move.l aBUF,DMAC_MAR(a2) ;バッファのアドレス
move.w d5,DMAC_MTC(a2) ;今回転送する長さ
dataout_dma_continue:
;FIFOが空になるまで待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,dataout_dma_phase ;フェーズ不一致
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,eq
;REQ=1を待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,dataout_dma_phase ;フェーズ不一致
move.b SPC_PSNS(aSPC),d0
while <btst.l #SPC_PSNS_REQ_BIT,d0>,eq
;バスエラー対策
; X68000ではDMACがSPCのDREQを外部転送要求信号として使えないため、
; DREQが出ていないときはDTACKを出さないことでDREGへのライトを待たせている
; SCSI機器のデータの受け取りが遅いとバッファが一杯になりDREQが出なくなる
; DREGへのライトでDTACKが出ないとバスエラーが発生して転送が中断される
; このときDMACはバスエラーになったデータは転送されなかったと判断するが、
; SPCはバスエラーを感知していないので、BERRがアサートされてからASがネゲートされるまでの間に
; バスエラーになったはずのデータを受け取ってしまう場合がある
; それを検出してデータが重複しないようにする
moveq.l #0,d0
move.b SPC_TCH(aSPC),d0
lsl.l #8,d0
move.b SPC_TCM(aSPC),d0
lsl.l #8,d0
move.b SPC_TCL(aSPC),d0 ;SPCが転送する残りの長さ
move.l d4,d1 ;ブロック開始時の残りの長さ
sub.l d0,d1 ;SPCが今回のブロックで転送した長さ
moveq.l #0,d0
move.w DMAC_MTC(a2),d0 ;DMACの今回のブロックの残りの長さ
move.l d5,d2 ;今回転送する長さ
sub.l d0,d2 ;DMACが今回のブロックで転送した長さ
sub.l d2,d1 ;SPCがDMACよりも多く転送した長さ
if ne
add.l d1,DMAC_MAR(a2) ;DMACが転送するアドレスを進める
sub.w d1,DMAC_MTC(a2) ;DMACが転送する長さを減らす
endif
;転送開始
move.b #-1,DMAC_CSR(a2) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(a2) ;転送開始
nop
nop
nop
nop
nop
;転送終了を待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,dataout_dma_phase ;フェーズ不一致
break <btst.b #SPC_INTS_CC_BIT,SPC_INTS(aSPC)>,ne ;転送終了
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(a2)>,eq
;SPCまたはDMAが転送終了した
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.b #1,DMAC_CER(a2)>,ne,dataout_dma_continue
;+++++ BUG +++++
goto <tst.b DMAC_CER(a2)>,ne,dataout_dma_error ;DMAエラーあり
goto <tst.w DMAC_MTC(a2)>,ne,dataout_dma_error ;DMAが転送終了していない
adda.l d5,aBUF ;アドレスを増やす
sub.l d5,d4 ;長さを減らす
sub.l d5,dLEN ;長さを減らす
while ne
moveq.l #0,d0
goto dataout_dma_end ;終了
;フェーズ不一致
dataout_dma_phase:
moveq.l #-3,d0
goto dataout_dma_abort ;転送中止
;DMAエラーあり
;DMAが転送終了していない
dataout_dma_error:
moveq.l #-2,d0
goto dataout_dma_abort ;転送中止
;+++++ BUG +++++
;どこからも参照されていない
moveq.l #-1,d0
;+++++ BUG +++++
;転送中止
dataout_dma_abort:
move.b #DMAC_CCR_SAB,DMAC_CCR(a2) ;DMA転送中止
;終了
dataout_dma_end:
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)実行
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a2.l:DMAチャンネルベースアドレス
;<a6.l:SPCベースアドレス
datain_dma:
push d1/d2/dLEN/d4/d5/aBUF
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
move.b #DMAC_DEVICE_TO_MEMORY|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX,DMAC_OCR(aDMAC)
;256バイトずつ転送する
do
if <cmp.l #256,dLEN>,hi
move.l #256,d5
else
move.l dLEN,d5
endif
;<dLEN.l:残りのデータの長さ
;<d5.l:今回転送する長さ
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w d5,DMAC_MTC(aDMAC) ;今回転送する長さ
datain_dma_continue:
;FIFOが空でなくなるまで待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,datain_dma_phase ;フェーズ不一致
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;転送開始
move.b #-1,DMAC_CSR(aDMAC) ;DMAC_CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;転送開始
nop
nop
nop
nop
nop
;転送終了を待つ
do
goto <btst.b #SPC_INTS_SR_BIT,SPC_INTS(aSPC)>,ne,datain_dma_phase ;フェーズ不一致
break <btst.b #SPC_INTS_CC_BIT,SPC_INTS(aSPC)>,ne ;転送終了
while <btst.b #DMAC_CSR_COC_BIT,DMAC_CSR(aDMAC)>,eq
;SPCまたはDMAが転送終了した
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.b #1,DMAC_CER(aDMAC)>,ne,datain_dma_continue
;+++++ BUG +++++
goto <tst.b DMAC_CER(aDMAC)>,ne,datain_dma_error ;DMAエラーあり
goto <tst.w DMAC_MTC(aDMAC)>,ne,datain_dma_error ;DMAが転送終了していない
adda.l d5,aBUF ;アドレスを増やす
sub.l d5,d4 ;長さを減らす
sub.l d5,dLEN ;長さを減らす
while ne
moveq.l #0,d0
goto datain_dma_end ;終了
;フェーズ不一致
datain_dma_phase:
moveq.l #-3,d0
goto datain_dma_abort ;転送中止
;DMAエラーあり
;DMAが転送終了していない
datain_dma_error:
moveq.l #-2,d0
goto datain_dma_abort ;転送中止
;+++++ BUG +++++
;どこからも参照されていない
moveq.l #-1,d0
;+++++ BUG +++++
;転送中止
datain_dma_abort:
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA転送中止
;終了
datain_dma_end:
pop
rts
.elif SCSI_BIOS_LEVEL<=10
;----------------------------------------------------------------
;SCSI出力(DMA転送)
; MC68040またはMC68060のときはデータキャッシュをプッシュしてから呼び出す必要がある
;<dLEN.l:長さ
;<aBUF.l:アドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
dataout_transfer:
push dLEN/aBUF
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;長さをセットする
move.l #$00FFFFFF,d0
and.l dLEN,d0
movep.l d0,SPC_TEMP(aSPC)
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;REQ=1を待つ
do
while <tst.b SPC_PSNS(aSPC)>,pl ;SPC_PSNS_REQ_BIT
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
bsr dataout_dma ;SCSI出力(DMA転送)実行
if <tst.l d0>,eq
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq
moveq.l #0,d0
endif
endif
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
datain_transfer:
push dLEN/aBUF
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;長さをセットする
move.l #$00FFFFFF,d0
and.l dLEN,d0
movep.l d0,SPC_TEMP(aSPC)
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
bsr datain_dma ;SCSI入力(DMA転送)実行
if <tst.l d0>,eq
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq
moveq.l #0,d0
endif
endif
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)実行
datain_dma:
push d1/d2/a0/a3
~dcr = DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
~ocr = DMAC_DEVICE_TO_MEMORY|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX
move.w #(~dcr<<8)|~ocr,d1
goto dataio_dma_common ;ここからSCSI入出力(DMA転送)実行共通
;----------------------------------------------------------------
;SCSI出力(DMA転送)実行
dataout_dma:
push_again
~dcr = DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
~ocr = DMAC_MEMORY_TO_DEVICE|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX
move.w #(~dcr<<8)|~ocr,d1
;----------------------------------------------------------------
;ここからSCSI入出力(DMA転送)実行共通
dataio_dma_common:
bsr cache_flush ;DMA転送開始直前のキャッシュフラッシュ
aDMAC reg a0
;DMAを設定する
lea.l DMAC_1_BASE,aDMAC
st.b DMAC_CSR(aDMAC) ;DMAC_CSRをクリア
clr.w DMAC_BTC(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
lea.l SPC_DREG(aSPC),a3
move.l a3,DMAC_DAR(aDMAC)
;一度に転送する長さを決める
moveq.l #0,d2
move.w #256,d2
if <tst.b SRAM_SCSI_MODE>,mi ;SRAM_SCSI_BLOCK_BIT ブロック
moveq.l #0,d2
move.w BIOS_SCSI_BLOCK_SIZE.l,d2 ;SCSI機器のブロックサイズ
endif
;バーストにするか
if <btst.b #SRAM_SCSI_BURST_BIT,SRAM_SCSI_MODE>,ne ;バースト
;外部転送要求にする
;DMAのREQ1がSPCのDREQに繋がっているのはX68030だけ
~dcr = DMAC_NO_HOLD_CYCLE^DMAC_BURST_TRANSFER
~ocr = DMAC_AUTO_REQUEST_MAX^DMAC_EXTERNAL_REQUEST
eori.w #(~dcr<<8)|~ocr,d1
endif
;DMAC_DCRとDMAC_OCRを設定する
move.w d1,DMAC_DCR(aDMAC) ;DMAC_DCRとDMAC_OCR
;入力と出力で分岐する
aINTS reg a3
lea.l SPC_INTS(aSPC),aINTS
goto <tst.b d1>,mi,dataio_dma_input ;pl=DMAC_MEMORY_TO_DEVICE,mi=DMAC_DEVICE_TO_MEMORY
;入力
;出力
dataio_dma_output:
do
;<dLEN.l:今回の残りのデータの長さ
;<aBUF.l:今回のバッファのアドレス
goto <cmp.l d2,dLEN>,ls,dataio_dma_output_last ;残り1~ブロックサイズ
dataio_dma_output_start:
;<d2.l:今回転送する長さ
;今回のバッファのアドレスと今回転送する長さをDMAに設定する
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w d2,DMAC_MTC(aDMAC) ;今回転送する長さ
dataio_dma_output_continue:
;FIFOが空になるまで待つ
do
goto <tst.b (aINTS)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,eq
;REQ=1を待つ
do
goto <tst.b (aINTS)>,ne,dataio_interrupted ;SPC割り込みあり
while <tst.b SPC_PSNS(aSPC)>,pl ;SPC_PSNS_REQ_BIT
;DMA転送開始
st.b DMAC_CSR(aDMAC) ;CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
tst.b (aINTS) ;空読み?
;DMA転送終了を待つ
do
goto <tst.b (aINTS)>,ne,dataio_interrupted ;SPC割り込みあり
while <tst.b DMAC_CSR(aDMAC)>,pl ;DMAC_CSR_COC
;エラーがないか確認する
move.b DMAC_CER(aDMAC),d0
goto ne,dataio_dma_output_error ;DMAエラーあり
;残りのデータの長さが0になるまで繰り返す
adda.l d2,aBUF ;次回のバッファのアドレス
sub.l d2,dLEN ;次回の残りのデータの長さ
while ne
moveq.l #0,d0
dataio_dma_output_end:
;+++++ BUG +++++
;DMAC_DARをSASIに戻していない
;+++++ BUG +++++
pop_test
rts
;残り1~ブロックサイズ
dataio_dma_output_last:
move.l dLEN,d2 ;今回転送する長さは残りのデータの長さ
goto dataio_dma_output_start
;DMAエラーあり
dataio_dma_output_error:
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.l #1,d0>,ne,dataio_dma_output_continue
;+++++ BUG +++++
;バスエラー以外のDMAエラー
moveq.l #-1,d0
goto dataio_dma_output_end
;SPC割り込みあり
dataio_interrupted:
move.b SPC_INTS(aSPC),d0
goto <cmpi.b #SPC_INTS_CC,d0>,ne,dataio_dma_output_abort ;SPCが転送終了していない。転送中止
;SPCが転送終了した
moveq.l #0,d0
goto <tst.w DMAC_MTC(aDMAC)>,eq,dataio_dma_output_abort ;DMAも転送終了した。転送中止
;SPCは転送終了したがDMAが転送終了していない
moveq.l #-2,d0
;転送中止
dataio_dma_output_abort:
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA転送中止
goto dataio_dma_output_end
;残り1~ブロックサイズ
dataio_dma_input_last:
move.l dLEN,d2 ;今回転送する長さは残りのデータの長さ
goto dataio_dma_input_start
;入力
dataio_dma_input:
do
;<dLEN.l:今回の残りのデータの長さ
;<aBUF.l:今回のバッファのアドレス
goto <cmp.l d2,dLEN>,ls,dataio_dma_input_last ;残り1~ブロックサイズ
dataio_dma_input_start:
;<d2.l:今回転送する長さ
;今回のバッファのアドレスと今回転送する長さをDMAに設定する
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w d2,DMAC_MTC(aDMAC) ;今回転送する長さ
dataio_dma_input_continue:
;FIFOが空でなくなるまで待つ
do
goto <tst.b (aINTS)>,ne,dataio_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;DMA転送開始
st.b DMAC_CSR(aDMAC) ;CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
tst.b (aINTS) ;空読み?
;DMA転送終了を待つ
do
goto <tst.b (aINTS)>,ne,dataio_interrupted ;SPC割り込みあり
while <tst.b DMAC_CSR(aDMAC)>,pl ;DMAC_CSR_COC
;エラーがないか確認する
move.b DMAC_CER(aDMAC),d0
goto ne,dataio_dma_input_error ;DMAエラーあり
;残りのデータの長さが0になるまで繰り返す
adda.l d2,aBUF ;次回のバッファのアドレス
sub.l d2,dLEN ;次回の残りのデータの長さ
while ne
moveq.l #0,d0
dataio_dma_input_end:
;+++++ BUG +++++
;DMAC_DARをSASIに戻していない
;+++++ BUG +++++
pop
rts
;DMAエラーあり
dataio_dma_input_error:
;+++++ BUG +++++
;DMAC_CERの5ビットのエラーコードのビット1だけテストしてバスエラー(デバイスアドレス)と見なしている
;バスエラー(デバイスアドレス)のエラーコード$0Aのビット1がたまたま1だったので動いている?
goto <btst.l #1,d0>,ne,dataio_dma_input_continue
;+++++ BUG +++++
;バスエラー以外のDMAエラー
moveq.l #-1,d0
goto dataio_dma_input_end
.else
;----------------------------------------------------------------
;SCSI出力(DMA転送)
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,-1=DMAエラー,その他=INTS
dataout_transfer:
push d1/d2/dLEN/a0/aBUF/a3
aDMAC reg a0
aINTS reg a3
lea.l DMAC_1_BASE,aDMAC
lea.l SPC_INTS(aSPC),aINTS
;キャッシュフラッシュ
bsr cache_flush
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC) ;データの長さ(下位)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC) ;データの長さ(中位)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC) ;データの長さ(上位)
;REQ=1を待つ
do
while <tst.b SPC_PSNS(aSPC)>,pl ;SPC_PSNS_REQ_BIT
;SPC転送開始
move.b (aINTS),(aINTS) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
;DCRとOCRを決める
; X68000のSPCのDREQはDMACのREQ1に繋がっていない
; DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
~dcr = DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT
~ocr = DMAC_MEMORY_TO_DEVICE|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX
move.w #(~dcr<<8)|~ocr,d1
.if SCSIEXROM==0
ifand <isX68030>,eq,<btst.b #SRAM_SCSI_BURST_BIT,SRAM_SCSI_MODE>,ne ;内蔵SCSIかつX68030かつバースト
~dcr = DMAC_NO_HOLD_CYCLE^DMAC_BURST_TRANSFER
~ocr = DMAC_AUTO_REQUEST_MAX^DMAC_EXTERNAL_REQUEST
eori.w #(~dcr<<8)|~ocr,d1
endif
.endif
;DMACを設定する
st.b DMAC_CSR(aDMAC) ;CSRをクリア
clr.w DMAC_BTC(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
move.w d1,DMAC_DCR(aDMAC) ;DMAC_DCR,DMAC_OCR
moveq.l #SPC_DREG,d0
add.l aSPC,d0
move.l d0,DMAC_DAR(aDMAC) ;DARにDREGを設定
;ブロックの長さを決める
move.l #256,d2
if <tst.b SRAM_SCSI_MODE>,mi ;SRAM_SCSI_BLOCK_BIT
move.w BIOS_SCSI_BLOCK_SIZE.l,d2 ;SCSI機器のブロックサイズ
endif
;<d2.l:ブロックの長さ
do
;<dLEN.l:ブロック開始時の全体の残りの長さ
;<aBUF.l:ブロック開始時のデータのアドレス
;最後のブロックの長さを調整する
if <cmp.l dLEN,d2>,hi
move.l dLEN,d2
endif
;<d2.l:ブロックの長さ
dataout_transfer_continue:
;FIFOが空になるまで待つ
do
goto <tst.b (aINTS)>,ne,dataout_transfer_finish ;SPC動作終了
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,eq
;データのアドレスとブロックの残りの長さを計算する
moveq.l #0,d0
move.b SPC_TCH(aSPC),d0 ;データの長さ(上位)
swap.w d0
move.b SPC_TCM(aSPC),d0 ;データの長さ(中位)
lsl.w #8,d0
move.b SPC_TCL(aSPC),d0 ;データの長さ(下位)
;<d0.l:全体の残りの長さ
sub.l dLEN,d0 ;-(ブロックの転送した長さ)=(全体の残りの長さ)-(ブロック開始時の全体の残りの長さ)
;<d0.l:-(ブロックの転送した長さ)
move.l aBUF,d1
sub.l d0,d1 ;(データのアドレス)=(ブロック開始時のデータのアドレス)+(ブロックの転送した長さ)
;<d1.l:データのアドレス
add.l d2,d0 ;(ブロックの残りの長さ)=(ブロックの長さ)-(ブロックの転送した長さ)
;<d0.l:ブロックの残りの長さ
st.b DMAC_CSR(aDMAC) ;CSRをクリア
move.l d1,DMAC_MAR(aDMAC) ;データのアドレス
move.w d0,DMAC_MTC(aDMAC) ;ブロックの残りの長さ
;REQ=1を待つ
do
goto <tst.b (aINTS)>,ne,dataout_transfer_finish ;SPC動作終了
while <tst.b SPC_PSNS(aSPC)>,pl ;SPC_PSNS_REQ_BIT
;DMA転送開始
st.b DMAC_CSR(aDMAC) ;CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
tst.b (aINTS) ;空読み
;DMA動作終了を待つ
do
goto <tst.b (aINTS)>,ne,dataout_transfer_finish ;SPC動作終了
while <tst.b DMAC_CSR(aDMAC)>,pl ;DMAC_CSR_COC
;DMA動作終了
move.b DMAC_CER(aDMAC),d0
if ne ;DMAエラーあり
goto <cmp.b #DMAC_BUS_ERROR_DEVICE,d0>,eq,dataout_transfer_continue ;デバイスアドレスのバスエラーは継続
;デバイスアドレスのバスエラー以外のDMAエラー
;!!! SPCの後始末をしていない。ハングアップしそう
moveq.l #-1,d0
goto dataout_transfer_end
endif
;DMAエラーなし
;データのアドレスと全体の残りの長さを更新する
adda.l d2,aBUF ;(データのアドレス)+=(ブロックの長さ)
sub.l d2,dLEN ;(全体の残りの長さ)-=(ブロックの長さ)
while ne ;全体の残りの長さが0になるまで繰り返す
;SPC動作終了
dataout_transfer_finish:
;SPCの後始末
moveq.l #0,d0
do
move.b (aINTS),d0
while eq
move.b d0,(aINTS) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq ;SPC転送終了
moveq.l #0,d0
endif
;DMACの後始末
if <tst.w DMAC_MTC(aDMAC)>,ne ;MTCが0でない
moveq.l #-2,d0
endif
if <tst.b DMAC_CSR(aDMAC)>,pl ;DMAC_CSR_COC。DMAが転送終了していない
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA転送中止
endif
;終了
dataout_transfer_end:
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)
;<dLEN.l:データの長さ
;<aBUF.l:バッファのアドレス
;<a6.l:SPCベースアドレス
;>d0.l:0=正常終了,その他=INTS
datain_transfer:
push dLEN/aBUF
;長さが0のとき256と見なす
if <tst.l dLEN>,eq
move.w #256,dLEN
endif
;フェーズをセットする
move.b SPC_PSNS(aSPC),d0
andi.b #SPC_PHASE_MASK,d0
move.b d0,SPC_PCTL(aSPC)
;長さをセットする
move.l dLEN,d0
move.b d0,SPC_TCL(aSPC) ;データの長さ(下位)
lsr.l #8,d0
move.b d0,SPC_TCM(aSPC) ;データの長さ(中位)
lsr.l #8,d0
move.b d0,SPC_TCH(aSPC) ;データの長さ(上位)
;転送開始
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
move.b #SPC_SCMD_CC_TR,SPC_SCMD(aSPC)
bsr datain_dma ;SCSI入力(DMA転送)実行
if <tst.l d0>,eq
;割り込みを待つ
do
move.b SPC_INTS(aSPC),d0
while eq
move.b SPC_INTS(aSPC),SPC_INTS(aSPC) ;INTSをクリア
if <cmp.b #SPC_INTS_CC,d0>,eq
moveq.l #0,d0
endif
endif
pop
rts
;----------------------------------------------------------------
;SCSI入力(DMA転送)実行
datain_dma:
push d1/d2/a0/a3
~dcr = DMAC_NO_HOLD_CYCLE|DMAC_HD68000_COMPATIBLE|DMAC_8_BIT_PORT|DMAC_STATUS_INPUT
;X68000のSPCのDREQはDMACのREQ1に繋がっていない
;DREQを使ってDTACKが作られるのでオートリクエスト最大速度を用いる
~ocr = DMAC_DEVICE_TO_MEMORY|DMAC_UNPACKED_OPERAND|DMAC_NO_CHAINING|DMAC_AUTO_REQUEST_MAX
move.w #(~dcr<<8)|~ocr,d1
bsr cache_flush ;DMA転送開始直前のキャッシュフラッシュ
aDMAC reg a0
;DMAを設定する
lea.l DMAC_1_BASE,aDMAC
st.b DMAC_CSR(aDMAC) ;DMAC_CSRをクリア
clr.w DMAC_BTC(aDMAC)
move.b #DMAC_INCREMENT_MEMORY|DMAC_FIXED_DEVICE,DMAC_SCR(aDMAC)
lea.l SPC_DREG(aSPC),a3
move.l a3,DMAC_DAR(aDMAC)
;一度に転送する長さを決める
moveq.l #0,d2
move.w #256,d2
if <tst.b SRAM_SCSI_MODE>,mi ;SRAM_SCSI_BLOCK_BIT ブロック
moveq.l #0,d2
move.w BIOS_SCSI_BLOCK_SIZE.l,d2 ;SCSI機器のブロックサイズ
endif
;バーストにするか
.if SCSIEXROM==0
ifand <isX68030>,eq,<btst.b #SRAM_SCSI_BURST_BIT,SRAM_SCSI_MODE>,ne ;内蔵SCSIかつX68030かつバースト
~dcr = DMAC_NO_HOLD_CYCLE^DMAC_BURST_TRANSFER
~ocr = DMAC_AUTO_REQUEST_MAX^DMAC_EXTERNAL_REQUEST
eori.w #(~dcr<<8)|~ocr,d1
endif
.endif
;DMAC_DCRとDMAC_OCRを設定する
move.w d1,DMAC_DCR(aDMAC) ;DMAC_DCRとDMAC_OCR
aINTS reg a3
lea.l SPC_INTS(aSPC),aINTS
do
;<dLEN.l:今回の残りのデータの長さ
;<aBUF.l:今回のバッファのアドレス
if <cmp.l d2,dLEN>,ls ;残り1~ブロックサイズ
move.l dLEN,d2 ;今回転送する長さは残りのデータの長さ
endif
;<d2.l:今回転送する長さ
;今回のバッファのアドレスと今回転送する長さをDMAに設定する
move.l aBUF,DMAC_MAR(aDMAC) ;バッファのアドレス
move.w d2,DMAC_MTC(aDMAC) ;今回転送する長さ
datain_dma_continue:
;FIFOが空でなくなるまで待つ
do
goto <tst.b (aINTS)>,ne,datain_dma_interrupted ;SPC割り込みあり
while <btst.b #SPC_SSTS_DE_BIT,SPC_SSTS(aSPC)>,ne
;DMA転送開始
st.b DMAC_CSR(aDMAC) ;CSRをクリア
move.b #DMAC_CCR_STR,DMAC_CCR(aDMAC) ;DMA転送開始
tst.b (aINTS) ;空読み
;DMA転送終了を待つ
do
goto <tst.b (aINTS)>,ne,datain_dma_interrupted ;SPC割り込みあり
while <tst.b DMAC_CSR(aDMAC)>,pl ;DMAC_CSR_COC
;エラーがないか確認する
move.b DMAC_CER(aDMAC),d0
goto ne,datain_dma_error ;DMAエラーあり
;残りのデータの長さが0になるまで繰り返す
adda.l d2,aBUF ;次回のバッファのアドレス
sub.l d2,dLEN ;次回の残りのデータの長さ
while ne
moveq.l #0,d0
datain_dma_end:
;DMAC_DARをSASIに戻す
move.l #HDC_DATA,DMAC_DAR(aDMAC)
pop
rts
;DMAエラーあり
;<d0.b:DMAC_CER
datain_dma_error:
goto <cmp.b #DMAC_BUS_ERROR_DEVICE,d0>,eq,datain_dma_continue ;バスエラー
;バスエラー以外のDMAエラー
moveq.l #-1,d0
goto datain_dma_end
;SPC割り込みあり
datain_dma_interrupted:
move.b SPC_INTS(aSPC),d0
goto <cmpi.b #SPC_INTS_CC,d0>,ne,datain_dma_abort ;SPCが転送終了していない。転送中止
;SPCが転送終了した
moveq.l #0,d0
goto <tst.w DMAC_MTC(aDMAC)>,eq,datain_dma_abort ;DMAも転送終了した。転送中止
;SPCは転送終了したがDMAが転送終了していない
moveq.l #-2,d0
;転送中止
datain_dma_abort:
move.b #DMAC_CCR_SAB,DMAC_CCR(aDMAC) ;DMA転送中止
goto datain_dma_end
.endif
;----------------------------------------------------------------
; https://twitter.com/kamadox/status/1204687543200972805
; SUPERからCompactまでの内蔵SCSIはDMA転送を使っているが、SPCのDREQはDMAコントローラに繋がっておらず、
; 代わりにDTACKとBERRで転送のタイミングを制御している。
;
; [X68000 XVI Compact]
;
; MC68HC000 DOSA HD63450
; +-------------+ +-------------+ +-------------+
; | BERR|-----|BERR BEC0/1|-----|BEC0/1 REQ1|--+
; | DTACK|--+ +-------------+ +--|DTACK | |
; +-------------+ | ASA | +-------------+ |
; | +-------------+ | PEDEC |
; +--|MPUDTACK | | +-------------+ | MB89352
; | +--DMADTACK|--+ | HDREQ|--+ +-------------+
; | +-SYNCDTACK|-----|IOCDTK--SIREQ|-----|DREQ |
; +-------------+ +-------------+ +-------------+
;
; [X68030]
;
; MC68EC030 SAKI HD63450
; +-------------+ +-------------+ +-------------+
; | BERR|-----|BERR BEC0/1|-----|BEC0/1 REQ1|--+
; | DSACK0/1|--+ +-------------+ +--|DTACK | |
; +-------------+ | YUKI | +-------------+ |
; | +-------------+ | PEDEC |
; +--|DSACK0/1 | | +-------------+ | MB89352
; | +--DMADTACK|--+ | HDREQ|- | +-------------+
; | +-SYNCDTACK|-----|IOCDTK--SIREQ|--+--|DREQ |
; +-------------+ +-------------+ +-------------+
;
; DMAコントローラはSPCのDREGをアクセスするときDREQを外部転送要求として使えないので、
; オートリクエスト最大速度でアクセスして、バスを掴んだままDREQと連動しているDTACKを待つ。
; 一定時間内に転送できず、バスエラーで強制終了させられても、転送を継続するようにプログラムされている。
; MOなどの遅いデバイスへの書き込みで、バスエラーが宣告されるタイミングが悪いと、
; DMAコントローラが一旦引っ込めようとしたデータをSPCが送信してしまうことがある。
; そのまま継続すると同じデータが重複して送信される。初期のSCSI BIOSはこれが原因で書き込みに失敗することがあった。
; データの重複はバスエラーが発生したときDMAコントローラとSPCのカウンタを比較して転送を再開する位置を補正することで回避できる。
; GaoさんのFiloP.xを用いるか、Human68k version 3.0のFORMAT.Xでフォーマットしたハードディスクから起動すると対策が施される。
;----------------------------------------------------------------
;--------------------------------------------------------------------------------
; .include sc08cache.s
;--------------------------------------------------------------------------------
.if 10<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;DMA転送開始直前のキャッシュフラッシュ
cache_flush:
.if SCSI_BIOS_LEVEL<=10
move.l d0,-(sp)
if <cmpi.b #1,BIOS_MPU_TYPE.w>,hi
.cpu 68030
movec.l cacr,d0
or.w #$0808,d0
movec.l d0,cacr
and.w #$F7F7,d0
movec.l d0,cacr
.cpu 68000
endif
move.l (sp)+,d0
.else
if <cmpi.b #2,BIOS_MPU_TYPE.w>,hs ;020/030/040/060
if <cmpi.b #4,BIOS_MPU_TYPE.w>,lo ;020/030
move.l d0,-(sp)
.cpu 68030
;68030のcacr
;| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
;| 0| 0| WA|DBE| CD|CED| FD| ED| 0| 0| 0|IBE| CI|CEI| FI| EI|
;CDとCIは1を書き込むとキャッシュクリアで常に0で読み出される。0を書き込んでも意味がない
movec.l cacr,d0
or.w #$0808,d0
movec.l d0,cacr
.cpu 68000
move.l (sp)+,d0
else ;040/060
.cpu 68040
cpusha bc
.cpu 68000
endif
endif
.endif
rts
.endif
;--------------------------------------------------------------------------------
; .include sc09sasi.s
;--------------------------------------------------------------------------------
.if 10<=SCSI_BIOS_LEVEL
;----------------------------------------------------------------
;SASIハードディスクを初期化する
dskini_all:
push d0-d4/a1/a6
move.w #$8000,d1
moveq.l #16-1,d2
for d2
lea.l 0.w,a1
.if SCSI_BIOS_LEVEL<=10
bsr scsi_43_B_DSKINI ;IOCSコール$43 _B_DSKINI(SCSI)
.else
bsr iocs_43_B_DSKINI ;IOCSコール$43 _B_DSKINI
.endif
add.w #1<<8,d1
next
pop
rts
.endif
.if SCSI_BIOS_LEVEL<>10
;----------------------------------------------------------------
;SCSIバスに接続されているSASI機器をIOCSコール$40~$4Fで操作できるようにする
install_sasi_iocs:
push d0/d1/d2/d3/d4/a1/aSPC
moveq.l #_B_INTVCS,d0
move.w #$100+_B_SEEK,d1
lea.l iocs_40_B_SEEK(pc),a1 ;IOCSコール$40 _B_SEEK
trap #15
.if SCSI_BIOS_LEVEL<=10
move.l d0,(BIOS_SCSI_OLD_SEEK)abs ;IOCSコール$40 _B_SEEKの元のベクタ
.else
move.l d0,(BIOS_SCSI_OLD_SEEK_16)abs ;IOCSコール$40 _B_SEEKの元のベクタ
.endif
moveq.l #_B_INTVCS,d0
move.w #$100+_B_VERIFY,d1
lea.l iocs_41_B_VERIFY(pc),a1 ;IOCSコール$41 _B_VERIFY
trap #15
move.l d0,(BIOS_SCSI_OLD_VERIFY)abs ;IOCSコール$41 _B_VERIFYの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_DSKINI,d1
lea.l iocs_43_B_DSKINI(pc),a1 ;IOCSコール$43 _B_DSKINI
trap #15
move.l d0,(BIOS_SCSI_OLD_DSKINI)abs ;IOCSコール$43 _B_DSKINIの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_DRVSNS,d1
lea.l iocs_44_B_DRVSNS(pc),a1 ;IOCSコール$44 _B_DRVSNS
trap #15
move.l d0,(BIOS_SCSI_OLD_DRVSNS)abs ;IOCSコール$44 _B_DRVSNSの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_WRITE,d1
lea.l iocs_45_B_WRITE(pc),a1 ;IOCSコール$45 _B_WRITE
trap #15
move.l d0,(BIOS_SCSI_OLD_WRITE)abs ;IOCSコール$45 _B_WRITEの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_READ,d1
lea.l iocs_46_B_READ(pc),a1 ;IOCSコール$46 _B_READ
trap #15
move.l d0,(BIOS_SCSI_OLD_READ)abs ;IOCSコール$46 _B_READの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_RECALI,d1
lea.l iocs_47_B_RECALI(pc),a1 ;IOCSコール$47 _B_RECALI
trap #15
move.l d0,(BIOS_SCSI_OLD_RECALI)abs ;IOCSコール$47 _B_RECALIの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_ASSIGN,d1
lea.l iocs_48_B_ASSIGN(pc),a1 ;IOCSコール$48 _B_ASSIGN
trap #15
move.l d0,(BIOS_SCSI_OLD_ASSIGN)abs ;IOCSコール$48 _B_ASSIGNの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_BADFMT,d1
lea.l iocs_4B_B_BADFMT(pc),a1 ;IOCSコール$4B _B_BADFMT
trap #15
move.l d0,(BIOS_SCSI_OLD_BADFMT)abs ;IOCSコール$4B _B_BADFMTの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_FORMAT,d1
lea.l iocs_4D_B_FORMAT(pc),a1 ;IOCSコール$4D _B_FORMAT
trap #15
move.l d0,(BIOS_SCSI_OLD_FORMAT)abs ;IOCSコール$4D _B_FORMATの元のベクタ
moveq.l #_B_INTVCS,d0
move.w #$100+_B_EJECT,d1
lea.l iocs_4F_B_EJECT(pc),a1 ;IOCSコール$4F _B_EJECT
trap #15
move.l d0,(BIOS_SCSI_OLD_EJECT)abs ;IOCSコール$4F _B_EJECTの元のベクタ
;SASIハードディスクを初期化する
move.w #$8000,d1
moveq.l #16-1,d2
for d2
movea.l #0,a1
bsr iocs_43_B_DSKINI ;IOCSコール$43 _B_DSKINI
add.w #1<<8,d1
next
pop
rts
.endif
.if SCSI_BIOS_LEVEL<>10
;----------------------------------------------------------------
;IOCSコール$40 _B_SEEK シーク
iocs_40_B_SEEK:
move.l (BIOS_SCSI_OLD_SEEK)abs,-(sp) ;IOCSコール$40 _B_SEEKの元のベクタ
push d1/d4/a5
lea.l scsi_2D_S_SEEK(pc),a5 ;SCSIコール$2D _S_SEEK
goto iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;IOCSコール$47 _B_RECALI トラック0へのシーク
iocs_47_B_RECALI:
move.l (BIOS_SCSI_OLD_RECALI)abs,-(sp) ;IOCSコール$47 _B_RECALIの元のベクタ
push_again
lea.l scsi_2B_S_REZEROUNIT(pc),a5 ;SCSIコール$2B _S_REZEROUNIT
goto iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;IOCSコール$48 _B_ASSIGN
iocs_48_B_ASSIGN:
move.l (BIOS_SCSI_OLD_ASSIGN)abs,-(sp) ;IOCSコール$48 _B_ASSIGNの元のベクタ
push_again
lea.l scsi_39_S_ASSIGN(pc),a5 ;SCSIコール$39 _S_ASSIGN
goto iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;IOCSコール$4B _B_BADFMT バッドトラックを使用不能にする
iocs_4B_B_BADFMT:
move.l (BIOS_SCSI_OLD_BADFMT)abs,-(sp) ;IOCSコール$4B _B_BADFMTの元のベクタ
push_again
lea.l scsi_38_S_BADFMT(pc),a5 ;SCSIコール$38 _S_BADFMT
goto iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;IOCSコール$4D _B_FORMAT 物理フォーマット
iocs_4D_B_FORMAT:
move.l (BIOS_SCSI_OLD_FORMAT)abs,-(sp) ;IOCSコール$4D _B_FORMATの元のベクタ
push_again
lea.l scsi_37_S_FORMATB(pc),a5 ;SCSIコール$37 _S_FORMATB
goto iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;IOCSコール$44 _B_DRVSNS
iocs_44_B_DRVSNS:
move.l (BIOS_SCSI_OLD_DRVSNS)abs,-(sp) ;IOCSコール$44 _B_DRVSNSの元のベクタ
push_again
lea.l scsi_24_S_TESTUNIT(pc),a5 ;SCSIコール$24 _S_TESTUNIT
;!!! 直後へのbra。サイズを書かないと削除される
bra.w iocs_40_44_47_48_4b_4d_common ;IOCSコール$40~$4Fの処理
;----------------------------------------------------------------
;ここから_B_SEEK、_B_RECALI、_B_ASSIGN、_B_BADFMT、_B_FORMAT、_B_DRVSNS共通
iocs_40_44_47_48_4b_4d_common:
.else
;----------------------------------------------------------------
;IOCSコール$40 _B_SEEK シーク
scsi_40_B_SEEK:
lea.l scsi_2D_S_SEEK(pc),a0 ;SCSIコール$2D _S_SEEK
goto scsi_40_44_47_48_4b_4d_common ;IOCSコール$40~$4F(SCSI)の処理
;----------------------------------------------------------------
;IOCSコール$47 _B_RECALI トラック0へのシーク
scsi_47_B_RECALI:
lea.l scsi_2B_S_REZEROUNIT(pc),a0 ;SCSIコール$2B _S_REZEROUNIT
goto scsi_40_44_47_48_4b_4d_common ;IOCSコール$40~$4F(SCSI)の処理
;----------------------------------------------------------------
;IOCSコール$48 _B_ASSIGN
scsi_48_B_ASSIGN:
lea.l scsi_39_S_ASSIGN(pc),a0 ;SCSIコール$39 _S_ASSIGN
goto scsi_40_44_47_48_4b_4d_common ;IOCSコール$40~$4F(SCSI)の処理
;----------------------------------------------------------------
;IOCSコール$4B _B_BADFMT バッドトラックを使用不能にする
scsi_4B_B_BADFMT:
lea.l scsi_38_S_BADFMT(pc),a0 ;SCSIコール$38 _S_BADFMT
goto scsi_40_44_47_48_4b_4d_common ;IOCSコール$40~$4F(SCSI)の処理
;----------------------------------------------------------------
;IOCSコール$4D _B_FORMAT 物理フォーマット
scsi_4D_B_FORMAT:
lea.l scsi_37_S_FORMATB(pc),a0 ;SCSIコール$37 _S_FORMATB
goto scsi_40_44_47_48_4b_4d_common ;IOCSコール$40~$4F(SCSI)の処理
;----------------------------------------------------------------
;IOCSコール$44 _B_DRVSNS
scsi_44_B_DRVSNS:
lea.l scsi_24_S_TESTUNIT(pc),a0 ;SCSIコール$24 _S_TESTUNIT
;----------------------------------------------------------------
;ここから_B_SEEK、_B_RECALI、_B_ASSIGN、_B_BADFMT、_B_FORMAT、_B_DRVSNS共通
scsi_40_44_47_48_4b_4d_common:
push d1/d4/a5
movea.l a0,a5
.endif
moveq.l #0,d4
move.w d1,d4
.if SCSI_BIOS_LEVEL<>10
andi.w #$F000,d1
goto <cmp.w #$8000,d1>,ne,iocs_40_44_47_48_4b_4d_not_hd ;HDではない
.endif
lsr.w #8,d4
lsr.w #1,d4 ;SCSI-ID=HD-ID/2
if cs
bset.l #16,d4 ;LUN=HD-ID%2
endif
andi.w #7,d4 ;SCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,eq,scsi_40_44_47_48_4b_4d_not_sasi ;SASIフラグがセットされていない
jsr (a5) ;SCSIコールを呼ぶ
;<d0.l:0=成功,-1=失敗,その他=MSGIN<<16|STSIN
.if SCSI_BIOS_LEVEL<>10
.if SCSI_BIOS_LEVEL<=10
.if 4<=SCSI_BIOS_LEVEL
andi.l #$FFFFFF1E,d0 ;SASIのステータスバイトの一部を無視する
.endif
goto <tst.l d0>,ne,scsi_40_44_47_48_4b_4d_error
.else
goto <btst.l #1,d0>,ne,scsi_40_44_47_48_4b_4d_error ;Check Condition
.endif
moveq.l #0,d0
pop_test
addq.l #4,sp ;元の処理を呼ばない
rts
scsi_40_44_47_48_4b_4d_error:
ori.l #$FFFFFF00,d0
pop_test
addq.l #4,sp ;元の処理を呼ばない
rts
;SASIフラグがセットされていない
scsi_40_44_47_48_4b_4d_not_sasi:
;HDではない
iocs_40_44_47_48_4b_4d_not_hd:
pop
rts ;元の処理を呼ぶ
.else
goto <btst.l #1,d0>,ne,scsi_40_44_47_48_4b_4d_error ;Check Condition
moveq.l #0,d0
scsi_40_44_47_48_4b_4d_end:
pop
rts
;SASIフラグがセットされていない
scsi_40_44_47_48_4b_4d_not_sasi:
moveq.l #-1,d0
scsi_40_44_47_48_4b_4d_error:
ori.l #$FFFFFF00,d0
goto scsi_40_44_47_48_4b_4d_end
.endif
;----------------------------------------------------------------
;IOCSコール$4F _B_EJECT イジェクト/シッピング
;<d1.w:
; FD $9000|FD-ID(0~3)<<8|MFM(0~1)<<6|RETRY(0~1)<<5|SEEK(0~1)<<4
; HD $8000|HD-ID(0~15)<<8
; HD-ID(0~15)=SCSI-ID(0~7)<<1|LUN(0~1)
;>d0.l:
; FD 不定
; HD 0以上=成功,-1以下=失敗
.if SCSI_BIOS_LEVEL<>10
iocs_4F_B_EJECT:
move.l (BIOS_SCSI_OLD_EJECT)abs,-(sp)
.else
scsi_4F_B_EJECT:
.endif
push d1/d2/d3/d4/d5/d6/d7/a1/a4
moveq.l #0,d4
move.w d1,d4
.if SCSI_BIOS_LEVEL<>10
andi.w #$F000,d1
goto <cmp.w #$8000,d1>,ne,iocs_4f_not_hd ;HDではない
.endif
move.l d4,d1
lsr.w #8,d4
lsr.w #1,d4 ;SCSI-ID=HD-ID/2
if cs
bset.l #16,d4 ;LUN=HD-ID%2
endif
andi.w #7,d4 ;SCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,eq,scsi_4f_not_sasi ;SASIフラグがセットされていない
.if SCSI_BIOS_LEVEL<=4
lea.l BIOS_SASI_CAPACITY.l,a4 ;SASIハードディスクの容量の配列。0=未確認,10=10MB,20=20MB,40=40MB,128=非接続
move.l d1,d0
ror.w #8,d0
and.l #15,d0 ;HD-ID
adda.l d0,a4
move.b (a4),d0
if <btst.l #7,d0>,eq ;接続
and.b #$7F,d0
if ne ;確認済み
move.l #33*4*664,d2 ;20MBシッピングゾーン
;!!! 不要
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_20mb_shipping_parameter,a1 ;20MBドライブパラメータ(シッピングゾーン)
.else
lea.l sasi_20mb_shipping_parameter(pc),a1 ;20MBドライブパラメータ(シッピングゾーン)
.endif
if <cmp.b #20,d0>,ne ;20MB
move.l #33*8*664,d2 ;40MBシッピングゾーン
;!!! 不要
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_40mb_shipping_parameter,a1 ;40MBドライブパラメータ(シッピングゾーン)
.else
lea.l sasi_40mb_shipping_parameter(pc),a1 ;40MBドライブパラメータ(シッピングゾーン)
.endif
if <cmp.b #40,d0>,ne ;40MB
move.l #33*4*340,d2 ;10MBシッピングゾーン
;!!! 不要
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_10mb_shipping_parameter,a1 ;10MBドライブパラメータ(シッピングゾーン)
.else
lea.l sasi_10mb_shipping_parameter(pc),a1 ;10MBドライブパラメータ(シッピングゾーン)
.endif
endif
endif
;!!! ROM 1.0~1.2のSASI BIOSの_B_EJECTはシッピングゾーンをSET DRIVE PARAMETERしてからSEEKしている
bsr scsi_2D_S_SEEK ;SCSIコール$2D _S_SEEK
endif
endif
;非接続または未確認
;+++++ BUG +++++
;内蔵SASIハードディスクをシッピングできなくなる
; SASIフラグがセットされていないとき内蔵SASIハードディスクをシッピングしなければならないのに元の処理を呼んでいない
;SASIフラグがセットされていない
scsi_4f_not_sasi:
;+++++ BUG +++++
pop_test
addq.l #4,sp ;元の処理を呼ばない
rts
;HDではない
iocs_4f_not_hd:
pop
rts ;元の処理を呼ぶ
;+++++ BUG +++++
;どこからも参照されていない
andi.w #$F000,d1
if <cmp.w #$8000,d1>,eq
movem.l (sp)+,d1
addq.l #4,sp
moveq.l #0,d0
rts
endif
movem.l (sp)+,d1
rts
;+++++ BUG +++++
.else
lea.l BIOS_SASI_CAPACITY.w,a4 ;SASIハードディスクの容量の配列。0=未確認,10=10MB,20=20MB,40=40MB,128=非接続
move.w d1,d0
ror.w #8,d0
and.w #15,d0 ;HD-ID
move.b (a4,d0.w),d0
;!!! 不要
ifand <tst.b d0>,pl,<>,ne
;接続、確認済み
move.l #33*4*664,d2 ;20MBシッピングゾーン
if <cmp.b #20,d0>,ne
move.l #33*8*664,d2 ;40MBシッピングゾーン
if <cmp.b #40,d0>,ne
move.l #33*4*340,d2 ;10MBシッピングゾーン
if <cmp.b #10,d0>,ne
goto scsi_4f_end ;10MB/20MB/40MBのいずれでもない
endif
endif
endif
;!!! ROM 1.0~1.2のSASI BIOSの_B_EJECTはシッピングゾーンをSET DRIVE PARAMETERしてからSEEKしている
bsr scsi_2D_S_SEEK ;SCSIコール$2D _S_SEEK
moveq.l #0,d0
endif
;非接続または未確認
scsi_4f_end:
.if SCSI_BIOS_LEVEL<=10
;SASIフラグがセットされていない
scsi_4f_not_sasi:
pop
rts
.else
pop_test
addq.l #4,sp ;元の処理を呼ばない
rts
;SASIフラグがセットされていない
scsi_4f_not_sasi:
;HDではない
iocs_4f_not_hd:
pop
rts ;元の処理を呼ぶ
.endif
.endif
;----------------------------------------------------------------
;IOCSコール$46 _B_READ 読み出し
;<d1.w:ドライブ
; HD $8000|HD-ID(0~15)<<8
; HD-ID(0~15)=SCSI-ID(0~7)<<1|LUN(0~1)
; FD $9000|FD-ID(0~3)<<8|MFM(0~1)<<6|RETRY(0~1)<<5|SEEK(0~1)<<4
;<d2.l:位置
; HD レコード番号
; FD レコード長(0~7)<<24|シリンダ番号(0~)<<16|ヘッド番号(0~1)<<8|セクタ番号(1~)
;<d3.l:バイト数
;<a1.l:アドレス
;>d0.l:結果
; HD 0以上=成功,-1以下=失敗。$FFFFFF00|エラーコード=失敗
; FD ST0<<24|ST1<<16|ST2<<8|シリンダ番号
;----------------------------------------------------------------
;IOCSコール$45 _B_WRITE 書き込み
;<d1.w:ドライブ
; HD $8000|HD-ID(0~15)<<8
; HD-ID(0~15)=SCSI-ID(0~7)<<1|LUN(0~1)
; FD $9000|FD-ID(0~3)<<8|MFM(0~1)<<6|RETRY(0~1)<<5|SEEK(0~1)<<4
;<d2.l:位置
; HD レコード番号
; FD レコード長(0~7)<<24|シリンダ番号(0~)<<16|ヘッド番号(0~1)<<8|セクタ番号(1~)
;<d3.l:バイト数
;<a1.l:アドレス
;>d0.l:結果
; HD 0以上=成功,$FFFFFF00|STSIN=失敗
; FD ST0<<24|ST1<<16|ST2<<8|シリンダ番号
.if SCSI_BIOS_LEVEL<>10
iocs_46_B_READ:
move.l (BIOS_SCSI_OLD_READ)abs,-(sp) ;IOCSコール$46 _B_READの元のベクタ
push d1/d2/d3/d4/d5/d6/a1/a2/a5
lea.l scsi_21_S_READ(pc),a5 ;SCSIコール$21 _S_READ
goto iocs_45_46_common ;ここから_B_READ、_B_WRITE共通
iocs_45_B_WRITE:
move.l (BIOS_SCSI_OLD_WRITE)abs,-(sp) ;IOCSコール$45 _B_WRITEの元のベクタ
push_again
lea.l scsi_22_S_WRITE(pc),a5 ;SCSIコール$22 _S_WRITE
;!!! 直後へのbra。サイズを書かないと削除される
bra.w iocs_45_46_common ;ここから_B_READ、_B_WRITE共通
;ここから_B_READ、_B_WRITE共通
;<a5.l:_S_READまたは_S_WRITE
iocs_45_46_common:
.else
scsi_46_B_READ:
lea.l scsi_21_S_READ(pc),a0 ;SCSIコール$21 _S_READ
goto scsi_45_46_common ;ここから_B_READ(SCSI)、_B_WRITE(SCSI)共通
scsi_45_B_WRITE:
lea.l scsi_22_S_WRITE(pc),a0 ;SCSIコール$22 _S_WRITE
;ここから_B_READ、_B_WRITE共通
;<a0.l:_S_READまたは_S_WRITE
scsi_45_46_common:
push d1/d2/d3/d4/d5/d6/a1/a2/a5
movea.l a0,a5 ;_S_READまたは_S_WRITE
.endif
moveq.l #0,d4
move.w d1,d4
.if SCSI_BIOS_LEVEL<>10
andi.w #$F000,d1
goto <cmp.w #$8000,d1>,ne,iocs_45_46_not_hd ;HDではない
.endif
lsr.w #8,d4
lsr.w #1,d4 ;SCSI-ID=HD-ID/2
if cs
bset.l #16,d4 ;LUN=HD-ID%2
endif
andi.w #7,d4 ;SCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,eq,scsi_45_46_not_sasi ;SASIフラグがセットされていない
move.l d3,d6 ;残りのバイト数
do
move.l d6,d3 ;残りのバイト数
add.l #255,d3
lsr.l #8,d3 ;今回のレコード数。256バイト/レコード
if <cmp.l #256,d3>,hi
move.l #256,d3 ;一度に転送するレコード数の上限
endif
moveq.l #0,d5 ;レコード長。0=256バイト/レコード
jsr (a5) ;_S_READまたは_S_WRITE
.if SCSI_BIOS_LEVEL<=3
;+++++ BUG +++++
;_S_READまたは_S_WRITEがエラーをzで返さないと検出できない
;+++++ BUG +++++
goto ne,scsi_45_46_error
.elif SCSI_BIOS_LEVEL<=4
andi.l #$FFFFFF1E,d0 ;SASIのステータスバイトの一部を無視する
goto <tst.l d0>,ne,scsi_45_46_error
.else
goto <btst.l #1,d0>,ne,scsi_45_46_error ;Check Condition
.endif
add.l d3,d2 ;次回のレコード番号
move.l d3,d1
lsl.l #8,d1 ;今回のバイト数
adda.l d1,a1 ;次回のアドレス
sub.l d1,d6 ;次回の残りのバイト数
while hi
.if SCSI_BIOS_LEVEL<>10
pop_test
addq.l #4,sp ;元の処理を呼ばない
moveq.l #0,d0
rts
scsi_45_46_error:
pop_test
addq.l #4,sp ;元の処理を呼ばない
ori.l #$FFFFFF00,d0
rts
;SASIフラグがセットされていない
scsi_45_46_not_sasi:
;HDではない
iocs_45_46_not_hd:
pop
rts ;元の処理を呼ぶ
.else
moveq.l #0,d0
scsi_45_46_end:
pop
rts
;SASIフラグがセットされていない
scsi_45_46_not_sasi:
moveq.l #-1,d0
scsi_45_46_error:
ori.l #$FFFFFF00,d0
goto scsi_45_46_end
.endif
;----------------------------------------------------------------
;IOCSコール$41 _B_VERIFY ベリファイ
;<d1.w:ドライブ
; HD $8000|HD-ID(0~15)<<8
; HD-ID(0~15)=SCSI-ID(0~7)<<1|LUN(0~1)
; FD $9000|FD-ID(0~3)<<8|MFM(0~1)<<6|RETRY(0~1)<<5|SEEK(0~1)<<4
;<d2.l:位置
; HD レコード番号
; FD レコード長(0~7)<<24|シリンダ番号(0~)<<16|ヘッド番号(0~1)<<8|セクタ番号(1~)
;<d3.l:バイト数
;<a1.l:アドレス
;>d0.l:結果
; HD 0=一致,-2=不一致
; FD ST0<<24|PCN<<16
.if SCSI_BIOS_LEVEL<>10
iocs_41_B_VERIFY:
.else
scsi_41_B_VERIFY:
.endif
link.w a4,#-256
push d1/d2/d3/d4/d5/d6/a1/a2
moveq.l #0,d4
move.w d1,d4
.if SCSI_BIOS_LEVEL<>10
andi.w #$F000,d1
goto <cmp.w #$8000,d1>,ne,iocs_b_verify_not_hd ;HDではない
move.l d4,d1
.endif
lsr.w #8,d4
lsr.w #1,d4 ;SCSI-ID=HD-ID/2
if cs
bset.l #16,d4 ;LUN=HD-ID%2
endif
andi.w #7,d4 ;SCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,eq,scsi_b_verify_not_sasi ;SASIフラグがセットされていない
movea.l a1,a2 ;アドレス
move.l d3,d6 ;残りのバイト数
do
move.l d6,d3 ;残りのバイト数
if <cmp.l #256,d3>,cc
move.l #256,d3 ;一度に読み込むバイト数の上限。256バイト/レコード
endif
;!!! スーパーバイザスタックに読み込んでいる。ローカルメモリがあるときDMAが届くとは限らない
lea.l -256(a4),a1
.if SCSI_BIOS_LEVEL<>10
bsr iocs_46_B_READ ;IOCSコール$46 _B_READ 読み出し
.else
bsr scsi_46_B_READ ;IOCSコール$46 _B_READ(SCSI) 読み出し
.endif
move.l d3,d5
subq.l #1,d5
for d5
cmpm.b (a1)+,(a2)+
goto ne,scsi_b_verify_error ;不一致
next
addq.l #1,d2 ;次回のレコード番号
sub.l d3,d6 ;次回の残りのバイト数
while hi
.if SCSI_BIOS_LEVEL<>10
pop_test
unlk a4
moveq.l #0,d0 ;一致
rts ;元の処理を呼ばない
scsi_b_verify_error:
moveq.l #-2,d0 ;不一致
pop_test
unlk a4
ori.l #$FFFFFF00,d0 ;-2のまま
rts ;元の処理を呼ばない
;SASIフラグがセットされていない
scsi_b_verify_not_sasi:
;HDではない
iocs_b_verify_not_hd:
pop
unlk a4
move.l (BIOS_SCSI_OLD_VERIFY)abs,-(sp) ;IOCSコール$41 _B_VERIFYの元のベクタ
rts ;元の処理を呼ぶ
.else
moveq.l #0,d0 ;一致
scsi_b_verify_end:
pop
unlk a4
rts
scsi_b_verify_error:
moveq.l #-2,d0 ;不一致
ori.l #$FFFFFF00,d0 ;-2のまま
goto scsi_b_verify_end
;SASIフラグがセットされていない
scsi_b_verify_not_sasi:
moveq.l #-1,d0
goto scsi_b_verify_end
.endif
;----------------------------------------------------------------
;IOCSコール$43 _B_DSKINI 初期化
;<d1.w:ドライブ
; HD $8000|HD-ID(0~15)<<8
; HD-ID(0~15)=SCSI-ID(0~7)<<1|LUN(0~1)
; FD $9000|FD-ID(0~3)<<8
;<d2.w:
; HD なし
; FD モーター停止時間(10ms単位)。0=デフォルト(2秒)
;<a1.l:
; HD ドライブパラメータのアドレス。0=デフォルト
; FD Specifyコマンドのアドレス。0=デフォルト
;>d0.l:結果
; HD 0=成功,$FFFFFF00|STSIN=失敗
; FD ST3<<24|不定
.if SCSI_BIOS_LEVEL<>10
iocs_43_B_DSKINI:
.else
scsi_43_B_DSKINI:
.endif
link.w a4,#-256
.if SCSI_BIOS_LEVEL<=10
;+++++ BUG +++++
;d5/a2を破壊している
push d1/d2/d3/d4/a1/a5
;+++++ BUG +++++
.else
push d1/d2/d3/d4/d5/a1/a2/a5
.endif
moveq.l #0,d4
move.w d1,d4
.if SCSI_BIOS_LEVEL<>10
andi.w #$F000,d1
goto <cmp.w #$8000,d1>,ne,iocs_b_dskini_not_hd ;HDではない
.endif
lsr.w #8,d4
lsr.w #1,d4 ;SCSI-ID=HD-ID/2
if cs
bset.l #16,d4 ;LUN=HD-ID%2
endif
andi.w #7,d4 ;SCSI-ID
goto <btst.b d4,SRAM_SCSI_SASI_FLAG>,eq,scsi_b_dskini_not_sasi ;SASIフラグがセットされていない
move.l a1,d0 ;初期化パラメータ
goto eq,scsi_b_dskini_default ;デフォルトのドライブパラメータを使う
scsi_b_dskini_go:
moveq.l #10,d3 ;ドライブパラメータの長さ。10バイト
bsr scsi_36_S_DSKINI ;SCSIコール$36 _S_DSKINI
.if SCSI_BIOS_LEVEL<>10
.if SCSI_BIOS_LEVEL<=10
.if 4<=SCSI_BIOS_LEVEL
andi.l #$FFFFFF1E,d0 ;SASIのステータスバイトの一部を無視する
.endif
goto <tst.l d0>,ne,scsi_b_dskini_error ;失敗
.else
goto <btst.l #1,d0>,ne,scsi_b_dskini_error ;Check Condition
.endif
.if SCSI_BIOS_LEVEL<=3
;!!! このbsrは$617Eで届くが$61000080になっている
bsr.w sasi_param_to_capacity ;ドライブパラメータからSASIハードディスクの容量を求める
.else
bsr sasi_param_to_capacity ;ドライブパラメータからSASIハードディスクの容量を求める
.endif
moveq.l #0,d0
pop_test
unlk a4
rts ;元の処理を呼ばない
;失敗
scsi_b_dskini_error:
ori.l #$FFFFFF00,d0
pop_test
unlk a4
rts ;元の処理を呼ばない
;SASIフラグがセットされていない
scsi_b_dskini_not_sasi:
;HDではない
iocs_b_dskini_not_hd:
pop
unlk a4
move.l (BIOS_SCSI_OLD_DSKINI)abs,-(sp) ;IOCSコール$43 _B_DSKINIの元のベクタ
rts ;元の処理を呼ぶ
.else
goto <btst.l #1,d0>,ne,scsi_b_dskini_error ;Check Condition
;ドライブパラメータからSASIハードディスクの容量を求める
lea.l BIOS_SASI_CAPACITY.w,a5 ;SASIハードディスクの容量の配列。0=未確認,10=10MB,20=20MB,40=40MB,128=非接続
move.w d1,d0
ror.w #8,d0
and.w #15,d0 ;HD-ID
adda.w d0,a5
moveq.l #40,d0 ;40MB
if <cmpi.b #$07,3(a1)>,ne
moveq.l #20,d0 ;20MB
if <cmpi.b #$02,4(a1)>,ne
moveq.l #10,d0 ;10MB
endif
endif
move.b d0,(a5)
moveq.l #0,d0
scsi_b_dskini_end:
pop
unlk a4
rts
;SASIフラグがセットされていない
scsi_b_dskini_not_sasi:
moveq.l #-1,d0
;Check Condition
scsi_b_dskini_error:
ori.l #$FFFFFF00,d0
goto scsi_b_dskini_end
.endif
;デフォルトのドライブパラメータを使う
scsi_b_dskini_default:
moveq.l #10,d3 ;ドライブパラメータの長さ。10バイト
.if SCSI_BIOS_LEVEL<=4
;20MBドライブパラメータ(シッピングゾーン)を設定する
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_20mb_shipping_parameter,a1 ;20MBドライブパラメータ(シッピングゾーン)
.else
lea.l sasi_20mb_shipping_parameter(pc),a1 ;20MBドライブパラメータ(シッピングゾーン)
.endif
.else
;40MBドライブパラメータ(シッピングゾーン)を設定する
lea.l sasi_40mb_shipping_parameter(pc),a1 ;40MBドライブパラメータ(シッピングゾーン)
.endif
bsr scsi_36_S_DSKINI ;SCSIコール$36 _S_DSKINI
.if SCSI_BIOS_LEVEL<=4
.if 4<=SCSI_BIOS_LEVEL
andi.l #$FFFFFF1E,d0 ;SASIのステータスバイトの一部を無視する
.endif
goto <tst.l d0>,ne,scsi_b_dskini_error
.else ;10<=SCSI_BIOS_LEVEL
goto <btst.l #1,d0>,ne,scsi_b_dskini_error ;Check Condition
.endif
;レコード4から256バイト読み込む
lea.l -256(a4),a1
moveq.l #$0400/256,d2
moveq.l #$0100/256,d3
moveq.l #0,d5 ;256バイト/レコード
bsr scsi_21_S_READ ;SCSIコール$21 _S_READ
.if SCSI_BIOS_LEVEL<=4
.if 4<=SCSI_BIOS_LEVEL
andi.l #$FFFFFF1E,d0 ;SASIのステータスバイトの一部を無視する
.endif
goto <tst.l d0>,ne,scsi_b_dskini_error ;読み込めない
.else ;10<=SCSI_BIOS_LEVEL
goto <btst.l #1,d0>,ne,scsi_b_dskini_error ;Check Condition
.endif
lea.l -256(a4),a2
.if SCSI_BIOS_LEVEL<=4
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_10mb_drive_parameter,a1 ;10MBドライブパラメータ
.else
lea.l sasi_10mb_drive_parameter(pc),a1 ;10MBドライブパラメータ
.endif
goto <cmpi.l #'X68K',0.w(a2)>,ne,scsi_b_dskini_error ;装置初期化されていない
;装置初期化されている
.if SCSI_BIOS_LEVEL<=0
lea.l sasi_10mb_drive_parameter,a1 ;10MBドライブパラメータ
.else
lea.l sasi_10mb_drive_parameter(pc),a1 ;10MBドライブパラメータ
.endif
move.l 4(a2),d0 ;レコード数
.else ;10<=SCSI_BIOS_LEVEL
goto <cmpi.l #'X68K',(a2)+>,ne,scsi_b_dskini_error ;装置初期化されていない
;装置初期化されている
lea.l sasi_10mb_drive_parameter(pc),a1 ;10MBドライブパラメータ
move.l (a2),d0 ;レコード数
.endif
goto <cmp.l #33*4*310+1,d0>,cs,scsi_b_dskini_go ;10MBは309シリンダだが310シリンダまで10MBと見なす
lea.l sasi_20mb_drive_parameter-sasi_10mb_drive_parameter(a1),a1 ;20MBドライブパラメータ
goto <cmp.l #33*4*615+1,d0>,cs,scsi_b_dskini_go ;20MBは614シリンダだが615シリンダまで20MBと見なす
lea.l sasi_40mb_drive_parameter-sasi_20mb_drive_parameter(a1),a1 ;40MBドライブパラメータ
goto scsi_b_dskini_go
.if SCSI_BIOS_LEVEL<>10
;----------------------------------------------------------------
;ドライブパラメータからSASIハードディスクの容量を求める
;<d1.w:HD-ID<<8
;<a1.l:ドライブパラメータ
sasi_param_to_capacity:
lea.l BIOS_SASI_CAPACITY.l,a5 ;SASIハードディスクの容量の配列。0=未確認,10=10MB,20=20MB,40=40MB,128=非接続
move.l d1,d0
ror.w #8,d0
and.l #15,d0 ;HD-ID
adda.l d0,a5
move.b #40,d0 ;40MB
if <cmpi.b #$07,3(a1)>,ne
move.b #20,d0 ;20MB
if <cmpi.b #$02,4(a1)>,ne
move.b #10,d0 ;10MB
endif
endif
move.b d0,(a5)
clr.l d0
rts
.endif
.if SCSI_BIOS_LEVEL<=0
;----------------------------------------------------------------
;Test Unit Readyコマンド
test_unit_ready_command:
.dc.b $00 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Rezero Unitコマンド
rezero_unit_command:
.dc.b $01 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Read(6)コマンド
read_6_command_2nd:
.dc.b $08 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Read Capacityコマンド
read_capacity_command:
.dc.b $25 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 Reserved
.dc.b $00 ;8 Reserved#######|PMI
.dc.b $00 ;9 コントロールバイト
;----------------------------------------------------------------
;Inquiryコマンド
inquiry_command:
.dc.b $12 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|EVPD
.dc.b $00 ;2 ページコード
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Request Senseコマンド
request_sense_command:
.dc.b $03 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Mode Sense(6)コマンド
mode_sense_6_command:
.dc.b $1A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|R|DBD|Reserved###
.dc.b $00 ;2 PC##|ページコード######
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 アロケーション長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Mode Select(6)コマンド
mode_select_6_command:
.dc.b $15 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|PF|Reserved###|SP
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 パラメータリスト長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Reassign Blocksコマンド
reassign_blocks_command:
.dc.b $07 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Read(6)コマンド
read_6_command:
.dc.b $08 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Write(6)コマンド
write_6_command:
.dc.b $0A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|論理ブロックアドレス(上位)#####
.dc.b $00 ;2 論理ブロックアドレス(中位)
.dc.b $00 ;3 論理ブロックアドレス(下位)
.dc.b $00 ;4 転送データ長
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Read(10)コマンド
read_10_command:
.dc.b $28 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|FUA|Reserved##|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
;----------------------------------------------------------------
;Write(10)コマンド
write_10_command:
.dc.b $2A ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|FUA|Reserved##|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
;----------------------------------------------------------------
;Verify(10)コマンド
verify_10_command:
.dc.b $2F ;0 オペレーションコード
.dc.b $00 ;1 LUN###|DPO|Reserved##|BytChk|RelAdr
.dc.b $00 ;2 論理ブロックアドレス(上位)
.dc.b $00 ;3 :
.dc.b $00 ;4 :
.dc.b $00 ;5 論理ブロックアドレス(下位)
.dc.b $00 ;6 Reserved
.dc.b $00 ;7 転送データ長(上位)
.dc.b $00 ;8 転送データ長(下位)
.dc.b $00 ;9 コントロールバイト
;----------------------------------------------------------------
;Prevent-Allow Medium Removalコマンド
prevent_allow_command:
.dc.b $1E ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved#####
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved#######|Prevent
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Start-Stop Unit(Eject SONY MO)コマンド
start_stop_unit_command:
.dc.b $1B ;0 オペレーションコード
.dc.b $00 ;1 LUN###|Reserved####|Immed
.dc.b $00 ;2 Reserved
.dc.b $00 ;3 Reserved
.dc.b $00 ;4 Reserved######|LoEj|Start
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Load/Unload SHARP MOコマンド
load_unload_command:
.dc.b $C1 ;0 オペレーションコード
.dc.b $00 ;1 LUN###|#####
.dc.b $00 ;2
.dc.b $00 ;3
.dc.b $00 ;4 #######|LoEj
.dc.b $00 ;5
;----------------------------------------------------------------
;Seek(6)コマンド
seek_6_command:
.dc.b $0B ;0 オペレーションコード
.dc.b $00 ;1 LUN###|ブロック番号(上位)#####
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 Reserved
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Assign Drive(SASI)コマンド
assign_drive_sasi_command:
.dc.b $C2 ;0 オペレーションコード
.dc.b $00 ;1
.dc.b $00 ;2
.dc.b $00 ;3
.dc.b $00 ;4
.dc.b $00 ;5 データの長さ
;----------------------------------------------------------------
;Format Block(SASI)コマンド
format_block_sasi_command:
.dc.b $06 ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5
;----------------------------------------------------------------
;Bad Track Format(SASI)コマンド
bad_track_format_sasi_command:
.dc.b $07 ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5 コントロールバイト
;----------------------------------------------------------------
;Assign Track(SASI)コマンド
assign_track_sasi_command:
.dc.b $0E ;0 オペレーションコード
.dc.b $00 ;1 ブロック番号(上位)
.dc.b $00 ;2 ブロック番号(中位)
.dc.b $00 ;3 ブロック番号(下位)
.dc.b $00 ;4 インタリーブ
.dc.b $00 ;5
.endif
;----------------------------------------------------------------
;10MBドライブパラメータ
sasi_10mb_drive_parameter:
.dc.b $01,$01,$00,$03,$01,$35,$80,$00,$00,$00
; ~~~~~~~309
; ~~~4-1
.if SCSI_BIOS_LEVEL<>10
;10MBドライブパラメータ(シッピングゾーン)
sasi_10mb_shipping_parameter:
.dc.b $01,$01,$00,$03,$01,$54,$80,$00,$00,$00
; ~~~~~~~340
; ~~~4-1
.endif
;20MBドライブパラメータ
sasi_20mb_drive_parameter:
.dc.b $01,$01,$00,$03,$02,$66,$80,$00,$00,$00
; ~~~~~~~614
; ~~~4-1
.if SCSI_BIOS_LEVEL<>10
;20MBドライブパラメータ(シッピングゾーン)
sasi_20mb_shipping_parameter:
.dc.b $01,$01,$00,$03,$02,$98,$80,$00,$00,$00
; ~~~~~~~664
; ~~~4-1
.endif
;40MBドライブパラメータ
sasi_40mb_drive_parameter:
.dc.b $01,$01,$00,$07,$02,$66,$80,$00,$00,$00
; ~~~~~~~614
; ~~~8-1
;40MBドライブパラメータ(シッピングゾーン)
sasi_40mb_shipping_parameter:
.dc.b $01,$01,$00,$07,$02,$98,$80,$00,$00,$00
; ~~~~~~~664
; ~~~8-1
;----------------------------------------------------------------
;SASIハードディスク
;
; 物理構成
; 10MB 20MB 40MB
; 256 256 256 バイト/レコード
; 33 33 33 レコード/トラック
; 4 4 8 トラック/シリンダ
; 309 614 614 シリンダ/ボリューム
; 340 664 664 シッピングゾーン
;
; SASIディスクIPL
; IPLROMが$2000.wに読み込んで実行する
; 起動パーティションを自動または手動で選択し、選択されたパーティションのSASIパーティションIPLを$2400.wに読み込んで実行する
; アドレス
; $00000000 SASIディスクIPL
;
; パーティションテーブル
; アドレス 10MB 20MB 40MB
; $00000400 $5836384B $5836384B $5836384B X68Kマジック
; $00000404 $00009F54 $00013C98 $00027930 レコード数(ディスクイメージのサイズ)
; 33*4*309=40788 33*4*614=81048 33*8*614=162096
; $00000408 $00009F54 $00013C98 $00027930 代替レコード
; $0000040C $0000AF50 $00015660 $0002ACC0 シッピングゾーン
; 33*4*340=44880 33*4*664=87648 33*8*664=175296
; $00000410 第1パーティションの情報
; $00000410 $48756D61 $48756D61 $48756D61 Humaマジック
; $00000414 $6E36386B $6E36386B $6E36386B n68kマジック
; $00000418 $00000021 $00000021 $00000021 開始レコード
; $0000041C $00009F2E $00013C68 $000278F8 レコード数
; $00000420 第2パーティションの情報
; :
; $000004F0 第15パーティションの情報
; $00000500 空き
; :
;
; 第1パーティション(10MBの装置に最大サイズのパーティションを確保した場合)
; アドレス セクタ
; $00002100 $00000000 SASIパーティションIPL
; SASIディスクIPLが$2400.wに読み込んで実行する
; ルートディレクトリにあるHUMAN.SYSを$6800.wに読み込んで実行する
; $00002500 $00000001 第1FAT
; $00007500 $00000015 第2FAT
; $0000C500 $00000029 ルートディレクトリ
; $00010500 $00000039 データ領域
;
; ドライブ情報(最大サイズのパーティションを確保した場合)
; 10MB 20MB 40MB
; 1024 1024 1024 バイト/セクタ
; 1 1 1 セクタ/クラスタ
; 10132 20155 40335 データ領域のクラスタ数+2
; 1 1 1 予約領域のセクタ数
; 20 40 80 1個のFAT領域に使用するセクタ数
; 41 81 161 ルートディレクトリの先頭セクタ番号
; 512 512 512 ルートディレクトリに入るエントリ数
; 57 97 177 データ領域の先頭セクタ番号
;
scsi_bios_end:
.if SCSI_BIOS_LEVEL==0
;リロケートテーブル
.dc.w $0000,$0004,$0004,$0004,$0004,$0004,$0004,$0004
.dc.w $0004,$0038,$0004,$0014,$0144,$04C2,$0490,$001A
.dc.w $001C,$005E,$0156,$004A,$004A,$004A,$004A,$004C
.dc.w $0060,$0064,$0056,$005C,$0016,$003E,$003C,$003C
.dc.w $003E,$004C,$004E,$004A,$004A,$04FC,$0012,$0012
.dc.w $01AC,$0024,$0010
;シンボルテーブル
.dc.w $0201
.dc.l install_sasi_iocs
.dc.b 'sainit',$00
.even
.dc.w $0201
.dc.l iocs_4F_B_EJECT
.dc.b 'b_eject',$00
.even
.dc.w $0201
.dc.l iocs_F5_SCSIDRV
.dc.b 'SCSI',$00
.even
.dc.w $0201
.dc.l scsi_00_S_RESET
.dc.b 'S_RESET',$00
.even
.dc.w $0201
.dc.l scsi_01_S_SELECT
.dc.b 'S_SELECT',$00
.even
.dc.w $0201
.dc.l scsi_02_S_SELECTA
.dc.b 'S_SELECTA',$00
.even
.dc.w $0201
.dc.l scsi_03_S_CMDOUT
.dc.b 'S_CMDOUT',$00
.even
.dc.w $0201
.dc.l scsi_04_S_DATAIN
.dc.b 'S_DATAIN',$00
.even
.dc.w $0201
.dc.l scsi_05_S_DATAOUT
.dc.b 'S_DATAOUT',$00
.even
.dc.w $0201
.dc.l scsi_06_S_STSIN
.dc.b 'S_STSIN',$00
.even
.dc.w $0201
.dc.l scsi_07_S_MSGIN
.dc.b 'S_MSGIN',$00
.even
.dc.w $0201
.dc.l scsi_08_S_MSGOUT
.dc.b 'S_MSGOUT',$00
.even
.dc.w $0201
.dc.l scsi_09_S_PHASE
.dc.b 'S_PHASE',$00
.even
.dc.w $0201
.dc.l scsi_0A_S_LEVEL
.dc.b 'S_LEVEL',$00
.even
.dc.w $0201
.dc.l scsi_0B_S_DATAINI
.dc.b 'S_DATAINI',$00
.even
.dc.w $0201
.dc.l scsi_0C_S_DATAOUTI
.dc.b 'S_DATAOUTI',$00
.even
.dc.w $0201
.dc.l scsi_24_S_TESTUNIT
.dc.b 'testunit',$00
.even
.dc.w $0201
.dc.l scsi_2B_S_REZEROUNIT
.dc.b 'rezerounit',$00
.even
.dc.w $0201
.dc.l scsi_2E_S_READI
.dc.b 'readi',$00
.even
.dc.w $0201
.dc.l scsi_25_S_READCAP
.dc.b 'readcap',$00
.even
.dc.w $0201
.dc.l scsi_20_S_INQUIRY
.dc.b 'inquiry',$00
.even
.dc.w $0201
.dc.l scsi_2C_S_REQUEST
.dc.b 'request',$00
.even
.dc.w $0201
.dc.l scsi_21_S_READ
.dc.b 'read',$00
.even
.dc.w $0201
.dc.l scsi_22_S_WRITE
.dc.b 'write',$00
.even
.dc.w $0201
.dc.l scsi_23_S_FORMAT
.dc.b 'format',$00
.even
.dc.w $0201
.dc.l scsi_2F_S_STARTSTOP
.dc.b 'startstop',$00
.even
.dc.w $0201
.dc.l scsi_30_S_SEJECT
.dc.b 'seject',$00
.even
.dc.w $0201
.dc.l scsi_2D_S_SEEK
.dc.b 'seek',$00
.even
.dc.w $0201
.dc.l scsi_36_S_DSKINI
.dc.b 'dskini',$00
.even
.dc.w $0201
.dc.l scsi_37_S_FORMATB
.dc.b 'formatb',$00
.even
.dc.w $0201
.dc.l scsi_38_S_BADFMT
.dc.b 'badfmt',$00
.even
.dc.w $0201
.dc.l scsi_39_S_ASSIGN
.dc.b 'assign',$00
.even
.dc.w $0201
.dc.l scsi_29_S_MODESENSE
.dc.b 'modesense',$00
.even
.dc.w $0201
.dc.l scsi_2A_S_MODESELECT
.dc.b 'modeselect',$00
.even
.dc.w $0201
.dc.l scsi_31_S_REASSIGN
.dc.b 'reassign',$00
.even
.dc.w $0201
.dc.l scsi_26_S_READEXT
.dc.b 'readext',$00
.even
.dc.w $0201
.dc.l scsi_27_S_WRITEEXT
.dc.b 'writeext',$00
.even
.dc.w $0201
.dc.l scsi_28_S_VERIFYEXT
.dc.b 'verifyext',$00
.even
.dc.w $0201
.dc.l scsi_32_S_PAMEDIUM
.dc.b 'pamedium',$00
.even
.dc.w $0201
.dc.l jump_00_0F
.dc.b 'cmdtbl1',$00
.even
.dc.w $0201
.dc.l jump_20_3F
.dc.b 'cmdtbl2',$00
.even
.dc.w $0201
.dc.l jump_40_4F
.dc.b 'cmdtbl3',$00
.even
.dc.w $0201
.dc.l select_and_cmdout
.dc.b 'command',$00
.even
.dc.w $0201
.dc.l stsin_and_msgin
.dc.b 'ms_get',$00
.even
.dc.w $0201
.dc.l spc_interrupt_routine
.dc.b 'scsi_int',$00
.even
.dc.w $0201
.dc.l dataout_cpu
.dc.b 'man_out',$00
.even
.dc.w $0201
.dc.l dataouti_transfer
.dc.b 'prg_out',$00
.even
.dc.w $0201
.dc.l dataini_transfer
.dc.b 'prg_in',$00
.even
.dc.w $0201
.dc.l datain_cpu
.dc.b 'man_in',$00
.even
.dc.w $0201
.dc.l dataini_wait
.dc.b 'wt_pin',$00
.even
.dc.w $0201
.dc.l dataini_loop
.dc.b 'st_pin',$00
.even
.dc.w $0201
.dc.l dataout_cpu_loop
.dc.b 'st_mout',$00
.even
.dc.w $0201
.dc.l dataout_cpu_wait_1
.dc.b 'aa_mout',$00
.even
.dc.w $0201
.dc.l dataout_cpu_wait_2
.dc.b 'na_mout',$00
.even
.dc.w $0201
.dc.l dataout_cpu_end
.dc.b 'ed_mout',$00
.even
.dc.w $0201
.dc.l datain_cpu_loop
.dc.b 'st_min',$00
.even
.dc.w $0201
.dc.l datain_cpu_wait_1
.dc.b 'aa_min',$00
.even
.dc.w $0201
.dc.l datain_cpu_wait_2
.dc.b 'na_min',$00
.even
.dc.w $0201
.dc.l dataout_wait
.dc.b 'dout_loop',$00
.even
.dc.w $0201
.dc.l dataout_transfer
.dc.b 'dma_out',$00
.even
.dc.w $0201
.dc.l datain_transfer
.dc.b 'dma_in',$00
.even
.dc.w $0201
.dc.l dataout_transfer_end
.dc.b 'er_dout',$00
.even
.dc.w $0201
.dc.l dataout_transfer_no_error
.dc.b 'ed_dout',$00
.even
.dc.w $0201
.dc.l datain_transfer_end
.dc.b 'er_din',$00
.even
.dc.w $0201
.dc.l datain_transfer_wait
.dc.b 'ew_din',$00
.even
.dc.w $0201
.dc.l datain_transfer_no_error
.dc.b 'ed_din',$00
.even
.dc.w $0203
.dc.l scsi_bios_end
.dc.b 'allend',$00
.even
.dc.w $0201
.dc.l iocs_40_B_SEEK
.dc.b 'b_seek',$00
.even
.dc.w $0201
.dc.l iocs_41_B_VERIFY
.dc.b 'b_verify',$00
.even
.dc.w $0201
.dc.l iocs_43_B_DSKINI
.dc.b 'b_dskini',$00
.even
.dc.w $0201
.dc.l iocs_44_B_DRVSNS
.dc.b 'b_drvsns',$00
.even
.dc.w $0201
.dc.l iocs_45_B_WRITE
.dc.b 'b_write',$00
.even
.dc.w $0201
.dc.l iocs_46_B_READ
.dc.b 'b_read',$00
.even
.dc.w $0201
.dc.l iocs_47_B_RECALI
.dc.b 'b_recali',$00
.even
.dc.w $0201
.dc.l iocs_48_B_ASSIGN
.dc.b 'b_assign',$00
.even
.dc.w $0201
.dc.l iocs_4B_B_BADFMT
.dc.b 'b_badfmt',$00
.even
.dc.w $0201
.dc.l iocs_4D_B_FORMAT
.dc.b 'b_format',$00
.even
;空き
.if SCSIEXROM
.dcb.b $2000-$1F18,$FF
.else
.dcb.b $2000-$1EF8,$FF
.endif
.elif SCSI_BIOS_LEVEL==3
;空き
.if SCSIEXROM
.dcb.b $2000-$1B1E,$FF
.else
.dcb.b $2000-$1AFE,$FF
.endif
.endif
.end