サンプルコード
注意:ここのサンプルコードは特記がない限りDK2でしか使えません。DK1/3で使いたい場合はメモリアドレスを適宜変更すれば使えるかもしれません。
線形合同法による擬似乱数生成ルーチン
線形合同法 Xn+1 = ( A×Xn+B ) mod M ( M > A, M > B, A > 0, B ≧ 0 ) |
;乱数の種を取得する。これは最初にこのルーチンを呼び出すときだけ使用する。 LDA $D5 ;下位16bitを取得 STA $1F00 ; LDA $D7 ;上位16bitを取得 STA $1F02 ; BRA Calc ; Calc: ;下位16bit*0xC1685309 ;ただし、この乱数計算において、この掛け算の上位16bitは不要。 ;また、第3項以降の計算をする場合はここからはじめる。 LDA $1F00 ;\ STA $1F04 ;| LDA #$5309 ;|下位16bit*0x5309 STA $1F06 ;| JSR Multi ;/ LDA $1F04 ;\ STA $1F08 ;|結果をコピー LDA $1F06 ;|$1F08-$1F0Bに先ほどの計算結果が入る STA $1F0A ;/ LDA $1F00 ;\ STA $1F04 ;| LDA #$C168 ;|下位16bit*0xC168 STA $1F06 ;| JSR Multi ;/ CLC ; LDA $1F0A ;\中位16bit(足し算) ADC $1F04 ;|$1F04-$1F07に STA $1F0A ;/下位16bit*0xC1685309の下位32bitだけが入る ;上位16bit*0xC1685309 ;ただし、この乱数計算において、この掛け算の上位32bitは不要。 LDA $1F02 ;\ STA $1F04 ;| LDA #$5309 ;|下位16bit*0x5309 STA $1F06 ;|この計算の下位16bitだけが必要。 JSR Multi ;/ ;上で得られたものを足して、32bit*32bitの答えを得る。 ;ただし、Bは32bitなので下位32bitだけを計算したので構わない。 CLC ; LDA $1F0A ;下位16bit*0xC1685309の上位16bit ADC $1F06 ;上位16bit*0xC1685309の下位16bit STA $1F0A ;これで$1F08-$1F0Bに32bit*32bitの下位32bitが入る ;Bを足し、0x100000000で割る。ただし、実際には割り算をせずに ;足し算の下位32bitを取得しただけで答えが得られる。 CLC ; LDA #$BD92 ;\ ADC $1F08 ;|下位16bit同士を足す STA $1F00 ;/ LDA #$E580 ;\ ADC $1F0A ;|上位16bit同士と繰り上がり(キャリーフラグ)を足す STA $1F02 ;/これで$1F00-$1F03に次の乱数値が入る CLC ;別の処理でバグを発生しないようきちんとキャリークリア RTS |
掛け算の計算方法 A.16bit*32bit (結果は最大48bit) 例)0x1234が被乗数のとき 0x | |1234 0x |C168|5309 0x |05E7|7FD4<-0x1234*0x00005309 0x0DC0|9920| <-0x1234*0xC1680000 0x0DC0|9F07|7FD4 | | └-----0x7FD4をそのまま下ろす | └----------0x05E7+0x9920 └---------------0x0DC0+繰り上がり B.32bit*32bit (結果は最大64bit) 例)0x12345678が被乗数のとき 0x | |1234|5678 0x | |C168|5309 0x |4153|B4CB|F238<-0x5678*0xC1685309 0x0DC0|9F07|7FD4| <-0x1234*0xC1685309 0x0DC0|E05B|349F|F238 └--------実際に必要なのはここまで いずれも掛け算の筆算と同じ方法で計算する。 |
SDK3の乱数計算ルーチン
LDA $02 ; STA $1C ; ASL A ;左シフト(2倍) LDA $04 ; ROL A ;左シフト(2倍) STA $1A ; LDA $03 ; EOR $1A ; STA $02 ; LDA $1C ; STA $04 ; LDA $02 ; RTS ; |
線形帰還シフトレジスタによる乱数生成ルーチン
LDA $1F00
; LSR A ; LSR A ; STA $1F02 ; EOR $1F00 ;これでbit0とbit2をXORしたことになる STA $1F04 ; LDA $1F02 ; LSR A ; STA $1F02 ; EOR $1F04 ;これでbit0とbit2とbit3をXORしたことになる STA $1F04 ; LDA $1F02 ; LSR A ; LSR A ; EOR $1F04 ;これでbit0とbit2とbit3とbit5をXORしたことになる AND $0001 ;bit0だけを残す。これがXOR演算の答え。 CLC ; ROR A ;bit0がキャリーフラグに移動 ROR A ;キャリーフラグがbit15に移動 STA $1F04 ; LDA $1F00 ; LSR A ; ORA $1F04 ;bit15を結合 STA $1F00 ; RTS ; |
表引きによる乱数生成
PHB
;DBレジスタを退避 LDA $D7 ;ゲーム内時間の上位16bitを取得 AND #$003F ;ROMのバンクを取得する CLC ; ADC #$00C0 ;0xC0を足す。これで実際に参照すべきバンクが得られる。 PHA ;DBレジスタには直接値を渡せないのでスタック経由で渡す PLB ;DB=0 PLB ;DB=Bank LDA ($D5) ;ゲーム内時間下位16bitをアドレス、DBレジスタをバンクとして16bit読込 PLB ;DBレジスタを元に戻す RTS ; |
ワールドマップごとにBGMを変える
PHX LDX $06B1 LDA songtable,x PLX AND #$00FF CMP $1C BEQ $821B BRA $820A |
B4:81F2 DA PHX B4:81F3 AE B1 06 LDX $06B1 ;ワールド番号の取得 B4:81F6 BF 00 FF B5 LDA $B5FF00,x ;曲テーブルからBGM番号を取得 B4:81FA FA PLX B4:81FB 29 FF 00 AND #$00FF ;上位バイトをクリア B4:81FE C5 1C CMP $1C B4:8200 F0 19 BEQ $821B B4:8202 80 06 BRA $820A B5:FF00 ワールドマップ用BGMテーブル 要素数は15。ワールド番号の若い順に使用したいBGMのBGM番号(1バイト)を記述する。 原作と同じ設定とする場合は以下のようになる 01 01 01 01 01 01 01 01 01 01 1C 1C 1C 1C 1C 全 W1 W2 W3 W4 W5 W6 W7 W2 W4 L2 L3 L4 L5 L6 |