misc/fullpat.s
;========================================================================================
; fullpat.s
; Copyright (C) 2003-2026 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/
;========================================================================================
.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 '/*FLPT*/'
TITLE_STRING reg 'フルパターンメモリドライバ'
PROGRAM_NAME reg 'fullpat.x'
MAGIC_CODE equ 'FLPT'
VERSION_CODE equ '1.00'
VERSION_STRING reg '1.00'
EXPAND_LOOP equ 1 ;ループを展開する
;----------------------------------------------------------------
;プログラムの先頭
.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
;リクエストヘッダのアドレス
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
;----------------------------------------------------------------
;ワークエリア
extended_1xx1x:
.dc.b 1 ;%1xx1xのときスプライト画面を使用できるか。-1=使える,0=使えない,1=未確認
.even
;----------------------------------------------------------------
;スプライト画面を使用できるか確認する
; IOCSコールの先頭で呼び出す
; スプライト画面を使用できるとき何もしない
; スプライト画面を使用できないときd0.l=-1でIOCSコールを終了する
;?d0
check_sprite:
moveq.l #.not.%10010,d0
or.b CRTC_RESOLUTION_BYTE,d0 ;R20L。%1xx1xのときだけ%11111111
not.b d0 ;%1xx1xのときだけ%00000000
if eq ;%1xx1x。使用できない
moveq.l #-1,d0 ;スプライト画面を使用できない
addq.l #4,sp ;IOCSコールを終了する
endif
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
;マジックコード
magic_code:
.dc.l MAGIC_CODE
;バージョンコード
version_code:
.dc.l VERSION_CODE
;----------------------------------------------------------------
;$C0 SP_INIT
; スプライト・バックグラウンドを初期化します。
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C0_SP_INIT:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1-d5/a1-a4/a6
lea.l SPRC_CONTROL,a5
;d1-d4/a1-a4をゼロにする
moveq.l #0,d1
.irp rn,d2,d3,d4,a1,a2,a3,a4
move.l d1,rn
.endm
;スプライトコントロールレジスタとパターンとテキストエリアをゼロクリアする
move.w #$0400,d5 ;MPUCS。$0400=後半,$0000=前半
do
move.w d5,(a5)
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
.if EXPAND_LOOP
moveq.l #128*256/32/8-1,d0
for d0
.rept 8
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
.endm
next
.else
moveq.l #128*256/32-1,d0
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
next
.endif
eor.w #$0400,d5
while eq
;バックグラウンドスクロールレジスタをゼロクリアする
movem.l d1-d2,SPRC_BG_0_X-SPRC_CONTROL(a5)
;スプライトスクロールレジスタをゼロクリアする
lea.l SPRC_SCROLL-SPRC_CONTROL(a5),a0
.if EXPAND_LOOP
moveq.l #8*128/32/8-1,d0 ;128枚
for d0
.rept 8
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
.endm
next
.else
moveq.l #8*128/32-1,d0 ;128枚
for d0
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
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
moveq.l #0,d0 ;正常終了
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=白
;----------------------------------------------------------------
;$C1 SP_ON
; スプライト・バックグラウンド画面を表示します。
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
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
;----------------------------------------------------------------
;$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
;----------------------------------------------------------------
;$C3 SP_CGCLR
; パターンをゼロクリアします。
;<d1.w:パターン番号。0~511
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
; MPUCSは入力は不定、出力は0
iocs_C3_SP_CGCLR:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1/d5/a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
move.w d1,d0
and.w #$0100,d0
lsl.w #2,d0 ;bit8→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
and.w #$00FF,d1
lsl.w #7,d1 ;*128
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
adda.w d1,a0
moveq.l #0,d0
.if EXPAND_LOOP
.rept 128/4
move.l d0,(a0)+
.endm
.else
moveq.l #128/4-1,d1
for d1
move.l d0,(a0)+
next
.endif
move.w d5,(a5) ;MPUCSをクリア
; moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;$C4 SP_DEFCG
; パターンを設定します。
;<d1.w:パターン番号。0~511
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
; MPUCSは入力は不定、出力は0
iocs_C4_SP_DEFCG:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1/d5/a1/a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
move.w d1,d0
if <tst.b d2>,eq ;8x8
and.w #$0400,d0
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
and.w #$03FF,d1
lsl.w #5,d1 ;*32
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
adda.w d1,a0
.if EXPAND_LOOP
.rept 32/4
move.l (a1)+,(a0)+
.endm
.else
moveq.l #32/4-1,d1
for d1
move.l (a1)+,(a0)+
next
.endif
else ;16x16
and.w #$0100,d0
lsl.w #2,d0 ;bit8→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
and.w #$00FF,d1
lsl.w #7,d1 ;*128
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
adda.w d1,a0
.if EXPAND_LOOP
.rept 128/4
move.l (a1)+,(a0)+
.endm
.else
moveq.l #128/4-1,d1
for d1
move.l (a1)+,(a0)+
next
.endif
endif
move.w d5,(a5) ;MPUCSをクリア
moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;$C5 SP_GTPCG
; パターンを取得します。
;<d1.w:パターン番号。0~511
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
; MPUCSは入力は不定、出力は0
iocs_C5_SP_GTPCG:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1/d5/a1/a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
move.w d1,d0
if <tst.b d2>,eq ;8x8
and.w #$0400,d0
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
and.w #$03FF,d1
lsl.w #5,d1 ;*32
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
adda.w d1,a0
.if EXPAND_LOOP
.rept 32/4
move.l (a0)+,(a1)+
.endm
.else
moveq.l #32/4-1,d1
for d1
move.l (a0)+,(a1)+
next
.endif
else ;16x16
and.w #$0100,d0
lsl.w #2,d0 ;bit8→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
and.w #$00FF,d1
lsl.w #7,d1 ;*128
lea.l SPRC_PATTERN-SPRC_CONTROL(a5),a0
adda.w d1,a0
.if EXPAND_LOOP
.rept 128/4
move.l (a0)+,(a1)+
.endm
.else
moveq.l #128/4-1,d1
for d1
move.l (a0)+,(a1)+
next
.endif
endif
move.w d5,(a5) ;MPUCSをクリア
moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;$C6 SP_REGST
; スプライトスクロールレジスタを設定します。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.w:スプライト番号。0~127
;<d2.l bit31:X座標の設定。0=する。1=しない
;<d2.w:X座標。0~1023
;<d3.l bit31:Y座標の設定。0=する,1=しない
;<d3.w:Y座標。0~1023
;<d4.l bit31:キャラクタの設定。0=する,1=しない
;<d4.w:キャラクタ。0~65535
;<d5.l bit31:プライオリティの設定。0=する,1=しない
;<d5.w:プライオリティ。0~7
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C6_SP_REGST:
bsr check_sprite ;スプライト画面を使用できるか確認する
moveq.l #$7F,d0 ;ここで上位ワードをクリアする
and.w d1,d0
lsl.w #3,d0
lea.l SPRC_SCROLL,a0
adda.l 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
move.w d5,6(a0) ;プライオリティ
endif
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;$C7 SP_REGGT
; スプライトスクロールレジスタを取得します。
;<d1.w:スプライト番号。0~127
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;>d2.l:X座標。0~1023
;>d3.l:Y座標。0~1023
;>d4.l:キャラクタ。0~65535
;>d5.l:プライオリティ。0~7
;?a0
iocs_C7_SP_REGGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
moveq.l #$7F,d0 ;ここで上位ワードをクリアする
and.w d1,d0
lsl.w #3,d0
lea.l SPRC_SCROLL,a0
adda.l d0,a0
moveq.l #0,d2
moveq.l #0,d3
moveq.l #0,d4
moveq.l #0,d5
move.w (a0)+,d2 ;X座標
move.w (a0)+,d3 ;Y座標
move.w (a0)+,d4 ;キャラクタ
move.w (a0)+,d5 ;プライオリティ
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;$C8 BGSCRLST
; バックグラウンドスクロールレジスタを設定します。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.b:バックグラウンド番号。0~1
;<d2.l bit31:X座標の設定。0=する。1=しない
;<d2.w:X座標。0~1023
;<d3.l bit31:Y座標の設定。0=する,1=しない
;<d3.w:Y座標。0~1023
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C8_BGSCRLST:
bsr check_sprite ;スプライト画面を使用できるか確認する
if <tst.l d1>,pl
bsr vdisp_falling_edge ;VDISPの立ち下がりを待つ
endif
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
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;$C9 BGSCRLGT
; バックグラウンドスクロールレジスタを取得します。
;<d1.b:バックグラウンド番号。0~1
;>d2.l:X座標。0~1023
;>d3.l:Y座標。0~1023
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C9_BGSCRLGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
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 ;正常終了
rts
;----------------------------------------------------------------
;$CA BGCTRLST
; バックグラウンド制御レジスタを設定します。
;<d1.b:バックグラウンド番号。0~1
;<d2.l bit31:テキスト番号の設定。0=する,1=しない
;<d2.b:テキスト番号。0~3
;<d3.l bit31:表示の有無の設定。0=する,1=しない
;<d3.b:表示の有無。0~1
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_CA_BGCTRLST:
bsr check_sprite ;スプライト画面を使用できるか確認する
move.w SPRC_CONTROL,d0
if <tst.b d1>,ne ;バックグラウンド1
ror.w #3,d0
endif
if <tst.l d2>,pl
and.b #.notb.%110,d0
move.b d2,-(sp)
and.b #3,d2 ;テキスト番号
add.b d2,d2
or.b d2,d0
move.b (sp)+,d2
endif
if <tst.l d3>,pl
and.b #.notb.%001,d0
if <tst.b d3>,ne ;表示する
addq.b #%001,d0
endif
endif
if <tst.b d1>,ne ;バックグラウンド1
rol.w #3,d0
endif
move.w d0,SPRC_CONTROL
moveq.l #0,d0 ;正常終了
rts
;----------------------------------------------------------------
;$CB BGCTRLGT
; バックグラウンド制御レジスタを取得します。
;<d1.b:バックグラウンド番号。0~1
;>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 ;バックグラウンド1
lsr.w #3,d0
endif
and.w #%111,d0
rts
;----------------------------------------------------------------
;$CC BGTEXTCL
; バックグラウンドテキストをキャラクタで埋め尽くします。
;<d1.b:テキスト番号。0~3
;<d2.w:キャラクタ。0~65535
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
; MPUCSは入力は不定、出力は0
iocs_CC_BGTEXTCL:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d1-d5/a1-a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
moveq.l #$02,d0
and.b d1,d0
ror.w #7,d0 ;bit1→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
moveq.l #$01,d0 ;ここで上位ワードをクリアする
and.b d1,d0
ror.w #3,d0 ;bit0→bit13 2*64*64
lea.l SPRC_TEXT_0,a0
adda.l d0,a0
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
moveq.l #2*64*64/32/8-1,d0
for d0
.rept 8
movem.l d1-d4/a1-a4,(a0)
lea.l 32(a0),a0
.endm
next
move.w d5,(a5) ;MPUCSをクリア
moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;$CD BGTEXTST
; バックグラウンドテキストにキャラクタを書き込みます。
;<d1.b:テキスト番号。0~3
;<d2.w:X座標。0~63
;<d3.w:Y座標。0~63
;<d4.w:キャラクタ。0~65535
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
; MPUCSは入力は不定、出力は0
iocs_CD_BGTEXTST:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d5/a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
moveq.l #$02,d0
and.b d1,d0
ror.w #7,d0 ;bit1→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
moveq.l #$01,d0 ;ここで上位ワードをクリアする
and.b d1,d0
ror.w #3,d0 ;bit0→bit13 2*64*64
lea.l SPRC_TEXT_0,a0
adda.l d0,a0
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) ;キャラクタ
move.w d5,(a5) ;MPUCSをクリア
moveq.l #0,d0 ;正常終了
pop
rts
;----------------------------------------------------------------
;$CE BGTEXTGT
; バックグラウンドテキストからキャラクタを読み出します。
;<d1.b:テキスト番号。0~3
;<d2.w:X座標。0~63
;<d3.w:Y座標。0~63
;>d0.l:-1=スプライト画面を使用できない,0~65535=キャラクタ
;?a0
; MPUCSは入力は不定、出力は0
iocs_CE_BGTEXTGT:
bsr check_sprite ;スプライト画面を使用できるか確認する
push d5/a5
lea.l SPRC_CONTROL,a5
move.w (a5),d5
and.w #.notw.$0400,d5 ;MPUCSをクリアした値
moveq.l #$02,d0
and.b d1,d0
ror.w #7,d0 ;bit1→bit10
or.w d5,d0
move.w d0,(a5) ;MPUCSを変更
moveq.l #$01,d0 ;ここで上位ワードをクリアする
and.b d1,d0
ror.w #3,d0 ;bit0→bit13 2*64*64
lea.l SPRC_TEXT_0,a0
adda.l d0,a0
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
; moveq.l #0,d0
move.w (a0,d0.w),d0 ;キャラクタ
move.w d5,(a5) ;MPUCSをクリア
pop
rts
;----------------------------------------------------------------
;$CF SPALET
; スプライトパレットを設定または取得します。
; パレットブロック0は指定できません。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.b:パレットブロック<<4|パレットコード。0~255
;<d2.b:パレットブロック。0~15
;<d3.l bit31:モード。0=設定,1=取得
;<d3.w:カラーコード。0~65535
;>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
add.w d0,d0
lea.l VICON_TSPALET,a0
adda.l 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 #'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
;ベクタを変更する
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:
lea.l wrong_message(pc),a1 ;オプションが違います
;改行とプログラム名とエラーメッセージを表示する。-qは無効
;<a1.l:メッセージ
device_error:
jbsr printcrlf
lea.l program_colon(pc),a0
jbsr print
movea.l a1,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,option_exit ;1文字目が-,/でない
move.b (a0)+,d0 ;2文字目
goto eq,option_exit ;-,/の後に文字がない
jbsr tolower
if <cmp.b #'c',d0>,eq ;-c 常駐確認
st.b (check_flag)r
elifor <cmp.b #'h',d0>,eq,<cmp.b #'?',d0>,eq ;-h/-? 使用法表示
st.b (help_flag)r
elif <cmp.b #'k',d0>,eq ;-k 常駐
st.b (keep_flag)r
elif <cmp.b #'q',d0>,eq ;-q メッセージ非表示
st.b (quiet_flag)r
elif <cmp.b #'r',d0>,eq ;-r 常駐解除
st.b (release_flag)r
elif <cmp.b #'v',d0>,eq ;-v バージョン確認
st.b (version_flag)r
else
goto option_exit
endif
move.b (a0),d0 ;次の文字
break eq
jbsr isspace
goto ne,option_exit ;余分な文字がある
start
jbsr nextword ;空白を読み飛ばす
while ne
;-c -h/-? -k -r -vは同時に指定できない
move.b (check_flag)r,d0
add.b (help_flag)r,d0
goto cs,option_exit
add.b (keep_flag)r,d0
goto cs,option_exit
add.b (release_flag)r,d0
goto cs,option_exit
add.b (version_flag)r,d0
goto cs,option_exit
;スーパーバイザモードへ移行する
supervisormode
;使用法表示
goto <tst.b (help_flag)r>,ne,help_exit ;使用法表示
;バージョン確認
if <tst.b (version_flag)r>,ne ;バージョン確認
moveq.l #1,d1 ;タイトル
moveq.l #0,d2 ;正常終了
goto message_exit
endif
;常駐部分を探す
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+iocs_C0_SP_INIT-program_head(aRESI),a0 ;常駐部分のSP_INIT
ifand <cmpa.l MM_TAIL(aRESI),a0>,ls,<cmp.l program_head+DH_NAME-iocs_C0_SP_INIT(a0),d0>,eq,<cmp.l program_head+DH_NAME+4-iocs_C0_SP_INIT(a0),d1>,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 (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 (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
;常駐部分のバージョンが違ったらエラー
; ベクタが変更されていないか確認する前に行うこと
; 常駐部分のメモリブロックの長さは確認済み
move.l version_code-program_head(aRESI),d0 ;常駐部分のバージョンコード
if <cmp.l version_code(pc),d0>,ne ;バージョンコードが違う
moveq.l #2+4,d1 ;プログラム名とメッセージ
moveq.l #5,d2 ;エラー終了。常駐部分のバージョンが違います。解除できません
lea.l version_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.b (keep_flag)r>,ne ;常駐
;常駐しているのに常駐しようとしたらエラー
if <tst.l dFLAG>,pl ;常駐している
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 #2+4,d1 ;プログラム名とメッセージ
moveq.l #-1,d2 ;常駐終了
lea.l resident_message(pc),a1 ;常駐しました
goto message_exit
endif
;使用法を表示して正常終了する
help_exit:
moveq.l #1+4,d1 ;タイトルとメッセージ
moveq.l #0,d2 ;正常終了
lea.l help_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
;オプションが違う
option_exit:
;プログラム名とエラーメッセージとタイトルと使用法を表示する。-qは無効
lea.l program_colon(pc),a0
jbsr print
lea.l wrong_message(pc),a0 ;オプションが違います
jbsr print
lea.l title_message(pc),a0
jbsr print
lea.l help_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
;----------------------------------------------------------------
;文字列
title_message:
.dc.b TITLE_STRING,' ',PROGRAM_NAME,' version ',VERSION_STRING,13,10,0
program_colon:
.dc.b PROGRAM_NAME,': ',0
help_message:
.dc.b '機能',13,10
.dc.b 9,'スプライト関連のIOCSコールをフルパターンメモリに対応させます。',13,10
.dc.b '使用法',13,10
.dc.b 9,'CONFIG.SYS',13,10
.dc.b 9,9,'device=',PROGRAM_NAME,' オプション',13,10
.dc.b 9,'コマンドライン',13,10
.dc.b 9,9,'A>',PROGRAM_NAME,' オプション',13,10
.dc.b 9,'オプション',13,10
.dc.b 9,9,'-c',9,'常駐確認',13,10
.dc.b 9,9,'-h/-?',9,'使用法表示',13,10
.dc.b 9,9,'-k',9,'常駐',13,10
.dc.b 9,9,'-q',9,'メッセージ非表示',13,10
.dc.b 9,9,'-r',9,'常駐解除',13,10
.dc.b 9,9,'-v',9,'バージョン確認',13,10
.dc.b 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
version_message:
.dc.b '常駐部分のバージョンが違います。解除できません',13,10,0
released_message:
.dc.b '解除しました',13,10,0
.even
.data
;----------------------------------------------------------------
;フラグ
check_flag:
.dc.b 0 ;-c 常駐確認
help_flag:
.dc.b 0 ;-h/-? 使用法表示
keep_flag:
.dc.b 0 ;-k 常駐
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:文字列
;>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