>>26 DQNはさっぱりわからんが、組み込みプログラマならそれ常識。
・まずARMとかRISKプロセッサでは、通常、除算回路はない。
・したがって、自分で除算ルーチンを用意する必要がある。たとえば、「引き算を繰り返す」でも
良い(決して恥ずかしいことではない。ケースによってはその方が良いこともある。可読性)
・通常は、10進の筆算と同じように桁どりをして、頭の方から引き算をして残りを桁取りして
いくことになる。ただし、10進の場合、「かけ算九九」でいくつまで引けるか暗算するが、
2進のときは「引けるか(1)、引けないか(0)」二者択一。
・用意するのは、割られる数(R0)、割る数(R1)、商を入れるとこ(R3。初期化時点では
ゼロにしておく)、余りを入れるとこR4。ただし、この事例ではトリッキーに(高速化を図る
べく)、R0を再利用していく。
・だいたいのイメージはこんな感じ。@R0をシフト(R0=R0+R0;)して、一番右をキャリービット
へ。AそれをR3に左から流し込む(R3=R3<<1+C;)。BR3のベルトコンベアwみて、
R11より大きくなったら、R11を引く。上記のとおり2回以上引けることはない。このことは直感的
に「前回(シフトする前だからだいたい半分)引けなかったのだから、2回以上引けるはずがない」
と理解。C以上を32ビット分=32回(各3ステップだから全部で96ステップ)繰り返せばよい
・なお、先頭数ビットがゼロビットのときはやる必要がなく、冒頭からスキップできる。RISKではそれを
調べるべく、CLZ(カウント・リーディング・ゼロ)という命令がある(おそらく、CLZ使わずにジャンプ
テーブルを使った点が馬鹿にされてる所以か?)。
・コードをみよう。
「96回」の前に必ず、
>:0000CE84 E0B00000 ads r0,r0,r0
があるはず。ここで先頭1ビットをキャリーに入れて1ビットシフト。
@1行目
>:0000CE7C E0B13083 adcs r3,r1,r3,lsl #0x1
足し算に見えるが、R1は符号反転してるはず。R3からとりあえずR1を引く
A2行目
>:0000CE80 30433001 subcc r3,r3,r1
「アセンブラについての知識はひととおりある」そうなので、補数表示はわかるよな?符号反転したR1
とR3を「足しこんで」(セマンティクには、R3からR1を引くのだがw)、キャリーがたつのは、R1補数
がオーバーフローして「正の数」になったときのみ。したがって、元R1<=R3のときのみCが立つ
だから、CC(キャリ無し)のとき、つまり、元R1>R3のときA発動で足しもどす。つまり@の引き算
を無かったことにする。
B3行目
>:0000CE84 E0B00000 adcs r0,r0,r0
ここではふたつのことをやってる。
・まず、R0をシフトして、先頭ビットをキャリーに保管する。つまり、次のループの準備。
・@で立ったキャリー(つまり商)をR0に流し込む。
これで、割られる数であるR0から1ビットずつ絞りとりながら、商を先頭ビットから流し込んでいる。
しかし、割られるレジスタと商のレジスタが同じである必要はないのだから、つまらんとこで可読性を
犠牲にして、1ステップ節約、1レジスタ節約する必然性は乏しい。総じてあまりよくないプログラム
と思われる。