PC-6001mkII/PC-6601用 ちょっとだけ高速な文字表示ルーチン

はじめに

PC-6001mkII/PC-6601は、グラフィック画面へのPRINTがとても遅いので、ちょっとだけ高速なPRINTルーチンをマシン語で作ってみました。

さらに高速化した ver 1.3 になりました。(2012.3.6)

自作プログラムでの使い方

まず、サンプルリストの50000行以降のマシン語書き込み部分を呼び出します。

そして、BASICプログラムから、

文字変数 = USR(文字列)

または、

文字変数 = USR(文字変数)

のように使ってください。

補足事項

サンプルリスト ver 1.3

ダウンロードはこちら

PC6001_HISPEED_PRINT.zip

10 REM ************** 11 REM コウソク PRINT テスト 12 REM TINYヤロウ 13 REM ************** 20 CLEAR 300,&HF000 30 GOSUB 50000 40 FOR S=3 TO 4 50 REM ************* 51 REM PRINTデ ヒョウジ 52 REM ************* 60 SCREEN S,2,2:CLS 70 T=TIME 80 FOR I=1 TO 16 90 LOCATE I,I:COLOR I 100 PRINT"PRINTデ ヒョウジ" 110 NEXT 120 T1(S-3)=TIME-T 130 REM ************* 131 REM マシンゴデ ヒョウジ 132 REM ************* 140 SCREEN S,2,2:CLS 150 T=TIME 160 FOR I=1 TO 16 170 LOCATE I,I:COLOR I 180 Z$=USR("マシンゴデ ヒョウジ") 190 NEXT 200 T2(S-3)=TIME-T 210 NEXT 220 SCREEN 1,1,1:CLS 230 PRINT"ジカン ケイソク ケッカ":PRINT 240 PRINT"SCREEN 3" 250 PRINT"PRINT:";T1(0);" マシンゴ:";T2(0) 260 PRINT 270 PRINT"SCREEN 4" 280 PRINT"PRINT:";T1(1);" マシンゴ:";T2(1) 290 END 50000 REM *************** 50001 REM コウソク PRINT ルーチン 50002 REM *************** 50010 FOR I=&HF000 TO &HF14B 50020 READ A$:POKE I,VAL("&H"+A$) 50030 NEXT 50040 POKE &HFAEB,0:POKE &HFAEC,&HF0 50050 RETURN 50100 DATA 3A,92,FD,FE,02,D8,3A,93,FD,28,08,3D,E6,03,21,34 50110 DATA F1,18,0A,3D,E6,0F,21,14,F1,DD,21,3C,F1,87,4F,06 50120 DATA 00,09,7E,32,BD,F0,23,7E,32,BE,F0,2A,A8,FD,2D,26 50130 DATA 00,29,29,29,29,4D,44,29,29,29,5D,54,29,19,09,3A 50140 DATA A9,FD,3D,4F,06,00,09,3A,92,FD,FE,03,28,01,09,3A 50150 DATA 91,FD,84,67,22,12,F1,3A,39,FF,2A,3B,FF,08,E5,CD 50160 DATA 9E,F0,2A,12,F1,3A,92,FD,FE,03,3A,A9,FD,28,07,FE 50170 DATA 14,23,30,0A,18,04,FE,28,30,04,23,3C,18,11,3A,A8 50180 DATA FD,FE,14,30,08,3C,32,A8,FD,01,69,01,09,3E,01,32 50190 DATA A9,FD,22,12,F1,E1,08,23,3D,20,C2,E1,E1,C9,7E,CD 50200 DATA A0,14,F3,DB,92,E6,FB,D3,92,2A,12,F1,3A,92,FD,FE 50210 DATA 03,28,3C,01,0F,0A,E5,EB,11,CF,F0,D9,01,00,00,E1 50220 DATA D9,7E,A1,12,AE,0F,0F,0F,0F,32,D2,F0,D9,DD,5E,00 50230 DATA DD,56,00,79,A2,77,79,A3,23,77,7C,C6,20,67,78,A3 50240 DATA 77,78,A2,2B,77,11,28,E0,19,D9,23,10,D4,18,1B,EB 50250 DATA 01,E0,0A,3A,BD,F0,A6,12,7A,91,57,3A,BE,F0,A6,12 50260 DATA 7B,C6,28,5F,7A,89,57,23,10,E9,DB,92,F6,04,D3,92 50270 DATA FB,C9,00,00,00,00,55,00,AA,00,FF,00,00,55,55,55 50280 DATA AA,55,FF,55,00,AA,55,AA,AA,AA,FF,AA,00,FF,55,FF 50290 DATA AA,FF,FF,FF,00,00,FF,00,00,FF,FF,FF,00,03,0C,0F 50300 DATA 30,33,3C,3F,C0,C3,CC,CF,F0,F3,FC,FF

アセンブラソース

;------------------------------
; 高速グラフィックPRINTルーチン
; (USR関数使用版 ver 1.3)
;
; by TINY野郎
;------------------------------
	ORG	0F000H
;BIOS
_GETCGADR	EQU	014A0H	; in:Aレジスタに文字コード out:DEレジスタにCGROMのアドレス
;システムワーク
_VRAMTOP	EQU	0FD91H	; 現在のページのVRAMアドレスの上位8ビット
_SCRMODE	EQU	0FD92H	; 現在のページのスクリーンモード-1
_COLOR1		EQU	0FD93H	; COLOR文で指定された第一パラメータ
_CURSORY	EQU	0FDA8H	; LOCATEで指定されたX+1
_CURSORX	EQU	0FDA9H	; LOCATEで指定されたY+1
;_USRFUNC	EQU	0FAEBH	; USR関数のジャンプ先(BASICで指定する)
_USRSTLEN	EQU	0FF39H	; USR関数の引数として与えられた文字列の文字数
_USRSTDAT	EQU	0FF3BH	; USR関数の引数として与えられた文字列のアドレス
;-------------------------------
; メイン処理
; (USR関数から呼ばれる)
;-------------------------------
START:
	LD	A,(_SCRMODE)	; A = スクリーンモード-1
	CP	2		; スクリーンモード-1 が2より大きいか小さいか
	RET	C		; スクリーンモード-1 が2より小さいなら(スクリーンモードが3より小さいなら)RETURN
				; USR関数の引数が数値ではなく文字列なので、そのままRETURNだと?TM Errorになるけどちょうどいいや
	LD	A,(_COLOR1)	; A = COLOR文で指定された第一パラメータ(文字色)
	JR	Z,COLMSKSET3	; さっき調べた スクリーンモード-1 が2なら(スクリーンモードが3なら)ジャンプ
COLMSKSET4:
	; SCREEN4用カラーマスク
	DEC	A		; COLORの値はいくらでも指定できるので
	AND	3		; 0~3 に変換して Aに入れる
	LD	HL,COLMSK4	; SCREEN4用のカラーマスクテーブル
	JR	COLMSKSET
COLMSKSET3:
	; SCREEN3用カラーマスク
	DEC	A		; COLORの値はいくらでも指定できるので
	AND	15		; 0~15 に変換して Aに入れる
	LD	HL,COLMSK3	; SCREEN3用のカラーマスクテーブル
	LD	IX,SC3BITTBL	; SCREEN3用伸長テーブル
COLMSKSET:
	; カラーマスクデータを取得
	ADD	A,A		; カラーマスクテーブルは2バイトなので
	LD	C,A		;
	LD	B,0		;
	ADD	HL,BC		; COLORに対応するカラーマスクテーブルのアドレスを計算
	LD	A,(HL)		; プレーン1のカラーマスク
	LD	(WCOLMSK1),A	; 保持しておくのも面倒なのでワークに書いておこう
	INC	HL		;
	LD	A,(HL)		; プレーン2のカラーマスク
	LD	(WCOLMSK2),A	; 保持しておくのも面倒なので以下略
CALCADDR:
	;-----------------------
	; VRAMアドレスの計算
	;-----------------------
	; 文字1行は、グラフィックVRAMだと
	; 横40バイト×縦10ドット=400バイトなので
	; LOCATEで指定されたYの値を400倍する
	LD	HL,(_CURSORY)	; LOCATEで指定されたY+1
	DEC	L		; -1する
	LD	H,0		; カーソルのY座標がHLレジスタに入る
	ADD	HL,HL		; x2
	ADD	HL,HL		; x4
	ADD	HL,HL		; x8
	ADD	HL,HL		; x16
	LD	C,L		;    16倍したところで
	LD	B,H		;    BCレジスタにコピー
	ADD	HL,HL		; x32
	ADD	HL,HL		; x64
	ADD	HL,HL		; x128
	LD	E,L		;    128倍したところで
	LD	D,H		;    DEレジスタにコピー
	ADD	HL,HL		; x256
	ADD	HL,DE		; Yの256倍 + Yの128倍 = Yの384倍
	ADD	HL,BC		; Yの384倍 + Yの 16倍 = Yの400倍
	; もっと短く400倍の計算ができたりするかもしれないけどあまり考えなかった…
	; LOCATEで指定されたXの値を足して
	; 最終的なVRAMアドレスを計算
	LD	A,(_CURSORX)	; LOCATEで指定されたX+1
	DEC	A		; -1する
	LD	C,A		;
	LD	B,0		; カーソルのX座標がBCレジスタに入る
	
	ADD	HL,BC		; X座標分のオフセットをVRAMアドレスに足す
	LD	A,(_SCRMODE)	; 突然のスクリーンモードチェック
	CP	3		; スクリーンモード-1が3(つまりスクリーンモードが4)かチェック
	JR	Z,PRTSTRX4	; スクリーンモードが4ならジャンプ
PRTSTRX3:
	; SCREEN3用の処理
	ADD	HL,BC		; SCREEN 3 は文字が横2バイト使うのでもう一度X座標分のオフセットを足す
PRTSTRX4:
	LD	A,(_VRAMTOP)	; そのページのVRAM先頭アドレスの上位8ビット
	ADD	A,H		; 計算済みのHLに加算して
	LD	H,A		;「最終的に文字を書くVRAMアドレス」を計算する
	LD	(WPUTVRAM),HL	; ワークに書いておく
PRTSTR:
	;-----------------------
	; 文字描画とカーソル移動
	;-----------------------
	; USR関数の引数を解析
	LD	A,(_USRSTLEN)	; 文字数
	LD	HL,(_USRSTDAT)	; 文字列データ
PRTSTRLP:
	EX	AF,AF'		; AFを裏レジスタに切り替え
	PUSH	HL		; 文字列データアドレス退避
	; ここまででセットされているもの
	; ・HLに文字データのアドレス
	; ・(WPUTVRAM)に文字を書くVRAMアドレス
	CALL	PUTASC		; 1文字描画
	LD	HL,(WPUTVRAM)	; 現VRAMアドレス
	; 一行右へ移る処理
	LD	A,(_SCRMODE)	; 突然のスクリーンモードチェック
	CP	3		; スクリーンモード-1が3(つまりスクリーンモードが4)かチェック
	LD	A,(_CURSORX)	; カーソルのX座標
	JR	Z,PRTSTRN4	; スクリーンモードが4ならジャンプ
PRTSTRN3:
	CP	20		; SCREEN 3 はX座標は19まで
	INC	HL		; VRAMを1バイト右に動かす(あとでもう1バイト動かす)
	JR	NC,PRTSTRNL	; 右端なら次の行へ
	JR	PRTSTRNX	; 右へ
PRTSTRN4:
	CP	40		; SCREEN 4 はX座標は39まで
	JR	NC,PRTSTRNL	; 右端なら次の行へ
PRTSTRNX:
	INC	HL		; VRAMを1バイト右に動かす(SCREEN 3 だと合計2バイト動かす)
	INC	A		; カーソルのX座標を+1
	JR	PRTSTRNM	; 次の文字へ
PRTSTRNL:
	; 一行下へ移る処理
	LD	A,(_CURSORY)	; カーソルのY座標
	CP	20		; Y座標は19まで
	JR	NC,PRTSTRNR	; 最下段なら次の行へ行かない
	INC	A		; Y座標を+1する
	LD	(_CURSORY),A	; LOCATEのY座標をアップデート
	LD	BC,361		; VRAMのアドレスを次の行の
	ADD	HL,BC		; 左端まで進める
PRTSTRNR:
	LD	A,1		; X座標を左端にする
PRTSTRNM:
	LD	(_CURSORX),A	; LOCATEのX座標をアップデート
	LD	(WPUTVRAM),HL
	POP	HL		; 文字列データアドレス復帰
	EX	AF,AF'		; AFを表レジスタに戻す
	INC	HL		; 次の文字へ
	DEC	A		; 文字数を-1して
	JR	NZ,PRTSTRLP	; 0になるまで繰り返す
	
	POP	HL		; USR関数からBASICへ戻る際の
	POP	HL		; チェック部分を飛ばす
	RET			; BASICへ戻る
	
;-------------------------------
; 1文字描画サブルーチン
;  in: HLに文字データのアドレス
;  in: (WPUTVRAM)に文字を書くVRAMアドレス
;-------------------------------
PUTASC:
	LD	A,(HL)		; 次の文字
	CALL	_GETCGADR	; DEにCGROMのデータアドレス
	
	;CGROMに切り替え
	DI			; 割り込み禁止
	IN	A,(092H)	; ポート92Hの
	AND	0FBH		; ビット2を0にすると
	OUT	(92H),A		; CGROMが見える
	LD	HL,(WPUTVRAM)	; HLに文字を描画するVRAM
	LD	A,(_SCRMODE)	; A = スクリーンモード-1
	CP	3		; スクリーンモード-1 が3なら(つまりスクリーンモードが4なら)
	JR	Z,PUTASC4	; SCREEN4用の描画ルーチンへジャンプ
PUTASC3:
	;-----------------------
	; SCREEN3用描画ルーチン
	;-----------------------
	LD	BC,0A0FH	; 縦10ライン, 表C = 下位4ビットマスク
	PUSH	HL		; VRAMアドレスを裏HLにコピー
	EX	DE,HL		; 表HL = CGROMアドレス
	LD	DE,PUTASC3IXE	; (余ってるので…)
	EXX			; (裏)
_WCOLMSK:
WCOLMSK1	EQU	_WCOLMSK+1
WCOLMSK2	EQU	_WCOLMSK+2
	LD	BC,0000H	; 自己書き換えされる(by 紅茶羊羹先生)
;----
	POP	HL		; 裏HL = VRAMアドレス
	EXX			; (表)
PUTASC3LP1:
	LD	A,(HL)		; CGROMからフォントデータを読む
	; フォントデータを横に伸長してDEレジスタに格納する
	; テーブルにして高速化(アドバイス by GORRY先生)
	AND	C		; データの下位4ビットを取得
	LD	(DE),A		; 自己書き換え LD E,(IX+[ここ])
	XOR	(HL)		; 下位4ビットを0にする(by 紅茶羊羹先生)
	RRCA			; データの
	RRCA			; 上位
	RRCA			; 4ビットを
	RRCA			; 抽出
	LD	(PUTASC3IXD),A	; 自己書き換え LD D,(IX+[ここ])
	EXX			; (裏) CGROMのアドレス退避
_PUTASC3IXE:
PUTASC3IXE	EQU	_PUTASC3IXE+2
	LD	E,(IX+0)	; 伸長テーブルからデータを拾う。+0の部分は自己書き換えされる
_PUTASC3IXD:
PUTASC3IXD	EQU	_PUTASC3IXD+2
	LD	D,(IX+0)	; 伸長テーブルからデータを拾う。+0の部分は自己書き換えされる
	; 例えば、元のデータが [0100 1101] の場合
	; DEレジスタの値は [0011 0000 1111 0011] になる
	
	; このままだと、すべてのドットが1(=白)になるので
	; 不必要なビットやプレーンをマスクすることで色をつける
	LD	A,C		; プレーン1用カラーマスク
	AND	D		; Dレジスタをマスク
	LD	(HL),A		; VRAMに書く
	LD	A,C		; プレーン1用カラーマスク
	AND	E		; Eレジスタもマスク
	INC	HL		; VRAMを1つ進めて
	LD	(HL),A		; 書く
	LD	A,H		; Hのみ加算することで
	ADD	A,20H		; プレーン2へ
	LD	H,A		;(by 紅茶羊羹先生)
	LD	A,B		; プレーン2用カラーマスク
	AND	E		; Eレジスタをマスク
	LD	(HL),A		; VRAMに書く
	LD	A,B		; プレーン2用カラーマスク
	AND	D		; Dレジスタもマスク
	DEC	HL		; VRAMを1つ戻して
	LD	(HL),A		; 書く
	LD	DE,0-2000H+40	; 
	ADD	HL,DE		; マイナス値を加算してプレーン1の次のラインへ
	EXX			; (表) CGROMのアドレス/カウンタ復帰
	INC	HL		; 次のデータへ
	DJNZ	PUTASC3LP1	; 縦10ライン終わるまでループ
	JR	PUTASC_RET	; 終了処理へ
	
PUTASC4:
	;-----------------------
	; SCREEN4用描画ルーチン
	;-----------------------
	EX	DE,HL
	LD	BC,0AE0H	; 縦10ライン, C = -20H(by 紅茶羊羹先生)
PUTASC4LP:
	LD	A,(WCOLMSK1)	; プレーン1用カラーマスク
	AND	(HL)		; CGROMからフォントデータを読む+データをマスクする(by 紅茶羊羹先生)
	LD	(DE),A		; VRAMに書く
	LD	A,D		; 
	SUB	C		; DE += 2000H
	LD	D,A		; プレーン2へ
	LD	A,(WCOLMSK2)	; プレーン2用カラーマスク
	AND	(HL)		; データをマスクする
	LD	(DE),A		; VRAMに書く
	LD	A,E		; 16ビット演算を
	ADD	A,40		; 使わずに
	LD	E,A		; DEに -2000H+40を
	LD	A,D		; 加算する
	ADC	A,C		; (by 紅茶羊羹先生)
	LD	D,A		; マイナス値を加算してプレーン1の次のラインへ
	INC	HL		; 次のデータへ
	DJNZ	PUTASC4LP	; 縦10ライン終わるまでループ
	
	;-----------------------
	; 終了処理
	;-----------------------
PUTASC_RET:
	IN	A,(092H)	; ポート92Hの
	OR	04H		; ビット2を1にすると
	OUT	(92H),A		; CGROMが隠れる
	EI			; 割り込み解除
	RET			; 1文字描画終わり
	
;-------------------------------
; ワークエリア
;-------------------------------
; 一時保存用
WPUTVRAM:	
	DEFW	0
; カラーマスクテーブル(プレーン1用マスクデータ, プレーン2用マスクデータ)
; CGROMから読んだデータを、VRAMに書く前にこの値とマスクすることで色をつける
COLMSK3:
	DEFB	000H,000H	; COLOR 1
	DEFB	055H,000H	; COLOR 2
	DEFB	0AAH,000H	; COLOR 3
	DEFB	0FFH,000H	; COLOR 4
	DEFB	000H,055H	; COLOR 5
	DEFB	055H,055H	; COLOR 6
	DEFB	0AAH,055H	; COLOR 7
	DEFB	0FFH,055H	; COLOR 8
	DEFB	000H,0AAH	; COLOR 9
	DEFB	055H,0AAH	; COLOR 10
	DEFB	0AAH,0AAH	; COLOR 11
	DEFB	0FFH,0AAH	; COLOR 12
	DEFB	000H,0FFH	; COLOR 13
	DEFB	055H,0FFH	; COLOR 14
	DEFB	0AAH,0FFH	; COLOR 15
	DEFB	0FFH,0FFH	; COLOR 16
COLMSK4:
	DEFB	000H,000H	; COLOR 1
	DEFB	0FFH,000H	; COLOR 2
	DEFB	000H,0FFH	; COLOR 3
	DEFB	0FFH,0FFH	; COLOR 4
; SCREEN3のビット伸長を計算せずにテーブルで保持
SC3BITTBL:
	DEFB	000H,003H,00CH,00FH
	DEFB	030H,033H,03CH,03FH
	DEFB	0C0H,0C3H,0CCH,0CFH
	DEFB	0F0H,0F3H,0FCH,0FFH
	
;-------------------------------
	END
; TINY野郎 2013.3

DEEP!P6! へ戻る