misc/sprdrv.s
;========================================================================================
; sprdrv.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/
;========================================================================================
;----------------------------------------------------------------
;タイトル
; 拡張スプライト・バックグラウンドドライバ
;名前
; sprdrv.x
;バージョン
; (2025-06-28)
;機能
; スプライト・バックグラウンド関連のIOCSコールでXEiJの拡張機能を使用できるようにします。
; _SP_INITで拡張機能を有効にしたプロセスが終了するとき拡張機能を無効にします。
;XEiJの設定
; 4096個のパターンをONにしてリセットしてください。
; スプライトの枚数は128/256/504/1016のいずれか、768x512でスプライトを表示、512x512でBG1を表示に対応します。
; ラスタあたりのスプライトの枚数は1016にしておくとよいでしょう。
;使用法
; device=sprdrv.x <オプション>
; または
; A>sprdrv.x <オプション>
;オプション
; -c 常駐確認
; 常駐確認を行い、結果をメッセージと終了コードで返します。
; -d 後始末なし
; 現在のプロセスの終了シーケンスに後始末の処理を追加しません。
; 初期化のプロセスが分かれている場合に指定します。
; 終了シーケンスの変更が他のプログラムやOSのパッチと衝突する場合にも指定します。
; -e 後始末あり(デフォルト)
; 拡張機能を使用するとき、現在のプロセスの終了シーケンスに後始末の処理を追加します。
; -q 静粛
; オプションが違うとき以外、メッセージを表示しません。
; -r 常駐解除
; 常駐部分がデバイスドライバのとき、ベクタを復元してデバイスドライバを切り離します。
; 常駐部分がメモリブロックのとき、ベクタを復元してメモリブロックを開放します。
; 常駐後にベクタが変更されて常駐部分を指していないときは解除できません。
; -v バージョン確認
; タイトルとバージョンを表示して正常終了します。
;終了コード
; 0 解除しました
; 1 オプションが違います
; 2 常駐しています
; 3 常駐していません
; 4 ベクタが変更されています。解除できません
; 65536 常駐しました
;更新履歴
; 2025-04-07
; 初版。
; 2025-04-10
; _SP_REGST/_SP_REGGTのスプライトの番号を連番に変更しました。
; _BGTEXTSTを修正しました。
; 2025-06-28
; _SP_INITに常駐確認を追加しました。
; _BGSCRLST/_BGSCRLGTに行スクロールまたは列スクロールの設定/取得を追加しました。
; _SP_INITが正常終了で0を返さない場合があった不具合を修正しました。
;----------------------------------------------------------------
;バンク制御
; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; | | モード |移動|
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; 移動
; 移動 テキストエリアの移動
; 0 しない
; 1 する
; モード
; モード パターン数 スプライト反転 テキスト反転
; 0 256 可 可
; 1 1024 可 可
; 2 4096 不可 不可
; 3 4096 可 不可
; 反転不可を補うため、_SP_DEFCGにパターンを反転する機能が追加されています。
;キャラクタ
; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; |上下|左右| | パレットブロック | パターン番号 | モード0
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; |上下|左右|番号上位 | パレットブロック | パターン番号下位 | モード1
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; | パターン番号上位 | パレットブロック | パターン番号下位 | モード2,3
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
;プライオリティ
; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; | |豆腐|優先順位 | モード0,1,2
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; |上下|左右| |豆腐|優先順位 | モード3
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; 優先順位
; 0 表示しない
; 1 バックグラウンド0>バックグラウンド1>スプライト
; 2 バックグラウンド0>スプライト>バックグラウンド1
; 3 スプライト>バックグラウンド0>バックグラウンド1
;----------------------------------------------------------------
;IOCS $C0 _SP_INIT
; 機能 スプライト・バックグラウンドを初期化します。
; _SP_INITで拡張機能を有効にしたプロセスが終了するとき拡張機能を無効にします。
; 入力 レジスタ 値
; d1.l 'SPRD'$53505244 拡張機能を使用する
; d2.l 0~7 バンク制御
; -1 常駐確認(初期化は行わない)
; 出力 レジスタ 値
; d0.l -3 拡張機能を使用できない
; -1 スプライト画面を使用できない
; 0 正常終了
; 常駐確認のとき
; d0.l $53xxxxxx バージョン
;----------------------------------------------------------------
;IOCS $C1 _SP_ON
; 機能 スプライト画面を表示します。
; 入力 なし
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C2 _SP_OFF
; 機能 スプライト画面を表示しません。
; 入力 なし
; 出力 レジスタ 値
; d0.l 0 正常終了
;----------------------------------------------------------------
;IOCS $C3 _SP_CGCLR
; 機能 パターンをゼロクリアします。
; 入力 レジスタ 値
; d1.w 0~4095 パターン番号
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C4 _SP_DEFCG
; 機能 パターンを設定します。
; パターンを反転する機能が追加されています。
; 入力 レジスタ 値
; d1.w 0~4095 パターン番号
; d2.w[15] 0~1 上下反転
; d2.w[14] 0~1 左右反転
; d2.b 0~1 サイズ。0=8x8,1=16x16
; a1.l 偶数 バッファのアドレス
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C5 _SP_GTPCG
; 機能 パターンを取得します。
; 入力 レジスタ 値
; d1.w 0~4095 パターン番号
; d2.b 0~1 サイズ。0=8x8,1=16x16
; a1.l 偶数 バッファのアドレス
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C6 _SP_REGST
; 機能 スプライトスクロールレジスタを設定します。
; 豆腐ビットをクリアします。
; 入力 レジスタ 値
; d1.l[31] 1 VDISPの立ち下がりを待たない
; d1.w 0~1015 スプライト番号(連番)
; d2.l[31] 1 X座標を設定しない
; d2.w 0~1023 X座標
; d3.l[31] 1 Y座標を設定しない
; d3.w 0~1023 Y座標
; d4.l[31] 1 キャラクタを設定しない
; d4.w 0~65535 キャラクタ
; d5.l[31] 1 プライオリティを設定しない
; d5.w 0~65535 プライオリティ
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C7 _SP_REGGT
; 機能 スプライトスクロールレジスタを取得します。
; 入力 レジスタ 値
; d1.w 0~1015 スプライト番号(連番)
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
; d2.l 0~1023 X座標
; d3.l 0~1023 Y座標
; d4.l 0~65535 キャラクタ
; d5.l 0~65535 プライオリティ
;----------------------------------------------------------------
;IOCS $C8 _BGSCRLST
; 機能 バックグラウンドスクロールレジスタを設定します。
; 行スクロールまたは列スクロールの設定が追加されています。
; 入力 レジスタ 値
; 共通
; d1.l[31] 1 VDISPの立ち下がりを待たない
; d1.w[15~8] 0~2 0=バックグラウンド,1=行スクロール,2=列スクロール
; d1.b 0~1 バックグラウンド番号
; バックグラウンド
; d2.l[31] 1 X座標を設定しない
; d2.w 0~1023 X座標
; d3.l[31] 1 Y座標を設定しない
; d3.w 0~1023 Y座標
; 行スクロール
; d2.w 0~63 行番号
; d3.w 0~1023 X座標
; 列スクロール
; d2.w 0~63 列番号
; d3.w 0~1023 Y座標
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $C9 _BGSCRLGT
; 機能 バックグラウンドスクロールレジスタを取得します。
; 行スクロールまたは列スクロールの取得が追加されています。
; 入力 レジスタ 値
; 共通
; d1.w[15~8] 0~2 0=バックグラウンド,1=行スクロール,2=列スクロール
; d1.b 0~1 バックグラウンド番号
; 行スクロール
; d2.w 0~63 行番号
; 列スクロール
; d2.w 0~63 列番号
; 出力 レジスタ 値
; 共通
; d0.l -1 スプライト画面を使用できない
; バックグラウンド
; d0.l 0 正常終了
; d2.l 0~1023 X座標
; d3.l 0~1023 Y座標
; 行スクロール
; d0.l 0~1023 X座標
; 列スクロール
; d0.l 0~1023 Y座標
;----------------------------------------------------------------
;IOCS $CA _BGCTRLST
; 機能 バックグラウンド制御レジスタを設定します。
; 入力 レジスタ 値
; d1.b 0~1 バックグラウンド番号
; d2.l[31] 1 テキストエリア番号を設定しない
; d2.b 0~1 テキストエリア番号
; d3.l[31] 1 表示の有無を設定しない
; d3.b 0~1 表示の有無
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $CB _BGCTRLGT
; 機能 バックグラウンド制御レジスタを取得します
; 入力 レジスタ 値
; d1.b 0~1 バックグラウンド番号
; 出力 レジスタ 値
; d0.l -1 スプライト画面を使用できない
; 0~7 テキストエリア番号<<1|表示の有無
;----------------------------------------------------------------
;IOCS $CC _BGTEXTCL
; 機能 バックグラウンドテキストをキャラクタで埋め尽くします。
; 疑似グラフィック画面を作る機能が追加されています。
; 入力 レジスタ 値
; d1.w[15~8] $00 キャラクタで埋め尽くす
; $10 疑似グラフィック画面を作る
; d1.b 0~1 テキストエリア番号
; d2.w 0~65535 キャラクタ/パレットブロック
; 出力 レジスタ 値
; d0.l -3 拡張機能を使用できない
; -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $CD _BGTEXTST
; 機能 バックグラウンドテキストにキャラクタを書き込みます。
; 疑似グラフィック画面に書き込む機能が追加されています。
; 入力 レジスタ 値
; d1.w[15~8] $00 キャラクタを書き込む
; $10 疑似グラフィック画面に1ドット書き込む
; d1.b 0~1 テキストエリア番号
; d2.w 0~1023 X座標
; d3.w 0~1023 Y座標
; d4.w 0~65535 キャラクタ/パレットコード
; 出力 レジスタ 値
; d0 -3 拡張機能を使用できない
; -1 スプライト画面を使用できない
; 0 正常終了
;----------------------------------------------------------------
;IOCS $CE _BGTEXTGT
; 機能 バックグラウンドテキストからキャラクタを読み出します。
; 疑似グラフィック画面から読み出す機能が追加されています。
; 入力 レジスタ 値
; d1.w[15~8] $00 キャラクタを読み出す
; $10 疑似グラフィック画面から1ドット読み出す
; d1.b 0~1 テキストエリア番号
; d2.w 0~1023 X座標
; d3.w 0~1023 Y座標
; 出力 レジスタ 値
; d0.l -3 拡張機能を使用できない
; -1 スプライト画面を使用できない
; 0~65535 キャラクタ/パレットコード
;----------------------------------------------------------------
;IOCS $CF _SPALET
; 機能 スプライトパレットを設定または取得します。
; パレットブロック0は指定できません。
; 入力 レジスタ 値
; d1.l[31] 1 VDISPの立ち下がりを待たない
; d1.b 0~255 パレットブロック<<4|パレットコード
; d2.b 0~15 パレットブロック(優先)
; d3.l[31] 0 設定
; 1 取得
; d3.w 0~65535 カラーコード
; 出力 レジスタ 値
; d0.l -2 パレットブロック0が指定された
; 0~65535 設定前のカラーコード
;----------------------------------------------------------------
.include bioswork.equ
.include control2.mac
.include crtc.equ
.include doscall.mac
.include dosconst.equ
.include doswork.equ
.include iocscall.mac
.include mfp.equ
.include misc.mac
.include push2.mac
.include sprc.equ
.include vector.equ
.include vicon.equ
DEVICE_NAME reg '/*SPRD*/'
JAPANESE_TITLE reg '拡張スプライト・バックグラウンドドライバ'
ENGLISH_TITLE reg 'Extended sprite and background driver'
VERSION_STRING reg '(2025-06-28)'
VERSION_NUMBER equ $53250628
PROGRAM_NAME reg 'sprdrv.x'
PROGRAMEN_NAME reg 'sprdrven.x'
.ifndef ENGLISH
ENGLISH equ 0
.endif
;----------------------------------------------------------------
;プログラムの先頭
.text
program_head:
;デバイスヘッダ
.dc.l -1 ;次のデバイスヘッダ。-1=デバイスヘッダのリストの末尾
.dc.w $8000 ;デバイスタイプ。キャラクタデバイス
.dc.l strategy_routine ;ストラテジルーチン
.dc.l interrupt_routine ;インタラプトルーチン
.dc.b DEVICE_NAME ;デバイス名
;ベクタテーブル
vector_table:
.dc.w 4*($100+_SP_INIT) ;オフセット
.dc.l iocs_C0_SP_INIT ;新しいベクタ
.dc.l 0 ;古いベクタ
.dc.w 4*($100+_SP_ON)
.dc.l iocs_C1_SP_ON
.dc.l 0
.dc.w 4*($100+_SP_OFF)
.dc.l iocs_C2_SP_OFF
.dc.l 0
.dc.w 4*($100+_SP_CGCLR)
.dc.l iocs_C3_SP_CGCLR
.dc.l 0
.dc.w 4*($100+_SP_DEFCG)
.dc.l iocs_C4_SP_DEFCG
.dc.l 0
.dc.w 4*($100+_SP_GTPCG)
.dc.l iocs_C5_SP_GTPCG
.dc.l 0
.dc.w 4*($100+_SP_REGST)
.dc.l iocs_C6_SP_REGST
.dc.l 0
.dc.w 4*($100+_SP_REGGT)
.dc.l iocs_C7_SP_REGGT
.dc.l 0
.dc.w 4*($100+_BGSCRLST)
.dc.l iocs_C8_BGSCRLST
.dc.l 0
.dc.w 4*($100+_BGSCRLGT)
.dc.l iocs_C9_BGSCRLGT
.dc.l 0
.dc.w 4*($100+_BGCTRLST)
.dc.l iocs_CA_BGCTRLST
.dc.l 0
.dc.w 4*($100+_BGCTRLGT)
.dc.l iocs_CB_BGCTRLGT
.dc.l 0
.dc.w 4*($100+_BGTEXTCL)
.dc.l iocs_CC_BGTEXTCL
.dc.l 0
.dc.w 4*($100+_BGTEXTST)
.dc.l iocs_CD_BGTEXTST
.dc.l 0
.dc.w 4*($100+_BGTEXTGT)
.dc.l iocs_CE_BGTEXTGT
.dc.l 0
.dc.w 4*($100+_SPALET)
.dc.l iocs_CF_SPALET
.dc.l 0
.dc.w 0
;フラグ
cleanup_flag:
.dc.b -1 ;-1=後始末あり,0=後始末なし
.even
;リクエストヘッダのアドレス
request_header:
.dc.l 0
;ストラテジルーチン
strategy_routine:
move.l a5,request_header
rts
;インタラプトルーチン
interrupt_routine:
push d0-d7/a0-a6
movea.l request_header(pc),a5
moveq.l #0,d0
move.b 2(a5),d0 ;コマンド番号
if <cmp.w #(jump_table_end-jump_table)/2,d0>,hs ;範囲外
moveq.l #(jump_table_end-jump_table)/2,d0
endif
add.w d0,d0
move.w jump_table(pc,d0.w),d0
jsr jump_table(pc,d0.w)
move.b d0,3(a5) ;エラーコード下位
lsr.w #8,d0
move.b d0,4(a5) ;エラーコード上位
pop
rts
;デバイスコマンドのジャンプテーブル
jump_table:
.dc.w initialize-jump_table ;デバイスコマンド0 初期化
.dc.w command_error-jump_table ;デバイスコマンド1 ディスク交換チェック
.dc.w command_error-jump_table ;デバイスコマンド2 BPBテーブルの再構築
.dc.w ioctrl_input-jump_table ;デバイスコマンド3 _IOCTRLによる入力
.dc.w input-jump_table ;デバイスコマンド4 入力
.dc.w control_sense-jump_table ;デバイスコマンド5 コントロール/センス
.dc.w input_status-jump_table ;デバイスコマンド6 入力ステータス
.dc.w input_flush-jump_table ;デバイスコマンド7 入力バッファフラッシュ
.dc.w output-jump_table ;デバイスコマンド8 出力(ベリファイなし)
.dc.w output-jump_table ;デバイスコマンド9 出力(ベリファイあり)
.dc.w output_status-jump_table ;デバイスコマンド10 出力ステータス
.dc.w no_error-jump_table ;デバイスコマンド11 正常終了
.dc.w ioctrl_output-jump_table ;デバイスコマンド12 _IOCTRLによる出力
jump_table_end:
.dc.w command_error-jump_table ;範囲外 コマンドエラー
;デバイスコマンド1 ディスク交換チェック
;デバイスコマンド2 BPBテーブルの再構築
;コマンドエラー
command_error:
move.w #IGNORE|ABORT|UNKNOWN_COMMAND,d0 ;無視(I) 中止(A) デバイスドライバに無効なコマンドを指定しました
rts
;デバイスコマンド3 _IOCTRLによる入力
ioctrl_input:
; movea.l 14(a5),a1 ;アドレス
goto command_error
;デバイスコマンド4 入力
input:
movea.l 14(a5),a1 ;アドレス
move.l 18(a5),d3 ;長さ
docontinue
clr.b (a1)+
while <subq.l #1,d3>,cc
moveq.l #0,d0 ;常に成功する(終わるまで復帰しない)
rts
;デバイスコマンド5 コントロール/センス
control_sense:
clr.b 13(a5) ;データ
moveq.l #0,d0 ;常に成功する
rts
;デバイスコマンド6 入力ステータス
input_status:
moveq.l #1,d0 ;0=入力バッファが空ではないので入力できる,1=入力バッファが空なので入力できない
rts
;デバイスコマンド7 入力バッファフラッシュ
input_flush:
moveq.l #0,d0 ;常に成功する
rts
;デバイスコマンド8 出力(ベリファイなし)
;デバイスコマンド9 出力(ベリファイあり)
output:
; movea.l 14(a5),a1 ;アドレス
; move.l 18(a5),d3 ;長さ
moveq.l #0,d0 ;常に成功する(終わるまで復帰しない)
rts
;デバイスコマンド10 出力ステータス
output_status:
moveq.l #1,d0 ;0=出力バッファが満杯ではないので出力できる,1=出力バッファが満杯なので出力できない
rts
;デバイスコマンド11 正常終了
no_error:
moveq.l #0,d0 ;常に成功する
rts
;デバイスコマンド12 _IOCTRLによる出力
ioctrl_output:
; movea.l 14(a5),a1 ;アドレス
goto command_error
;----------------------------------------------------------------
;ワークエリア
original_exitvc:
.dc.l 0 ;変更前の_EXITVC。0=変更していない
original_sr:
.dc.w 0 ;変更前のsr
text_area:
.dc.l SPRC_TEXT_0 ;現在のテキストエリア0
sprite_max:
.dc.w 127 ;スプライト番号の最大値。127,255,511,1023
bank_available:
.dc.b 0 ;-1=バンクあり,0=バンクなし
extended_1xx1x:
.dc.b 1 ;%1xx1xのときスプライト画面を使用できるか。-1=使える,0=使えない,1=未確認
.even
;----------------------------------------------------------------
;_EXITVCルーチン
; _EXITVCを用いて親プロセスの_EXECの直後に処理を追加する
; そのままだと親プロセスがユーザモードのときスーパーバイザ領域にある(デバイスドライバの中にある)コードを実行できない
; 親プロセスのsrを変更してスーパーパイザモードで追加の処理を実行してから変更前のsrを復元する
exitvc_routine:
;後始末する
push d0-d1/a0
move.b cleanup_flag(pc),d0
if ne ;後始末あり
moveq.l #0,d1
bsr iocs_C0_SP_INIT
endif
pop
;変更前のsrを復元して、変更前の_EXITVC(他に_EXITVCに追加された処理がなければ親プロセスの_EXECの直後)へジャンプする
if <tst.b BIOS_MPU_TYPE.w>,ne
clr.w -(sp)
endif
move.l original_exitvc(pc),-(sp) ;変更前の_EXITVC
clr.l original_exitvc
move.w original_sr(pc),-(sp) ;変更前のsr
clr.w original_sr
rte
;----------------------------------------------------------------
;スプライト画面を使用できるか確認する
; IOCSコールの先頭で呼び出す
; スプライト画面を使用できるとき何もしない
; スプライト画面を使用できないときd0.l=-1でIOCSコールを終了する
;?d0/a0
check_sprite:
moveq.l #.not.%10010,d0
or.b CRTC_RESOLUTION_BYTE,d0 ;R20L。%1xx1xのときだけ%11111111
not.b d0 ;%1xx1xのときだけ%00000000
do
break ne ;%1xx1xではない。使用できる
move.b extended_1xx1x(pc),d0 ;%1xx1xのときスプライト画面を使用できるか
break mi ;-1=使用できる
if ne ;1=未確認
;%1xx1xのときスプライト画面を使用できるか確認する
moveq.l #-1,d0
move.l OFFSET_BUS_ERROR.w,-(sp)
movea.l sp,a0
move.l #@f,OFFSET_BUS_ERROR.w
nop
move.w SPRC_SCROLL,d0 ;スプライトスクロールレジスタをリードしてみる
nop
@@: movea.l a0,sp
move.l (sp)+,OFFSET_BUS_ERROR.w
tst.w d0 ;バスエラーが発生したかX座標が負のときmi、さもなくばpl
spl.b extended_1xx1x ;-1=使用できる,0=使用できない
break pl ;使用できる
endif
moveq.l #-1,d0 ;スプライト画面を使用できない
addq.l #4,sp ;IOCSコールを終了する
while f
rts
;----------------------------------------------------------------
;VDISPの立ち下がりを待つ
vdisp_falling_edge:
do
while <btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq
do
while <btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne
rts
;----------------------------------------------------------------
;IOCS $C0 _SP_INIT
; スプライト・バックグラウンドを初期化します。
; _SP_INITで拡張機能を有効にしたプロセスが終了するとき拡張機能を無効にします。
;<d1.l:'SPRD'$53505244=拡張機能を使用する
;<d2.l:バンク制御,-1=常駐確認
;>d0.l:-3=拡張機能を使用できない,-1=スプライト画面を使用できない,0=正常終了,常駐確認のとき$53xxxxxx
;?a0
iocs_C0_SP_INIT:
ifand <cmp.l #'SPRD',d1>,eq,<cmp.l #-1,d2>,eq ;常駐確認
move.l #VERSION_NUMBER,d0 ;バージョン
rts
endif
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1-d7/a1-a4/a6
lea.l $00EB8000,a6
EB reg -$00EB8000(a6)
;拡張機能を使用する/使用しない
moveq.l #-1,d6
if <cmp.l #'SPRD',d1>,eq ;拡張機能を使用する
moveq.l #7,d6
and.w d2,d6 ;バンク制御
endif
;<d6.l:-1=拡張機能を使用しない,0~7=バンク制御
;スプライトの番号の最大値を求める
lea.l (SPRC_SCROLL)EB,a0 ;スプライトスクロールレジスタのX座標
move.w #1024-1,d7
do
move.w d7,d0 ;番号
lsl.w #3,d0 ;8*番号
break <tst.w (a0,d0.w)>,pl ;あれば終了
lsr.w #1,d7 ;なければ半分にする
while <tst.b d7>,mi ;128-1で終了
;<d7.w:スプライトの番号の最大値
;d1-d4/a1-a4をゼロにする
moveq.l #0,d1
.irp rn,d2,d3,d4,a1,a2,a3,a4
move.l d1,rn
.endm
;スプライトコントロールレジスタをゼロクリアする
move.w d1,(SPRC_CONTROL)EB
;バックグラウンドスクロールレジスタをゼロクリアする
movem.l d1-d2,(SPRC_BG_0_X)EB
;スプライトスクロールレジスタをゼロクリアする
lea.l (SPRC_SCROLL)EB,a0
move.w d7,d0 ;スプライトの番号の最大値。127,255,511,1023
lsr.w #5-3,d0 ;8*欠番を含む枚数/32-1。31,63,127,255
moveq.l #8*256/32-1,d5
if <cmp.w d5,d0>,hi ;256枚より多いとき
for d5
movem.l d1-d4/a1-a4,(a0) ;256枚クリアして
lea.l 32(a0),a0
next
lea.l 8*8(a0),a0 ;8枚飛ばす
sub.w #8*(256+8)/32,d0
endif
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
;パターンとテキストエリアをゼロクリアする
move.w (SPRC_BANK_NUMBER)EB,d0
if mi ;バンクなし
;パターンとテキストエリアをゼロクリアする
lea.l (SPRC_PATTERN)EB,a0
move.w #128*256/32-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
else ;バンクあり
lsr.w #1,d0
if cs ;テキストエリア移動あり
;テキストエリアをゼロクリアする
lea.l (SPRC_BANK_TEXT_0)EB,a0
move.w #2*64*64*2/32-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
endif
;パターンをゼロクリアする
moveq.l #15,d5 ;バンク番号。15~0。バンク0が選択された状態で終了する
for d5
move.b d5,(SPRC_BANK_NUMBER)EB ;バンク番号
lea.l (SPRC_PATTERN)EB,a0
move.w #128*256/32-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
next
endif
;スプライトパレットを初期化する
lea.l VICON_TSPALET+2*16,a0 ;パレットブロック1~15
movem.l 100f(pc),d1-d4/a1-a4 ;カラーコードの初期値
bsr vdisp_falling_edge ;VDISPの立ち下がりを待つ
moveq.l #15-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
;拡張機能を使用する/使用しない
if <tst.l d6>,mi ;拡張機能を使用しない
if <tst.w (SPRC_BANK_NUMBER)EB>,pl ;バンク番号レジスタがある
clr.l (SPRC_BANK_CONTROL)EB ;バンク制御レジスタとバンク番号レジスタをゼロクリアする
endif
move.l #SPRC_TEXT_0,text_area ;移動前のテキストエリア
move.w #127,sprite_max ;スプライトの番号の最大値
sf.b bank_available ;バンクなし
moveq.l #0,d0 ;正常終了
elif <tst.w (SPRC_BANK_NUMBER)EB>,mi ;バンク番号レジスタがない
moveq.l #-3,d0 ;拡張機能を使用できない
else ;拡張機能を使用する
;後始末の準備
move.b cleanup_flag(pc),d0
if ne ;後始末あり
movea.l DOS_PROCESS_HANDLE.w,a0 ;プロセスハンドル
movea.l (a0),a0 ;実行中のプロセスのメモリ管理ポインタ
lea.l original_exitvc(pc),a1 ;変更前の_EXITVCのハンドル
lea.l original_sr(pc),a2 ;変更前のsrのハンドル
lea.l exitvc_routine(pc),a3 ;変更後の_EXITVC
lea.l OFFSET_DOS+4*(_EXITVC&$FF).w,a4 ;_EXITVCのハンドル
if <tst.l (a1)>,eq ;自分を登録していない
move.l (a4),(a1) ;_EXITVCを保存する
move.l a3,(a4) ;_EXITVCを変更する
move.l a3,MM_EXITVC(a0) ;実行中のプロセスの_EXITVCを変更する
move.w MM_SR(a0),(a2) ;実行中のプロセスの親プロセスのsrを保存する
ori.w #$2000,MM_SR(a0) ;実行中のプロセスの親プロセスのsrを変更する
endif
endif
;拡張機能を有効にする
move.w d6,(SPRC_BANK_CONTROL)EB ;バンク制御
lea.l (SPRC_TEXT_0)EB,a0 ;移動前のテキストエリア
if <btst.l #0,d6>,ne
lea.l (SPRC_BANK_TEXT_0)EB,a0 ;移動後のテキストエリア
endif
move.l a0,text_area
move.w d7,sprite_max ;スプライトの番号の最大値
st.b bank_available ;バンクあり
moveq.l #0,d0 ;正常終了
endif
pop
rts
;カラーコードの初期値
100: dcrgb 0,0,0 ;0=黒
dcrgb 10,10,10 ;1=暗い灰色
dcrgb 0,0,16 ;2=暗い青
dcrgb 0,0,31 ;3=青
dcrgb 16,0,0 ;4=暗い赤
dcrgb 31,0,0 ;5=赤
dcrgb 16,0,16 ;6=暗い紫
dcrgb 31,0,31 ;7=紫
dcrgb 0,16,0 ;8=暗い緑
dcrgb 0,31,0 ;9=緑
dcrgb 0,16,16 ;10=暗い水色
dcrgb 0,31,31 ;11=水色
dcrgb 16,16,0 ;12=暗い黄色
dcrgb 31,31,0 ;13=黄色
dcrgb 21,21,21 ;14=明るい灰色
dcrgb 31,31,31 ;15=白
;----------------------------------------------------------------
;IOCS $C1 _SP_ON
; スプライト画面を表示します。
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C1_SP_ON:
bsr check_sprite ;スプライト画面を使用できるか確認する
ori.w #VICON_SPON_MASK,VICON_VISIBLE
ori.w #SPRC_SPRITE_ON,SPRC_CONTROL
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $C2 _SP_OFF
; スプライト画面を表示しません。
;>d0.l:0=正常終了
iocs_C2_SP_OFF:
andi.w #.notw.VICON_SPON_MASK,VICON_VISIBLE
andi.w #.notw.SPRC_SPRITE_ON,SPRC_CONTROL
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $C3 _SP_CGCLR
; パターンをゼロクリアします。
;<d1.w:パターン番号
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C3_SP_CGCLR:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1
lea.l SPRC_PATTERN,a0
move.b bank_available(pc),d0
if ne ;バンクあり
move.w d1,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;バンク番号
endif
and.w #$00FF,d1 ;バンク内パターン番号
lsl.w #7,d1
adda.w d1,a0
moveq.l #0,d0
moveq.l #128/4-1,d1
for d1
move.l d0,(a0)+
next
; moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;IOCS $C4 _SP_DEFCG
; パターンを設定します。
; パターンを反転する機能が追加されています。
;<d1.w:パターン番号
;<d2.w[15]:上下反転
;<d2.w[14]:左右反転
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C4_SP_DEFCG:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1-d2/a1
lea.l SPRC_PATTERN,a0
do
if <tst.b d2>,eq ;8x8
move.b bank_available(pc),d0
if ne ;バンクあり
move.w d1,d0
lsr.w #2,d0
move.w d0,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;バンク番号
endif
and.w #$03FF,d1 ;バンク内8x8パターン番号
lsl.w #5,d1
adda.w d1,a0
add.w d2,d2
if cc ;上下反転しない
if pl ;左右反転しない
moveq.l #8-1,d2
for d2
move.l (a1)+,(a0)+ ;上→下
next
break
else ;左右反転する
moveq.l #8-1,d2
for d2
move.l (a1)+,d0 ;上→下
bsr hexrev
move.l d0,(a0)+ ;上→下
next
break
endif
else ;上下反転する
lea.l 32(a1),a1 ;上→下
if pl ;左右反転しない
moveq.l #8-1,d2
for d2
move.l -(a1),(a0)+ ;下→上/上→下
next
break
else ;左右反転する
moveq.l #8-1,d2
for d2
move.l -(a1),d0 ;下→上
bsr hexrev
move.l d0,(a0)+ ;上→下
next
break
endif
endif
else ;16x16
move.b bank_available(pc),d0
if ne ;バンクあり
move.w d1,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;バンク番号
endif
and.w #$00FF,d1 ;バンク内16x16パターン番号
lsl.w #7,d1
adda.w d1,a0
add.w d2,d2
if cc ;上下反転しない
if pl ;左右反転しない
moveq.l #32-1,d2
for d2
move.l (a1)+,(a0)+ ;左上→左下=右上→右下
next
break
else ;左右反転する
lea.l 64(a1),a1 ;左上→右上
moveq.l #16-1,d2
for d2
move.l (a1)+,d0 ;右上→右下
bsr hexrev
move.l d0,(a0)+ ;左上→左下=右上
next
lea.l -128(a1),a1 ;右下→左上
moveq.l #16-1,d2
for d2
move.l (a1)+,d0 ;左上→左下
bsr hexrev
move.l d0,(a0)+ ;左下=右上→右下
next
break
endif
else ;上下反転する
if pl ;左右反転しない
lea.l 64(a1),a1 ;左上→左下
moveq.l #16-1,d2
for d2
move.l -(a1),(a0)+ ;左下→左上/左上→左下=右上
next
lea.l 128(a1),a1 ;左上→右下
moveq.l #16-1,d2
for d2
move.l -(a1),(a0)+ ;右下→右上/左下=右上→右下
next
break
else ;左右反転する
lea.l 128(a1),a1 ;左上→右下
moveq.l #32-1,d2
for d2
move.l -(a1),d0 ;右下→右上=左下→左上
bsr hexrev
move.l d0,(a0)+ ;左上→左下=右上→右下
next
; break
endif
endif
endif
while f
moveq.l #0,d0 ;正常終了
pop
rts
;左右反転
;<d0.l:パターン
;>d0.l:左右反転したパターン
;?d1
hexrev:
;d0=ABCDEFGH
move.l d0,d1 ;d1=ABCDEFGH
and.l #$00FF00FF,d1 ;d1=00CD00GH
eor.l d1,d0 ;d0=AB00EF00
swap.w d1 ;d1=00GH00CD
or.l d1,d0 ;d0=ABGHEFCD
move.l d0,d1 ;d1=ABGHEFCD
and.l #$0F0F0F0F,d1 ;d1=0B0H0F0D
eor.l d1,d0 ;d0=A0G0E0C0
rol.l #8,d1 ;d1=0H0F0D0B
or.l d1,d0 ;d0=AHGFEDCB
rol.l #4,d0 ;d0=HGFEDCBA
rts
;----------------------------------------------------------------
;IOCS $C5 _SP_GTPCG
; パターンを取得します。
;<d1.w:パターン番号
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C5_SP_GTPCG:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1-d2/a1
lea.l SPRC_PATTERN,a0
if <tst.b d2>,eq ;8x8
move.b bank_available(pc),d0
if ne ;バンクあり
move.w d1,d0
lsr.w #2,d0
move.w d0,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;バンク番号
endif
and.w #$03FF,d1 ;バンク内8x8パターン番号
lsl.w #5,d1
moveq.l #8-1,d2
else ;16x16
move.b bank_available(pc),d0
if ne ;バンクあり
move.w d1,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;バンク番号
endif
and.w #$00FF,d1 ;バンク内16x16パターン番号
lsl.w #7,d1
moveq.l #32-1,d2
endif
adda.w d1,a0
for d2
move.l (a0)+,(a1)+
next
moveq.l #0,d0
pop
rts
;----------------------------------------------------------------
;IOCS $C6 _SP_REGST
; スプライトスクロールレジスタを設定します。
; 豆腐ビットをクリアします。
;<d1.l[31]:1=VDISPの立ち下がりを待たない
;<d1.w:スプライト番号(連番)
;<d2.l[31]:1=X座標を設定しない
;<d2.w:X座標
;<d3.l[31]:1=Y座標を設定しない
;<d3.w:Y座標
;<d4.l[31]:1=キャラクタを設定しない
;<d4.w:キャラクタ
;<d5.l[31]:1=プライオリティを設定しない
;<d5.w:プライオリティ
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C6_SP_REGST:
bsr check_sprite ;スプライト画面を使用できるか確認する
move.w d1,d0
and.w sprite_max(pc),d0 ;0~1015/1016~1023
do
if <cmp.w #256,d0>,hs ;256~1015/1016~1023
addq.w #8,d0 ;264~1023/1024~1031
break <cmp.w sprite_max(pc),d0>,hi ;1024~1031
endif
lea.l SPRC_SCROLL,a0
lsl.w #3,d0
adda.w d0,a0
if <tst.l d1>,pl
bsr vdisp_falling_edge ;VDISPの立ち下がりを待つ
endif
if <tst.l d2>,pl
move.w d2,(a0) ;X座標
endif
if <tst.l d3>,pl
move.w d3,2(a0) ;Y座標
endif
if <tst.l d4>,pl
move.w d4,4(a0) ;キャラクタ
endif
if <tst.l d5>,pl
moveq.l #.not.4,d0 ;豆腐ビットをクリアする
and.w d5,d0
move.w d0,6(a0) ;プライオリティ
endif
while f
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $C7 _SP_REGGT
; スプライトスクロールレジスタを取得します。
;<d1.w:スプライト番号(連番)
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;>d2.l:X座標
;>d3.l:Y座標
;>d4.l:キャラクタ
;>d5.l:プライオリティ
;?a0
iocs_C7_SP_REGGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
moveq.l #0,d2
moveq.l #0,d3
moveq.l #0,d4
moveq.l #0,d5
move.w d1,d0
and.w sprite_max(pc),d0 ;0~1015/1016~1023
do
if <cmp.w #256,d0>,hs ;256~1015/1016~1023
addq.w #8,d0 ;264~1023/1024~1031
break <cmp.w sprite_max(pc),d0>,hi ;1024~1031
endif
lea.l SPRC_SCROLL,a0
lsl.w #3,d0
adda.w d0,a0
move.w (a0)+,d2 ;X座標
move.w (a0)+,d3 ;Y座標
move.w (a0)+,d4 ;キャラクタ
move.w (a0)+,d5 ;プライオリティ
while f
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $C8 _BGSCRLST
; バックグラウンドスクロールレジスタを設定します。
; 行スクロールまたは列スクロールの設定が追加されています。
;共通
; <d1.l[31]:1=VDISPの立ち下がりを待たない
; <d1.b:バックグラウンド番号
; >d0.l:-1=スプライト画面を使用できない,0=正常終了
; ?a0
;バックグラウンド
; <d1.w[15~8]:0
; <d2.l[31]:1=X座標を設定しない
; <d2.w:X座標
; <d3.l[31]:1=Y座標を設定しない
; <d3.w:Y座標
;行スクロール
; <d1.w[15~8]:1
; <d2.w:行番号
; <d3.w:X座標
;列スクロール
; <d1.w[15~8]:2
; <d2.w:列番号
; <d3.w:Y座標
iocs_C8_BGSCRLST:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <tst.l d1>,pl
bsr vdisp_falling_edge ;VDISPの立ち下がりを待つ
endif
if <cmp.w #$0100,d1>,lo ;バックグラウンド
lea.l SPRC_BG_0_X,a0
if <tst.b d1>,ne
addq.l #SPRC_BG_1_X-SPRC_BG_0_X,a0
endif
if <tst.l d2>,pl
move.w d2,(a0) ;X座標
endif
if <tst.l d3>,pl
move.w d3,2(a0) ;Y座標
endif
else ;行スクロールまたは列スクロール
lea.l $00EB2000,a0 ;行スクロールレジスタ
if <cmp.w #$0200,d1>,hs
lea.l $00EB2200-$00EB2000(a0),a0 ;列スクロールレジスタ
endif
if <tst.b d1>,ne
lea.l 2*64(a0),a0
endif
move.w d2,d0 ;行番号または列番号
add.w d0,d0
move.w d3,(a0,d0.w) ;X座標またはY座標
endif
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $C9 _BGSCRLGT
; バックグラウンドスクロールレジスタを取得します。
; 行スクロールまたは列スクロールの取得が追加されています。
;共通
; <d1.b:バックグラウンド番号
; ?a0
;バックグラウンド
; <d1.w[15~8]:0
; >d2.l:X座標
; >d3.l:Y座標
; >d0.l:-1=スプライト画面を使用できない,0=正常終了
;行スクロール
; <d1.w[15~8]:1
; <d2.w:行番号
; >d0.l:-1=スプライト画面を使用できない,0~1023=X座標
;列スクロール
; <d1.w[15~8]:2
; <d2.w:列番号
; >d0.l:-1=スプライト画面を使用できない,0~1023=Y座標
iocs_C9_BGSCRLGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <cmp.w #$0100,d1>,lo ;バックグラウンド
lea.l SPRC_BG_0_X,a0
if <tst.b d1>,ne
addq.l #SPRC_BG_1_X-SPRC_BG_0_X,a0
endif
moveq.l #0,d2
moveq.l #0,d3
move.w (a0)+,d2 ;X座標
move.w (a0)+,d3 ;Y座標
moveq.l #0,d0 ;正常終了
else ;行スクロールまたは列スクロール
lea.l $00EB2000,a0 ;行スクロールレジスタ
if <cmp.w #$0200,d1>,hs
lea.l $00EB2200-$00EB2000(a0),a0 ;列スクロールレジスタ
endif
if <tst.b d1>,ne
lea.l 2*64(a0),a0
endif
move.w d2,d0 ;行番号または列番号
add.w d0,d0
movea.w (a0,d0.w),a0 ;X座標またはY座標
move.l a0,d0
endif
rts
;----------------------------------------------------------------
;IOCS $CA _BGCTRLST
; バックグラウンド制御レジスタを設定します。
;<d1.b:バックグラウンド番号
;<d2.l[31]:1=テキストエリア番号を設定しない
;<d2.b:テキストエリア番号
;<d3.l[31]:1=表示の有無を設定しない
;<d3.b:表示の有無
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_CA_BGCTRLST:
bsr check_sprite ;スプライト画面を使用できるか確認する
move.w SPRC_CONTROL,d0
if <tst.b d1>,eq ;バックグラウンド0
if <tst.l d2>,pl ;テキストエリア番号を設定する
and.w #.notw.%000_110,d0
if <tst.b d2>,ne ;テキストエリア1
addq.w #%000_010,d0
endif
endif
if <tst.l d3>,pl ;表示の有無を設定する
and.w #.notw.%000_001,d0
if <tst.b d3>,ne ;表示あり
addq.w #%000_001,d0
endif
endif
else ;バックグラウンド1
if <tst.l d2>,pl ;テキストエリア番号を設定する
and.w #.notw.%110_000,d0
if <tst.b d2>,ne ;テキストエリア1
add.w #%010_000,d0
endif
endif
if <tst.l d3>,pl ;表示の有無を設定する
and.w #.notw.%001_000,d0
if <tst.b d3>,ne ;表示あり
addq.w #%001_000,d0
endif
endif
endif
move.w d0,SPRC_CONTROL
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $CB _BGCTRLGT
; バックグラウンド制御レジスタを取得します
;<d1.b:バックグラウンド番号
;>d0.l:-1=スプライト画面を使用できない,0~7=テキストエリア番号<<1|表示の有無
;?a0
iocs_CB_BGCTRLGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
moveq.l #0,d0
move.w SPRC_CONTROL,d0
if <tst.b d1>,ne
lsr.w #3,d0
endif
and.w #%111,d0
rts
;----------------------------------------------------------------
;IOCS $CC _BGTEXTCL
; バックグラウンドテキストをキャラクタで埋め尽くします。
; 疑似グラフィック画面を作る機能が追加されています。
;<d1.w[15~8]:$00=キャラクタで埋め尽くす,$10=疑似グラフィック画面を作る
;<d1.b:テキストエリア番号
;<d2.w:キャラクタ/パレットブロック
;>d0.l:-3=拡張機能を使用できない,-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_CC_BGTEXTCL:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <cmp.w #$0FFF,d1>,ls ;キャラクタを書き込む
push d1-d4/a1-a4
movea.l text_area,a0
if <tst.b d1>,ne
lea.l 2*64*64(a0),a0
endif
move.w d2,d0
swap.w d2
move.w d0,d2
.irp rn,d1,d3,d4,a1,a2,a3,a4
move.l d2,rn
.endm
move.w #2*64*64/32-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
pop
else ;疑似グラフィック画面を作る
move.b bank_available(pc),d0
if eq ;バンクなし
moveq.l #-3,d0 ;拡張機能を使用できない
rts
endif
movea.l text_area,a0
if <tst.b d1>,ne
lea.l 2*64*64(a0),a0
endif
moveq.l #$0F,d0
and.w d2,d0 ;パレットブロック
lsl.w #8,d0 ;パターン番号上位4bit<<12|パレットブロック<<8|パターン番号下位8bit
do
do
.rept 8
move.w d0,(a0)+
addq.b #1,d0
.endm
while cc
add.w #1<<12,d0
while cc
endif
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $CD _BGTEXTST
; バックグラウンドテキストにキャラクタを書き込みます。
; 疑似グラフィック画面に書き込む機能が追加されています。
;<d1.w[15~8]:$00=キャラクタを書き込む,$10=疑似グラフィック画面に1ドット書き込む
;<d1.b:テキストエリア番号
;<d2.w:X座標
;<d3.w:Y座標
;<d4.w:キャラクタ/パレットコード
;>d0.l:-3=拡張機能を使用できない,-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_CD_BGTEXTST:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <cmp.w #$0FFF,d1>,ls ;キャラクタを書き込む
movea.l text_area,a0
if <tst.b d1>,ne
lea.l 2*64*64(a0),a0
endif
moveq.l #63,d0 ;00111111
and.b d3,d0 ;00YYYYYY
move.b d0,-(sp) ;00YYYYYY
move.w (sp)+,d0 ;00YYYYYY........
move.b d2,d0 ;00YYYYYY..XXXXXX
add.b d0,d0 ;00YYYYYY.XXXXXX0
add.b d0,d0 ;00YYYYYYXXXXXX00
lsr.w #1,d0 ;000YYYYYYXXXXXX0
move.w d4,(a0,d0.w)
else ;疑似グラフィック画面に1ドット書き込む
move.b bank_available(pc),d0
if eq ;バンクなし
moveq.l #-3,d0 ;拡張機能を使用できない
rts
endif
push d1-d3
lea.l SPRC_PATTERN,a0
moveq.l #%00011,d1
and.w SPRC_RESOLUTION-SPRC_PATTERN(a0),d1 ;水平サイズ
if eq ;8x8
ifand <cmp.w #511,d2>,ls,<cmp.w #511,d3>,ls ;範囲内
;512x512ドットの画面が64x64個の8x8ドット(32バイト)のパターンに分割されている
;画面座標(%LLLLLLTXX,%BBHHHHYYY)
;8x8パターン座標(%LLLLLL,%BBHHHH) 8x8パターン内座標(%TXX,%YYY)
;8x8パターン番号%BBHHHHLLLLLL バンク番号%BB バンク内8x8パターン番号%HHHHLLLLLL
;ワードアドレス$00EB8000+%HHHHLLLLLLYYYT0 ワード内ビット番号%XX00^%1100
moveq.l #%111,d0 ;d2.w=%LLLLLLTXX
moveq.l #%111,d1 ;d3.w=%BBHHHHYYY
and.w d2,d0 ;d0.l=%TXX
and.w d3,d1 ;d1.l=%YYY
lsr.w #3,d2 ;d2.w=%LLLLLL
eor.w d1,d3 ;d3.w=%BBHHHH000
add.w d3,d3 ;d3.w=%BBHHHH0000
move.w d3,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;%BB バンク番号
and.w #$00FF,d3 ;d3.w=%HHHH0000
add.w d3,d3 ;d3.w=%HHHH00000
add.w d3,d3 ;d3.w=%HHHH000000
or.w d3,d2 ;d2.w=%HHHHLLLLLL バンク内8x8パターン番号
lsl.w #3,d2 ;d2.w=%HHHHLLLLLL000,x=0
or.w d2,d1 ;d1.w=%HHHHLLLLLLYYY
roxr.b #3,d0 ;d0.b=%XX000000,x=T
addx.w d1,d1 ;d1.w=%HHHHLLLLLLYYYT
add.w d1,d1 ;d1.w=%HHHHLLLLLLYYYT0
adda.w d1,a0 ;a0=$00EB8000+%HHHHLLLLLLYYYT0 ワードアドレス
lsr.b #4,d0 ;d0.b=%XX00
eori.b #%1100,d0 ;d0.b=%XX00^%1100 ワード内ビット番号
moveq.l #%1111,d1
and.w d4,d1 ;d1.w=%PPPP パレットコード
move.w (a0),d3 ;ワードを読み出す
ror.w d0,d3 ;目的の位置を下位4bitへ移動する
and.w #$FFF0,d3 ;下位4bitを消す
or.w d1,d3 ;下位4bitにパレットコードを入れる
rol.w d0,d3 ;元の位置に戻す
move.w d3,(a0) ;ワードを書き戻す
endif
else ;16x16
ifand <cmp.w #1023,d2>,ls,<cmp.w #1023,d3>,ls ;範囲内
;1024x1024ドットの画面が64x64個の16x16ドット(128バイト)のパターンに分割されている
;画面座標(%LLLLLLSTXX,%BBBBHHYYYY)
;パターン座標(%LLLLLL,%BBBBHH) パターン内座標(%STXX,%YYYY)
;パターン番号%BBBBHHLLLLLL バンク番号%BBBB バンク内パターン番号%HHLLLLLL
;ワードアドレス$00EB8000+%HHLLLLLLSYYYYT0 ワード内ビット番号%XX00^%1100
moveq.l #%1111,d0 ;d2.w=%LLLLLLSTXX
moveq.l #%1111,d1 ;d3.w=%BBBBHHYYYY
and.w d2,d0 ;d0.l=%STXX
and.w d3,d1 ;d1.l=%YYYY
lsr.w #4,d2 ;d2.w=%LLLLLL
eor.w d1,d3 ;d3.w=%BBBBHH0000
add.w d3,d3 ;d3.w=%BBBBHH00000
add.w d3,d3 ;d3.w=%BBBBHH000000,x=0
move.w d3,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;%BBBB バンク番号
and.w #$00FF,d3 ;d3.w=%HH000000
or.w d3,d2 ;d2.w=%HHLLLLLL バンク内パターン番号
roxr.b #4,d0 ;d0.b=%TXX00000,x=S
addx.w d2,d2 ;d2.w=%HHLLLLLLS
lsl.w #4,d2 ;d2.w=%HHLLLLLLS0000
or.w d2,d1 ;d1.w=%HHLLLLLLSYYYY
add.b d0,d0 ;d0.b=%XX000000,x=T
addx.w d1,d1 ;d1.w=%HHLLLLLLSYYYYT
add.w d1,d1 ;d1.w=%HHLLLLLLSYYYYT0
adda.w d1,a0 ;a0=$00EB8000+%HHLLLLLLSYYYYT0 ワードアドレス
lsr.b #4,d0 ;d0.b=%XX00
eori.b #%1100,d0 ;d0.b=%XX00^%1100 ワード内ビット番号
moveq.l #%1111,d1
and.w d4,d1 ;d1.w=%PPPP パレットコード
move.w (a0),d3 ;ワードを読み出す
ror.w d0,d3 ;目的の位置を下位4bitへ移動する
and.w #$FFF0,d3 ;下位4bitを消す
or.w d1,d3 ;下位4bitにパレットコードを入れる
rol.w d0,d3 ;元の位置に戻す
move.w d3,(a0) ;ワードを書き戻す
endif
endif
pop
endif
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;IOCS $CE _BGTEXTGT
; バックグラウンドテキストからキャラクタを読み出します。
; 疑似グラフィック画面から読み出す機能が追加されています。
;<d1.w[15~8]:$00=キャラクタを読み出す,$10=疑似グラフィック画面から1ドット読み出す
;<d1.b:テキストエリア番号
;<d2.w:X座標
;<d3.w:Y座標
;>d0.l:-3=拡張機能を使用できない,-1=スプライト画面を使用できない,0~65535=キャラクタ/パレットコード
;?a0
iocs_CE_BGTEXTGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <cmp.w #$0FFF,d1>,ls ;キャラクタを読み出す
movea.l text_area,a0
if <tst.b d1>,ne
lea.l 2*64*64(a0),a0
endif
moveq.l #63,d0 ;00111111 ここで上位ワードをクリアする
and.b d3,d0 ;00YYYYYY
move.b d0,-(sp) ;00YYYYYY
move.w (sp)+,d0 ;00YYYYYY........
move.b d2,d0 ;00YYYYYY..XXXXXX
add.b d0,d0 ;00YYYYYY.XXXXXX0
add.b d0,d0 ;00YYYYYYXXXXXX00
lsr.w #1,d0 ;000YYYYYYXXXXXX0
move.w (a0,d0.w),d0
else ;疑似グラフィック画面から1ドット読み出す
move.b bank_available(pc),d0
if eq ;バンクなし
moveq.l #-3,d0 ;拡張機能を使用できない
rts
endif
push d1-d3
lea.l SPRC_PATTERN,a0
moveq.l #0,d0 ;範囲外
moveq.l #%00011,d1
and.w SPRC_RESOLUTION-SPRC_PATTERN(a0),d1 ;水平サイズ
if eq ;8x8
ifand <cmp.w #511,d2>,ls,<cmp.w #511,d3>,ls ;範囲内
;512x512ドットの画面が64x64個の8x8ドット(32バイト)のパターンに分割されている
;画面座標(%LLLLLLTXX,%BBHHHHYYY)
;8x8パターン座標(%LLLLLL,%BBHHHH) 8x8パターン内座標(%TXX,%YYY)
;8x8パターン番号%BBHHHHLLLLLL バンク番号%BB バンク内8x8パターン番号%HHHHLLLLLL
;ワードアドレス$00EB8000+%HHHHLLLLLLYYYT0 ワード内ビット番号%XX00^%1100
moveq.l #%111,d0 ;d2.w=%LLLLLLTXX
moveq.l #%111,d1 ;d3.w=%BBHHHHYYY
and.w d2,d0 ;d0.l=%TXX
and.w d3,d1 ;d1.l=%YYY
lsr.w #3,d2 ;d2.w=%LLLLLL
eor.w d1,d3 ;d3.w=%BBHHHH000
add.w d3,d3 ;d3.w=%BBHHHH0000
move.w d3,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;%BB バンク番号
and.w #$00FF,d3 ;d3.w=%HHHH0000
add.w d3,d3 ;d3.w=%HHHH00000
add.w d3,d3 ;d3.w=%HHHH000000
or.w d3,d2 ;d2.w=%HHHHLLLLLL バンク内8x8パターン番号
lsl.w #3,d2 ;d2.w=%HHHHLLLLLL000,x=0
or.w d2,d1 ;d1.w=%HHHHLLLLLLYYY
roxr.b #3,d0 ;d0.b=%XX000000,x=T
addx.w d1,d1 ;d1.w=%HHHHLLLLLLYYYT
add.w d1,d1 ;d1.w=%HHHHLLLLLLYYYT0
adda.w d1,a0 ;a0=$00EB8000+%HHHHLLLLLLYYYT0 ワードアドレス
lsr.b #4,d0 ;d0.b=%XX00
eori.b #%1100,d0 ;d0.b=%XX00^%1100 ワード内ビット番号
moveq.l #%1111,d1
and.w d4,d1 ;d1.w=%PPPP パレットコード
move.w (a0),d3 ;ワードを読み出す
ror.w d0,d3 ;目的の位置を下位4bitへ移動する
moveq.l #$0F,d0
and.w d3,d0 ;下位4bitを読み出す
endif
else ;16x16
ifand <cmp.w #1023,d2>,ls,<cmp.w #1023,d3>,ls ;範囲内
;1024x1024ドットの画面が64x64個の16x16ドット(128バイト)のパターンに分割されている
;画面座標(%LLLLLLSTXX,%BBBBHHYYYY)
;パターン座標(%LLLLLL,%BBBBHH) パターン内座標(%STXX,%YYYY)
;パターン番号%BBBBHHLLLLLL バンク番号%BBBB バンク内パターン番号%HHLLLLLL
;ワードアドレス$00EB8000+%HHLLLLLLSYYYYT0 ワード内ビット番号%XX00^%1100
moveq.l #%1111,d0 ;d2.w=%LLLLLLSTXX
moveq.l #%1111,d1 ;d3.w=%BBBBHHYYYY
and.w d2,d0 ;d0.l=%STXX
and.w d3,d1 ;d1.l=%YYYY
lsr.w #4,d2 ;d2.w=%LLLLLL
eor.w d1,d3 ;d3.w=%BBBBHH0000
add.w d3,d3 ;d3.w=%BBBBHH00000
add.w d3,d3 ;d3.w=%BBBBHH000000,x=0
move.w d3,SPRC_BANK_NUMBER-SPRC_PATTERN(a0) ;%BBBB バンク番号
and.w #$00FF,d3 ;d3.w=%HH000000
or.w d3,d2 ;d2.w=%HHLLLLLL バンク内パターン番号
roxr.b #4,d0 ;d0.b=%TXX00000,x=S
addx.w d2,d2 ;d2.w=%HHLLLLLLS
lsl.w #4,d2 ;d2.w=%HHLLLLLLS0000
or.w d2,d1 ;d1.w=%HHLLLLLLSYYYY
add.b d0,d0 ;d0.b=%XX000000,x=T
addx.w d1,d1 ;d1.w=%HHLLLLLLSYYYYT
add.w d1,d1 ;d1.w=%HHLLLLLLSYYYYT0
adda.w d1,a0 ;a0=$00EB8000+%HHLLLLLLSYYYYT0 ワードアドレス
lsr.b #4,d0 ;d0.b=%XX00
eori.b #%1100,d0 ;d0.b=%XX00^%1100 ワード内ビット番号
moveq.l #%1111,d1
and.w d4,d1 ;d1.w=%PPPP パレットコード
move.w (a0),d3 ;ワードを読み出す
ror.w d0,d3 ;目的の位置を下位4bitへ移動する
moveq.l #$0F,d0
and.w d3,d0 ;下位4bitを読み出す
endif
endif
pop
endif
rts
;----------------------------------------------------------------
;IOCS $CF _SPALET
; スプライトパレットを設定または取得します。
; パレットブロック0は指定できません。
;<d1.l[31]:1=VDISPの立ち下がりを待たない
;<d1.b:パレットブロック<<4|パレットコード
;<d2.b:パレットブロック(優先)
;<d3.l[31]:0=設定,1=取得
;<d3.w:カラーコード
;>d0.l:-2=パレットブロック0が指定された,0~65535=設定前のカラーコード
;?a0
iocs_CF_SPALET:
move.b d2,-(sp)
moveq.l #$0F,d0 ;ここで上位ワードをクリアする
and.b d1,d0 ;0<<4|パレットコード
lsl.b #4,d2 ;d2のパレットブロック<<4|0
if ne ;d2にパレットブロックがある
or.b d2,d0 ;d2のパレットブロック<<4|パレットコード
else
goto <cmp.b d1,d0>,eq,20f ;d2とd1のどちらにもパレットブロックがない
move.b d1,d0 ;d1のパレットブロック<<4|パレットコード
endif
lea.l VICON_TSPALET,a0
add.w d0,d0
adda.w d0,a0
if <tst.l d1>,pl
bsr vdisp_falling_edge ;VDISPの立ち下がりを待つ
endif
move.w (a0),d0 ;取得
if <tst.l d3>,pl
move.w d3,(a0) ;設定
endif
10: move.b (sp)+,d2
rts
20: moveq.l #-2,d0 ;パレットブロック0が指定された
goto 10b
;----------------------------------------------------------------
;デバイスドライバの末尾
device_tail:
dFLAG reg d4 ;-1=常駐していない,0=常駐部分はデバイスドライバ,1=常駐部分はメモリブロック
aRESI reg a2 ;常駐部分のプログラムの先頭。0=常駐していない
aPREV reg a3 ;デバイスドライバとして常駐しているとき直前のデバイスドライバ。さもなくば最後のデバイスドライバ
aSELF reg a4 ;自分のプログラムの先頭
r reg -program_head(aSELF)
;----------------------------------------------------------------
;デバイスコマンド0 初期化
initialize:
lea.l program_head(pc),aSELF ;自分のプログラムの先頭
;オプションを確認する
movea.l 18(a5),a0 ;引数の並び。区切りは0、末尾は0,0。先頭はデバイスファイル名
do
while <tst.b (a0)+>,ne ;デバイスファイル名を読み飛ばす
dostart
gotoand <cmp.b #'-',d0>,ne,<cmp.b #'/',d0>,ne,option_error ;1文字目が-,/でない
move.b (a0)+,d0 ;2文字目
goto eq,option_error ;-,/の後に文字がない
jbsr tolower
if <cmp.b #'d',d0>,eq ;-d 後始末なし
goto <tst.b (enable_flag)r>,ne,option_error ;-d -eは同時に指定できない
st.b (disable_flag)r
elif <cmp.b #'e',d0>,eq ;-e 後始末あり
goto <tst.b (disable_flag)r>,ne,option_error ;-d -eは同時に指定できない
st.b (enable_flag)r
elif <cmp.b #'q',d0>,eq ;-q 静粛
st.b (quiet_flag)r
else
goto option_error
endif
tst.b (a0)+ ;引数の区切り
goto ne,option_error ;余分な文字がある
start
move.b (a0)+,d0 ;次の引数の1文字目
while ne
;後始末の設定
if <tst.b (disable_flag)r>,ne ;後始末なし
sf.b (cleanup_flag)r
elif <tst.b (enable_flag)r>,ne ;後始末あり
st.b (cleanup_flag)r
endif
;ベクタを変更する
lea.l vector_table(pc),a0 ;ベクタテーブル
bsr set_vector ;ベクタを変更する
;改行とタイトルを表示する
if <tst.b (quiet_flag)r>,eq
jbsr printcrlf
lea.l title_message(pc),a0
jbsr print
endif
;デバイスドライバの末尾を設定して正常終了する
move.l #device_tail,14(a5) ;デバイスドライバの末尾
moveq.l #0,d0 ;正常終了する
rts
;オプションエラー
option_error:
;改行とエラーメッセージを表示する。-qは無効
jbsr printcrlf
lea.l program_colon(pc),a0
jbsr print
lea.l wrong_message(pc),a0
jbsr print
;デバイスドライバを組み込まない
move.w #ABORT|MISCELLANEOUS_ERROR,d0 ;中止(A) エラーが発生しました
rts
;----------------------------------------------------------------
;実行開始
execution_start:
lea.l program_head(pc),aSELF ;自分のプログラムの先頭
;オプションを確認する
lea.l 1(a2),a0 ;コマンドライン
dostart
addq.l #1,a0
gotoand <cmp.b #'-',d0>,ne,<cmp.b #'/',d0>,ne,usage_exit ;1文字目が-,/でない
move.b (a0)+,d0 ;2文字目
goto eq,usage_exit ;-,/の後に文字がない
jbsr tolower
if <cmp.b #'c',d0>,eq ;-c 常駐確認
gotoor <tst.b (release_flag)r>,ne,<tst.b (version_flag)r>,ne,usage_exit ;-c -r -vは同時に指定できない
st.b (check_flag)r
elif <cmp.b #'d',d0>,eq ;-d 後始末なし
gotoor <tst.b (enable_flag)r>,ne,<tst.b (release_flag)r>,ne,usage_exit ;-d -e -rは同時に指定できない
st.b (disable_flag)r
elif <cmp.b #'e',d0>,eq ;-e 後始末あり
gotoor <tst.b (disable_flag)r>,ne,<tst.b (release_flag)r>,ne,usage_exit ;-d -e -rは同時に指定できない
st.b (enable_flag)r
elif <cmp.b #'q',d0>,eq ;-q 静粛
st.b (quiet_flag)r
elif <cmp.b #'r',d0>,eq ;-r 常駐解除
gotoor <tst.b (check_flag)r>,ne,<tst.b (version_flag)r>,ne,usage_exit ;-c -r -vは同時に指定できない
gotoor <tst.b (disable_flag)r>,ne,<tst.b (enable_flag)r>,ne,usage_exit ;-d -e -rは同時に指定できない
st.b (release_flag)r
elif <cmp.b #'v',d0>,eq ;-v バージョン確認
gotoor <tst.b (check_flag)r>,ne,<tst.b (release_flag)r>,ne,usage_exit ;-c -r -vは同時に指定できない
st.b (version_flag)r
else
goto usage_exit
endif
move.b (a0),d0 ;次の文字
break eq
jbsr isspace
goto ne,usage_exit ;余分な文字がある
start
jbsr nextword ;空白を読み飛ばす
while ne
;スーパーバイザモードへ移行する
supervisormode
;常駐部分を探す
do
;デバイスドライバを探す
moveq.l #0,dFLAG ;常駐部分はデバイスドライバ
movea.l DOS_HUMAN_MEMORY.w,a0 ;Human68kの先頭。これより手前はスーパーバイザスタックエリア
move.w #'NU',d0 ;NULデバイスドライバ=デバイスドライバのリストの先頭を探す。必ずある
lea.l DH_NAME(a0),a0
do
do
while <cmp.w (a0)+,d0>,ne
whileor <cmpi.l #'L ',2-2(a0)>,ne,<cmpi.w #' ',6-2(a0)>,ne,<cmpi.w #$8024,DH_TYPE-(DH_NAME+2)(a0)>,ne
lea.l -(DH_NAME+2)(a0),aRESI ;NULデバイスドライバ
movem.l DH_NAME(aSELF),d0-d1 ;自分のデバイス名
do
break2and <cmp.l DH_NAME(aRESI),d0>,eq,<cmp.l DH_NAME+4(aRESI),d1>,eq ;デバイス名が同じ
movea.l aRESI,aPREV ;デバイスドライバ→直前のデバイスドライバ
movea.l DH_NEXT(aRESI),aRESI ;次のデバイスドライバ
while <cmpa.w #-1,aRESI>,ne
;メモリブロックを探す
moveq.l #1,dFLAG ;常駐部分はメモリブロック
movea.l DOS_HUMAN_MEMORY.w,aRESI ;メモリブロックのリストの先頭
dostart
if <cmpi.b #-1,MM_PARENT(aRESI)>,eq ;常駐している。自分はここで取り除く
lea.l MM_PROGRAM+DH_NAME+8(aRESI),a0 ;常駐部分のデバイス名の直後
ifand <cmpa.l MM_TAIL(aRESI),a0>,ls,<cmp.l -(a0),d1>,eq,<cmp.l -(a0),d0>,eq ;長さが足りていてデバイス名が同じ
lea.l MM_PROGRAM(aRESI),aRESI ;常駐部分のプログラムの先頭
break2
endif
endif
start
movea.l MM_NEXT(aRESI),aRESI ;次のメモリ管理テーブル
while <cmpa.w #0,aRESI>,ne
moveq.l #-1,dFLAG ;常駐していない
while f
;<dFLAG.l:-1=常駐していない,0=常駐部分はデバイスドライバ,1=常駐部分はメモリブロック
;<aRESI.l:常駐部分のプログラムの先頭。0=常駐していない
;<aPREV.l:デバイスドライバとして常駐しているとき直前のデバイスドライバ。さもなくば最後のデバイスドライバ
;バージョン確認
if <tst.b (version_flag)r>,ne ;バージョン確認
moveq.l #1,d1 ;タイトル
moveq.l #0,d2 ;正常終了
goto message_exit
endif
;常駐確認
if <tst.b (check_flag)r>,ne ;常駐確認
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #2,d2 ;エラー終了。常駐しています
lea.l already_message(pc),a1 ;常駐しています
if <tst.l dFLAG>,mi ;常駐していない
moveq.l #3,d2 ;エラー終了。常駐していません
lea.l not_yet_message(pc),a1 ;常駐していません
endif
goto message_exit
endif
;後始末の設定
if <tst.b (disable_flag)r>,ne ;後始末なし
sf.b (cleanup_flag)r
elif <tst.b (enable_flag)r>,ne ;後始末あり
st.b (cleanup_flag)r
endif
;解除
if <tst.b (release_flag)r>,ne ;解除
;常駐していないのに解除しようとしたらエラー
if <tst.l dFLAG>,mi ;常駐していない
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #3,d2 ;エラー終了。常駐していません
lea.l not_yet_message(pc),a1 ;常駐していません
goto message_exit
endif
;ベクタが変更されていたらエラー
lea.l (vector_table-program_head)(aRESI),a0 ;常駐部分のベクタテーブル
bsr check_vector ;ベクタを確認する
if ne ;ベクタが変更されている
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #4,d2 ;エラー終了。ベクタが変更されています。解除できません
lea.l vector_message(pc),a1 ;ベクタが変更されています。解除できません
goto message_exit
endif
;初期化する
moveq.l #0,d1
bsr iocs_C0_SP_INIT
;ベクタを復元する
lea.l (vector_table-program_head)(aRESI),a0 ;常駐部分のベクタテーブル
bsr release_vector ;ベクタを復元する
;デバイスドライバを切り離す/メモリブロックを開放する
if <tst.l dFLAG>,eq ;常駐部分はデバイスドライバ
move.l DH_NEXT(aRESI),DH_NEXT(aPREV) ;直前のデバイスドライバの次のデバイスドライバは次のデバイスドライバ(-1を含む)
else ;常駐部分はメモリブロック
pea.l MM_SIZE-MM_PROGRAM(aRESI) ;常駐部分のメモリブロックの先頭
DOS _MFREE
addq.l #4,sp
endif
;正常終了する
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #0,d2 ;正常終了
lea.l released_message(pc),a1 ;解除しました
goto message_exit
endif
;常駐しているのに常駐しようとしたらエラー
if <tst.l dFLAG>,pl ;常駐している
;設定変更
ifor <tst.b (disable_flag)r>,ne,<tst.b (enable_flag)r>,ne
move.b (cleanup_flag)r,cleanup_flag-program_head(aRESI)
lea.l disabled_message(pc),a0 ;後始末なし
if ne ;後始末あり
lea.l enabled_message(pc),a0 ;後始末あり
endif
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #0,d2 ;正常終了
goto message_exit
endif
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #2,d2 ;エラー終了。常駐しています
lea.l already_message(pc),a1 ;常駐しています
goto message_exit
endif
;ベクタを変更する
lea.l vector_table(pc),a0 ;ベクタテーブル
bsr set_vector ;ベクタを変更する
;デバイスドライバを接続する
; move.l aSELF,(aPREV) ;最後のデバイスドライバの次のデバイスドライバを自分にする
;初期化する
moveq.l #0,d1
bsr iocs_C0_SP_INIT
;常駐終了する
moveq.l #1+2+4,d1 ;タイトルとプログラム名とメッセージ
moveq.l #-1,d2 ;常駐終了
lea.l resident_message(pc),a1 ;常駐しました
goto message_exit
;ユーザモードへ復帰して終了する
;<d1.l:1=タイトルを表示する,2=プログラム名を表示する,4=メッセージを表示する
;<d2.w:終了コード。-1=常駐終了,0=正常終了,1~=エラー終了
;<a1.l:メッセージ
message_exit:
;ユーザモードへ復帰する
usermode
if <tst.b (quiet_flag)r>,eq
if <btst.l #0,d1>,ne ;タイトルを表示する
lea.l title_message(pc),a0
jbsr print
endif
if <btst.l #1,d1>,ne ;プログラム名を表示する
lea.l program_colon(pc),a0
jbsr print
endif
if <btst.l #2,d1>,ne ;メッセージを表示する
movea.l a1,a0
jbsr print
endif
endif
;終了する
if <tst.w d2>,mi ;常駐終了
clr.w -(sp)
move.l #device_tail-program_head,-(sp)
DOS _KEEPPR
endif
move.w d2,-(sp)
DOS _EXIT2
;タイトルと使用法を表示して終了する
usage_exit:
;タイトルと使用法を表示する。-qは無効
lea.l title_message(pc),a0
jbsr print
lea.l usage_message(pc),a0
jbsr print
;終了する
move.w #1,-(sp)
DOS _EXIT2
;----------------------------------------------------------------
;ベクタを変更する
; スーパーバイザモードで呼び出すこと
;<a0.l:ベクタテーブル
set_vector:
push d0/a0-a1
dostart
movea.w d0,a1 ;オフセット
move.l (a1),d0
move.l (a0)+,(a1) ;新しいベクタ
move.l d0,(a0)+ ;古いベクタ
start
move.w (a0)+,d0
while ne
pop
rts
;----------------------------------------------------------------
;ベクタを確認する
; スーパーバイザモードで呼び出すこと
;<a0.l:常駐部分のベクタテーブル
;>ccr:eq=ベクタは変更されていない,ne=ベクタが変更されている
check_vector:
push d0/a0-a1
dostart
movea.w d0,a1 ;オフセット
move.l (a1),d0
break <cmp.l (a0)+,d0>,ne ;新しいベクタが現在のベクタと一致しなければ失敗
addq.l #4,a0 ;古いベクタを読み飛ばす
start
move.w (a0)+,d0
while ne
pop
rts
;----------------------------------------------------------------
;ベクタを復元する
; スーパーバイザモードで呼び出すこと
;<a0.l:常駐部分のベクタテーブル
release_vector:
push d0/a0-a1
dostart
movea.w d0,a1 ;オフセット
addq.l #4,a0 ;新しいベクタを読み飛ばす
move.l (a0)+,(a1) ;古いベクタ
start
move.w (a0)+,d0
while ne
pop
rts
;----------------------------------------------------------------
;文字列
.if ENGLISH
title_message:
.dc.b ENGLISH_TITLE,' ',VERSION_STRING,13,10,0
program_colon:
.dc.b PROGRAMEN_NAME,': ',0
usage_message:
.dc.b ' device = ',PROGRAM_NAME,' <option>',13,10
.dc.b ' or',13,10
.dc.b ' A>',PROGRAM_NAME,' <option>',13,10
.dc.b ' -c Resident check',10
.dc.b ' -d Disable cleanup',10
.dc.b ' -e Enable cleanup',10
.dc.b ' -q Quiet',13,10
.dc.b ' -r Release',13,10
.dc.b ' -v Version check',13,10,0
wrong_message:
.dc.b 'Wrong option',13,10,0
already_message:
.dc.b 'Already resident',13,10,0
resident_message:
.dc.b 'Resident',13,10,0
not_yet_message:
.dc.b 'Not yet resident',13,10,0
vector_message:
.dc.b 'Vector has been changed, unable to release',13,10,0
released_message:
.dc.b 'Released',13,10,0
disabled_message:
.dc.b 'Cleanup is disabled',13,10,0
enabled_message:
.dc.b 'Cleanup is enabled',13,10,0
.else
title_message:
.dc.b JAPANESE_TITLE,' ',VERSION_STRING,13,10,0
program_colon:
.dc.b PROGRAM_NAME,': ',0
usage_message:
.dc.b ' device = ',PROGRAM_NAME,' <オプション>',13,10
.dc.b ' または',13,10
.dc.b ' A>',PROGRAM_NAME,' <オプション>',13,10
.dc.b ' -c 常駐確認',13,10
.dc.b ' -d 後始末なし',10
.dc.b ' -e 後始末あり',10
.dc.b ' -q 静粛',13,10
.dc.b ' -r 常駐解除',13,10
.dc.b ' -v バージョン確認',13,10,0
wrong_message:
.dc.b 'オプションが違います',13,10,0
already_message:
.dc.b '常駐しています',13,10,0
resident_message:
.dc.b '常駐しました',13,10,0
not_yet_message:
.dc.b '常駐していません',13,10,0
vector_message:
.dc.b 'ベクタが変更されています。解除できません',13,10,0
released_message:
.dc.b '解除しました',13,10,0
disabled_message:
.dc.b '後始末なし',13,10,0
enabled_message:
.dc.b '後始末あり',13,10,0
.endif
.even
.data
;----------------------------------------------------------------
;フラグ
check_flag:
.dc.b 0 ;-c 常駐確認
disable_flag:
.dc.b 0 ;-d 後始末なし
enable_flag:
.dc.b 0 ;-e 後始末あり
quiet_flag:
.dc.b 0 ;-q 静粛
release_flag:
.dc.b 0 ;-r 常駐解除
version_flag:
.dc.b 0 ;-v バージョン確認
.even
.text
.even
;----------------------------------------------------------------
;空白文字か \s
;<d0.b:文字
;>z:eq=空白文字,ne=空白文字ではない(0を含む)
isspace::
if <cmp.b #' ',d0>,ne
ifand <cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls ;\t\n\v\f\r
cmp.b d0,d0
endif
endif
rts
;----------------------------------------------------------------
;空白を読み飛ばす
;<a0.l:文字列
;>d0.l:最初の空白以外の文字または0
;>a0.l:最初の空白以外の文字または0の位置
;>z:ne=空白以外の文字がある,eq=空白以外の文字がない
nextword::
moveq.l #0,d0
do
move.b (a0)+,d0 ;次の文字
break eq ;0ならば終了
jbsr isspace ;空白か
while eq ;空白ならば繰り返す
subq.l #1,a0 ;進み過ぎた分戻る
tst.l d0
rts
;----------------------------------------------------------------
;文字列を表示する
;<a0.l:文字列
print::
push d0
jbsr strlen
move.l d0,-(sp)
move.l a0,-(sp)
move.w #1,-(sp)
DOS _WRITE
lea.l (10,sp),sp
pop
rts
;----------------------------------------------------------------
;改行を表示する
printcrlf::
move.l a0,-(sp)
lea.l 100f(pc),a0 ;13,10
jbsr print
movea.l (sp)+,a0
rts
100: .dc.b 13,10,0
.even
;----------------------------------------------------------------
;文字列比較
;<a0.l:文字列0
;<a1.l:文字列1
;>ccr:eq=文字列0==文字列1,lo=文字列0<文字列1,hi=文字列1<文字列0
strcmp::
push d0/a0-a1
do
move.b (a0)+,d0
if eq
cmp.b (a1)+,d0
break
endif
cmp.b (a1)+,d0
while eq
pop
rts
;----------------------------------------------------------------
;文字列の長さを数える
;<a0.l:文字列
;>d0.l:長さ
strlen::
move.l a0,d0 ;d0=先頭
do
while <tst.b (a0)+>,ne ;0の次の位置まで進む
subq.l #1,a0 ;進み過ぎた分戻る。a0=0の位置
exg.l d0,a0 ;d0=末尾,a0=先頭
sub.l a0,d0 ;d0=末尾-先頭=長さ
rts
;----------------------------------------------------------------
;小文字にする
;<d0.b:文字
;>d0.b:文字
tolower::
ifand <cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls ;大文字
add.b #'a'-'A',d0 ;小文字にする
endif
rts
;----------------------------------------------------------------
;プログラムの末尾
.bss
.even
program_end:
.end execution_start