SSブログ
English Version

GAME言語で 3DHAT の高速描画 [Z80]

 Z80 アセンブラで作成した 16 ビットの固定小数の乗算演算処理を使って asciiart を高速に描画できたことを「GAME言語での ASCIIART の高速化」の記事で書きました。

 GAME言語コンパイラはGAME言語自身で記述されているので固定小数点のような新たな演算子の追加も割合楽にできます。
 上記の記事では固定小数点の乗算のみを追加しましたが、今回はコンパイラに下記の演算子を追加して3DHATを高速に描いてみたいと思います。
 尚、3DHATのプログラムは「Pic24MC68Kマイコン(その9)ehBASICの移植」の記事にアップしたものを今回の拡張GAMEコンパイラ(以降、拡張コンパイラと記す)用に移植します。

No演算子記号種別実装方法演算内容
1x2項演算子アセンブラ固定小数点の乗算
2¥s単項演算子アセンブラSIN(引数:固定小数点(90°=1))
3¥c単項演算子アセンブラCOS(引数: 同上 )
4¥r単項演算子アセンブラ平方根(引数:固定小数点)
5¥f単項演算子コンパイラ整数から固定小数点への変換
6¥i単項演算子コンパイラ固定小数点から整数への変換
7&2項演算子コンパイラAND 演算
8|2項演算子コンパイラOR 演算
9<<2項演算子コンパイラ左シフト
10>>2項演算子コンパイラ算術右シフト
    ※:コンパイラ内に Z80 のマシン語への変換ロジックを実装


 No.1 の固定小数点の乗算記号を '*' としなかったのは従来の整数演算も並行して使用したかったからです。BASCI 言語等でも整数と浮動小数点を同時に使えますが、こうしないと既存のプログラムの移植の際等に非常に不便であることが今回身に染みて判りました。
 No.7 までは今回移植する3DHATを動かす上で必要なものですが No.8 以降はついでに付加したものです。

 No.2 と No.3 の三角関数は速度優先で 0 .. pai/2 区間の SIN の値からなる 256 バイトのテーブルから値を引くようにしました。今回の固定小数点では 0x0100 が1の値なのですが、256 は1バイトに収まらないので テーブル先頭の唯一の 0 は参照しないようにして 角度が pai/2 の整数倍の時は -1,0,1 のいずれかを判断して返す様にすることでテーブル内のゼロを 256 と見なすようにしました。

 No.4 の平方根は Twitter で見かけた下記の処理手法を Z80 アセンブラで記述しました。



 アセンブラのソースも貼っておきます。乗算処理のメインループのステップ数はこれ以上短くならないのではないかと思います。

今回作成した固定小数点演算処理(乗算、平方根、SIN/COS)
;++++++++++++++++++++++++++++++++++ ; calcurate Fixed point[8.8] sin ; Ver 0.01 2023/01/06 skyriver ; Ver 0.02 2023/01/12 skyriver ; Ver 0.02b 2023/01/15 skyriver ; Ver 0.03 2023/05/05 skyriver ;++++++++++++++++++++++++++++++++++ 0000' ASEG ORG 8400H 8400 C3 8443 JP SIN 8403 C3 8442 JP COS 8406 C3 8470 JP SQRT ; HL,DE <- value ; DE -> result:HL*DE 8409 01 0F01 Mul: LD BC,15*256 + 1 840C CB 7C BIT 7,H 840E 28 07 JR Z,Mul10 8410 0C INC C 8411 AF XOR A 8412 95 SUB L 8413 6F LD L,A 8414 9F SBC A,A 8415 94 SUB H 8416 67 LD H,A 8417 EB Mul10: EX DE,HL 8418 29 ADD HL,HL 8419 30 07 JR NC,Mul20 841B 0C INC C 841C AF XOR A 841D 95 SUB L 841E 6F LD L,A 841F 9F SBC A,A 8420 94 SUB H 8421 67 LD H,A 8422 CB 19 Mul20: RR C ; Cy 0:negative 8424 08 EX AF,AF' 8425 4C LD C,H 8426 7D LD A,L 8427 21 0000 LD HL,0 842A MulLoop: 842A 29 ADD HL,HL 842B 17 RLA 842C CB 11 RL C 842E 30 03 JR NC,MulL10 8430 19 ADD HL,DE 8431 CE 00 ADC A,0 8433 10 F5 MulL10: DJNZ MulLoop 8435 57 LD D,A 8436 5C LD E,H 8437 08 EX AF,AF' 8438 D8 RET C 8439 AF XOR A 843A 93 SUB E 843B 5F LD E,A 843C 9F SBC A,A 843D 92 SUB D 843E 57 LD D,A 843F C9 RET ; cos ; DE <- 256:90deg ; DE -> SIN value 8440 14 COS: INC D ; go through to SIN ; sin ; DE <- 256:90deg ; DE -> SIN value 8441 7B SIN: LD A,E 8442 B7 OR A 8443 C2 8452 JP NZ,SIN10 8446 CB 1A RR D 8448 17 RLA ; A:0 8449 CB 1A RR D 844B D2 8450 JP NC,SIN02 844E ED 44 NEG 8450 57 SIN02: LD D,A ; orgD:D = 00:00, 01:01, 02:00, 03:FF 8451 C9 RET 8452 CB 42 SIN10: BIT 0,D 8454 28 02 JR Z,SIN20 8456 ED 44 NEG 8458 6F SIN20: LD L,A 8459 26 85 LD H,HIGH SINTAB 845B 5E LD E,(HL) 845C 26 00 LD H,0 845E 1C INC E 845F 1D DEC E 8460 20 01 JR NZ,SIN30 8462 24 INC H 8463 CB 4A SIN30: BIT 1,D 8465 54 LD D,H 8466 C8 RET Z 8467 AF XOR A 8468 93 SUB E 8469 5F LD E,A 846A 9F SBC A,A 846B 92 SUB D 846C 57 LD D,A 846D C9 RET ; sqrt ; DE <- data:fixed8.8 ; DE -> result:fixed8.8 846E 21 0000 SQRT: LD HL,0 ; ans = 0 8471 01 8000 LD BC,08000H ; for( bit=4000H; bit; bit >>= 2 ) { 8474 CB 38 SQRFOR: SRL B 8476 CB 19 RR C 8478 CB 3C SRL H ; ans >>= 1 847A CB 1D RR L 847C E5 PUSH HL 847D 29 ADD HL,HL ; if( n >= ( tmp = (ans << 1) | bit ) ) { 847E 09 ADD HL,BC 847F D5 PUSH DE 8480 EB EX DE,HL ;; OR A ; already Cy:0 8481 ED 52 SBC HL,DE ; HL:n, DE:tmp 8483 D1 POP DE ; DE:n 8484 38 04 JR C,SQR10 8486 EB EX DE,HL ; n -= tmp 8487 E1 POP HL 8488 09 ADD HL,BC ; ans |= bit; 8489 FE DB 0FEH ; } skip POP 848A E1 SQR10: POP HL 848B CB 38 SRL B 848D CB 19 RR C 848F D2 8474 JP NC,SQRFOR ; } 8492 29 ADD HL,HL ; convert fixed point 8.8 8493 29 ADD HL,HL 8494 29 ADD HL,HL 8495 29 ADD HL,HL 8496 EB EX DE,HL 8497 C9 RET ORG ( $ + 255 ) AND 0FF00H 8500 00 02 03 05 SINTAB: DB 0, 2, 3, 5, 6, 8, 9, 11 8504 06 08 09 0B 8508 0D 0E 10 11 DB 13, 14, 16, 17, 19, 20, 22, 24 850C 13 14 16 18 8510 19 1B 1C 1E DB 25, 27, 28, 30, 31, 33, 34, 36 8514 1F 21 22 24 8518 26 27 29 2A DB 38, 39, 41, 42, 44, 45, 47, 48 851C 2C 2D 2F 30 8520 32 33 35 37 DB 50, 51, 53, 55, 56, 58, 59, 61 8524 38 3A 3B 3D 8528 3E 40 41 43 DB 62, 64, 65, 67, 68, 70, 71, 73 852C 44 46 47 49 8530 4A 4C 4D 4F DB 74, 76, 77, 79, 80, 82, 83, 85 8534 50 52 53 55 8538 56 58 59 5B DB 86, 88, 89, 91, 92, 94, 95, 97 853C 5C 5E 5F 61 8540 62 63 65 66 DB 98, 99, 101,102, 104, 105, 107, 108 8544 68 69 6B 6C 8548 6D 6F 70 72 DB 109, 111, 112, 114, 115, 117, 118, 119 854C 73 75 76 77 8550 79 7A 7B 7D DB 121, 122, 123, 125, 126, 128, 129, 130 8554 7E 80 81 82 8558 84 85 86 88 DB 132, 133, 134, 136, 137, 138, 140, 141 855C 89 8A 8C 8D 8560 8E 90 91 92 DB 142, 144, 145, 146, 147, 149, 150, 151 8564 93 95 96 97 8568 98 9A 9B 9C DB 152, 154, 155, 156, 157, 159, 160, 161 856C 9D 9F A0 A1 8570 A2 A4 A5 A6 DB 162, 164, 165, 166, 167, 168, 170, 171 8574 A7 A8 AA AB 8578 AC AD AE AF DB 172, 173, 174, 175, 177, 178, 179, 180 857C B1 B2 B3 B4 8580 B5 B6 B7 B8 DB 181, 182, 183, 184, 185, 186, 188, 189 8584 B9 BA BC BD 8588 BE BF C0 C1 DB 190, 191, 192, 193, 194, 195, 196, 197 858C C2 C3 C4 C5 8590 C6 C7 C8 C9 DB 198, 199, 200, 201, 202, 203, 204, 205 8594 CA CB CC CD 8598 CE CF CF D0 DB 206, 207, 207, 208, 209, 210, 211, 212 859C D1 D2 D3 D4 85A0 D5 D6 D7 D7 DB 213, 214, 215, 215, 216, 217, 218, 219 85A4 D8 D9 DA DB 85A8 DC DC DD DE DB 220, 220, 221, 222, 223, 224, 224, 225 85AC DF E0 E0 E1 85B0 E2 E3 E3 E4 DB 226, 227, 227, 228, 229, 229, 230, 231 85B4 E5 E5 E6 E7 85B8 E7 E8 E9 E9 DB 231, 232, 233, 233, 234, 235, 235, 236 85BC EA EB EB EC 85C0 ED ED EE EE DB 237, 237, 238, 238, 239, 239, 240, 241 85C4 EF EF F0 F1 85C8 F1 F2 F2 F3 DB 241, 242, 242, 243, 243, 244, 244, 245 85CC F3 F4 F4 F5 85D0 F5 F5 F6 F6 DB 245, 245, 246, 246, 247, 247, 248, 248 85D4 F7 F7 F8 F8 85D8 F8 F9 F9 F9 DB 248, 249, 249, 249, 250, 250, 250, 251 85DC FA FA FA FB 85E0 FB FB FC FC DB 251, 251, 252, 252, 252, 252, 253, 253 85E4 FC FC FD FD 85E8 FD FD FE FE DB 253, 253, 254, 254, 254, 254, 254, 255 85EC FE FE FE FF ; DB 255, 255, 255, 255, 255, 255, 256, 256 ; DB 256, 256, 256, 256, 256, 256, 256, 256 85F0 FF FF FF FF DB 255, 255, 255, 255, 255, 255, 0, 0 85F4 FF FF 00 00 85F8 00 00 00 00 DB 0, 0, 0, 0, 0, 0, 0, 0 85FC 00 00 00 00 END Macros: Symbols: 8442 COS 8409 MUL 8418 MUL10 8424 MUL20 8435 MULL10 842C MULLOOP 8443 SIN 8452 SIN02 8454 SIN10 845A SIN20 8465 SIN30 8500 SINTAB 848C SQR10 8476 SQRFOR 8470 SQRT No Fatal error(s)

[history]
・Ver0.02b 2023/01/15 improve srqt a little
・Ver0.03 2023/05/05 improve Mul


 3DHATを描画するGAME言語のソースは下記になります。元々が記号言語なので読み辛いとは思いますが、全てをアセンブラで記述するよりは効率的に記述できるのではないかと思います。

3DHat描画ソース(拡張GAME言語)
10' ** 3D graphic with teraterm 20'GOSUB 1000:REM TEKCLS 21 !=1000 30'X1=2:GOSUB 1100:REM TEKCOLOR(2) 31 G=2 !=1100 40'DIM D(1,255):FOR L=0 TO 255:D(0,L)=-1:D(1,L)=-1:NEXT 41 D=&+1 L=0,255 D(L)=-1 D(L+256)=-1 @=L+1 60'FOR Y=-180 TO 180 STEP 4:FOR X=-180 TO 180 STEP 4 61'-10,10 62 YF=$F600,$0A00 XF=$F600,$0A00 80'R=PI/180*SQR(X*X+Y*Y):Z=100*COS(R)-30*COS(3*R) 81 RF=¥r(XFxXF+(YFxYF))x$0033 83 T=$1E00x¥c($0300xRF) 84 Z=¥i($6400x¥c(RF)-T) 100'V=INT(116+X/2+(16-Y/2)/2):W=INT((130-Y/2-Z)/2) 101' TF=YFx$0400 V=\i($0800xXF-TF)+124 102 TF=YF<<2 V=\i(XF<<3-TF)+124 103 W=65-(Z>>1)-¥iTF 104 T=V+256 120'IF (V<0)+(V>255) THEN GOTO 160 121 ;=(V<0)+(V>255) #=160 130'IF D(0,V)=-1 THEN GOTO 500 131 ;=D(V)=-1#=500 140'IF W<=D(0,V) THEN GOTO 700 141 ;=W<=D(V) #=700 150'IF W>=D(1,V) THEN GOTO 800 151 ;=W>=D(T) #=800 160'NEXT X:NEXT Y:END 161 @=XF+$0040 @=YF+$0040 #=-1 500'IF V=0 THEN GOTO 600 501 ;=V=0 #=600 510'IF D(0,V-1)=-1 THEN GOTO 600 511 ;=D(V-1)=-1 #=600 520'IF D(0,V+1)=-1 THEN GOTO 600 521 ;=D(V+1)=-1 #=600 530'D(0,V)=INT((D(0,V-1)+D(0,V+1))/2) 531 D(V)=(D(V-1)+D(V+1))>>1 540'D(1,V)=INT((D(1,V-1)+D(1,V+1))/2) 541 D(T)=(D(T-1)+D(T+1))>>1 550'GOSUB 900:GOTO 160 551 !=900 #=160 600'D(0,V)=W:D(1,V)=W:GOSUB 900:GOTO 160 601 D(V)=W D(T)=W !=900 #=160 700'GOSUB 900:D(0,V)=W:IF D(1,V)=-1 THEN D(1,V)=W 701 !=900 D(V)=W ;=D(T)=-1 D(T)=W 710'GOTO 160 711 #=160 800'GOSUB 900:D(1,V)=W:IF D(0,V)=-1 THEN D(0,V)=W 801 !=900 D(T)=W ;=D(V)=-1 D(V)=W 810'GOTO 160 811 #=160 900'X1=V*3.5+30:Y1=600-W*3.5:GOSUB 2100:RETURN 901 G=V<<2-(V>>1)+30 902 H=W>>1-(W<<2)+600 903 !=2100 ] 999' TEKCLS 1000'PRINT CHR$($1B);CHR$($0C);CHR$($0D);CHR$($0A);:RETURN 1001 $=$1B $=$0C $=$0D $=$0A ] 1100' TEKCOLOR(X) 1110'PRINT CHR$($1B);CHR$($5B);CHR$($33);CHR$($30+X1);CHR$($6D);:RETURN 1111 $=$1B $=$5B $=$33 $=G+$30 $=$6D ] 2100'REM TEKDOT(X1,Y1) 2110'PRINT CHR$($1D); 2111 $=$1D 2120'PRINT CHR$($20+(Y1/32 AND $1F));CHR$($60+(Y1 AND $1F)); 2121 $=H>>5&$1F+$20 $=H&$1F+$60 2140'PRINT CHR$($20+(X1/32 AND $1F));CHR$($40+(X1 AND $1F)); 2141 $=G>>5&$1F+$20 $=G&$1F+$40 2160'PRINT CHR$($20+(Y1/32 AND $1F));CHR$($60+(Y1 AND $1F)); 2161 $=H>>5&$1F+$20 $=H&$1F+$60 2180'PRINT CHR$($20+(X1/32 AND $1F));CHR$($40+(X1 AND $1F));:RETURN 2181 $=G>>5&$1F+$20 $=G&$1F+$40 ]


 GAMEコンパイラでコンパイル後に実行した画面のキャプチャーが下図になります。冒頭で紹介した「ehBASICの移植の記事」の記事で書いたように TeraTerm のテクトロ端末機能(TEKウィンド)を使ってグラフィック描画しています。描画に掛かった時間は開発中の Z80PicCompact(Z80 12MHz)で 8s 程度でした。
★変更 2023/01/09 16s から 14s に変更。STEP幅が大きかったので元版に合わせ 14s から 9s に変更
★変更 2023/01/11 乗算の一部をシフトに変更して 9s から 8s に変更


 16 ビットの固定小数点では精度不足で若干ガタガタしている部分がありますが「ehBASICの移植の記事」で書いたように MC68K 16MHz での描画時間が 2 分 34 秒なので今回作成したものはメチャ速いことが判ります。

 もう少し精度を上げたいところですが、現状でも処理の一部で MSB まで桁あふれした値を MSB まで対応している 平方根処理で固定小数点の範囲内に戻しているので 16 ビットでのほぼ限界に近い処理になっているのではないかと思います。

3DHAT描画画面


 最後に今回機能追加した拡張GAMEGAMEコンパイラ(GAME80用)も貼っておきます。



★追記 2023/01/09 {
 Twitter に投稿した動画付きメッセージを貼っておきます。動画にすると描画のドットの色が薄くて全画面表示にしないと殆ど見えないですね ^^;;

}


★追記 2023/01/10 {
 MSX に移植して MSXPen で実行した際に投稿した動画付きの Twitter コメントも貼っておきます。
 グラフィックはオーバーヘッドが少なそうな Graphics7(256x192 in 256 colors)を使っています。

}

★追記 2023/04/20
 MSX 用 3DHat の実行ファイルは下記からダウンロードできます。


★追記 2024/01/29
 MZ-2200 のエミュレータである EmyuZ-2200 を弄る機会があり関連資料を見ていたところ、MZ 系の CM ではお馴染みの3Dハットを表示中の画面の写真を見つけました。
 本家の MZ のエミュで固定小数点+拡張 GAME コンパイラによる高速3Dハット描画を試したところ、CPU クロック 6MHz の設定で描画時間は約 20 秒でした。

EmyuZ-2200 での3Dハット描画画面

★追記 2024/01/30
 MZ-2200 用の 3DHat 描画プログラム( MZT ファイル)は下記URLからダウンロードできます。
[History]
2023/02/03 Ver 2 若干高速化(描画時間は6MHzで約12秒)



[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー