misc/scsi16.s- Source code ソースコード - XEiJ - STUDIO KAMADA
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のカウンタを比較して転送を再開する位置を補正することで回避できる。
    ;	Ｇａｏさんの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

STUDIO KAMADA
Copyright © 1999-2026 Makoto Kamada