まずは最速コードの一例を織り交ぜつつ考察。


■乗算について■
要約:
 掛けられる数を左シフトしてキャリーフラグが立てば、掛ける数答えに加算。
 ループを抜けない場合は、答えを左シフトしてループの先頭に戻る。

 この例では、初期化部分の所要クロックは31
 ループ内の最大所要クロックは1115


16bit同士の乗算の一例
(Yレジスタを使わず、ブランチがページクロッシングしない場合)
コードクロック数
lda #$00
sta <temp0
sta <temp1
sta <temp2
sta <temp3
lda <kakerareru-kazu_low
sta <kakerare-temp_low
lda <kakerareru-kazu_high
sta <kakerare-temp_high
ldx #16
bne .Loop_First
2
3
3
3
3
3
3
3
3
2
3
.Loop:;>>>>>>>>>>>>>>>>>
asl <temp0
rol <temp1
rol <temp2
rol <temp3
.Loop_First:
asl <kakerare-temp_low
rol <kakerare-temp_high
bcc .IsNotCF
lda <kakeru-kazu_low
clc
adc <temp0
sta <temp0
lda <kakeru-kazu_high
adc <temp1
sta <temp1
bcc .DoNotIncrement3rd4th
inc <temp2
bne .DoNotIncrement4th
inc <temp3
.DoNotIncrement4th:
.DoNotIncrement3rd4th:
.IsNotCF:;--------------
dex
bne .Loop
;<<<<<<<<<<<<<<<<<<<<<<<

5
5
5
5

5
5
2 or 3
3
2
3
3
3
3
3
2 or 3
5
2 or 3
5



2
2 or 3


■除算について■
要約:
 割られる数を左シフトして、キャリーフラグを左ローテートシフトで
 比較用メモリに入れる。そして比較用メモリの値と割る数を比較。
 比較用メモリ割る数より小さければ、答えに%0を左ローテートシフトで押し込む。
 比較用メモリ割る数と同じか大きければ、比較用メモリから割る数を引いてから、
 答えに%1を左ローテートシフトで押し込む。
 ループを抜けない場合は、そのままループの先頭に戻る。

 比較用メモリには最終的に剰余が入る。
 0除算をすると、全ビットが立っている値が答えとして出される。

 この例では、初期化部分の所要クロックは28
 ループ内の最大所要クロックは943


16bit同士の除算の一例
(ブランチがページクロッシングしない場合)
コードクロック数
lda #$00
sta <hikaku_low
sta <hikaku_high
sta <temp0
sta <temp1
lda <warareru-kazu_low
sta <warare-temp_low
lda <warareru-kazu_high
sta <warare-temp_high
ldx #16
2
3
3
3
3
3
3
3
3
2
.Loop:;>>>>>>>>>>>>>>>>>
asl <warare-temp_low
rol <warare-temp_high
rol <hikaku_low
rol <hikaku_high
lda <hikaku_low
sec
sbc <waru-kazu_low
tay
lda <hikaku_high
sbc <waru-kazu_high
bcc .IsNotCF
sta <hikaku_high
sty <hikaku_low
.IsNotCF:;--------------
rol <temp0
rol <temp1
dex
bne .Loop
;<<<<<<<<<<<<<<<<<<<<<<<

5
5
5
5
3
2
3
2
3
3
2 or 3
3
3

5
5
2
2 or 3


ファミコンでは掛け算より割り算のほうが早いという事実!

掛け算ではレジスタをひとつ使っていないという不公平はあるものの、
それを使ったとしても、今回の場合13クロックしか削れない。
その上で比較すると、乗算が1133クロックに対して、除算が971クロック。

しかし、どちらにしてもやっぱり遅い。




inserted by FC2 system