DBNZ のような少数のコマンドしか持たない RISC プロセッサを考えます。レジスタ A の否定を B に書き込むコードと、B から A を減算して結果を C に入れる必要がある 2 番目の別のコードを記述しようとしています。
私はそれを行う方法がわかりません.Nasm Assemblerで可能になるかもしれませんが、これらは2つの異なることですが、開始方法がわかりません.
DBNZ のような少数のコマンドしか持たない RISC プロセッサを考えます。レジスタ A の否定を B に書き込むコードと、B から A を減算して結果を C に入れる必要がある 2 番目の別のコードを記述しようとしています。
私はそれを行う方法がわかりません.Nasm Assemblerで可能になるかもしれませんが、これらは2つの異なることですが、開始方法がわかりません.
記録として、実際の RISC アーキテクチャ (ARM や MIPS など) は DBNZ よりも機能が豊富です。あなたが想像するものは、通常、OISC または URISC として指定されます。
ところで、NASM は役に立ちません。実際の CPU のみを対象としています。あなたはアカデミックモデルです。しかし、高級言語でエミュレーターを作成するのは簡単なことではありません。おそらく JavaScript で 1 時間ほどで作成できます。
唯一のコマンドで想定している構文は次のとおりです。
DBNZ reg[, label]
意味は次のとおりです。
reg = reg - 1
if label is given and reg != 0 then goto label
label が省略された場合、暗黙的なジャンプ ターゲットは次の命令になります。コードを読みやすくするための、私にとっては構文糖の塊です。
セミコロンから行末までがコメントです。ラベルはコロンで終了します。私のコードでは、レジスタのサイズは有限であり、整数のラップアラウンドは例外なく静かに行われると想定しています。
否定のアルゴリズムは非常に簡単です。
b=0
while a > 0
a = a-1
b = b-1
アセンブルでは、条件ジャンプとデクリメントは同じものです。したがって、次のようになります。
;Zero out B
BZeroLoop:
DBNZ B, BZeroLoop ; Decrement until it's zero
;Main loop: subtract from A until it's zero, decrementing B on every iteration
NegLoop:
DBNZ B ; Decrement B with no jump
DBNZ A, NegLoop
さて引き算。A から B をその場で減算する (つまり、結果が A レジスタに残る) アルゴリズムは次のようになります。
while b != 0
b = b-1
a = a-1
実際、これは否定の場合と同じループですが、最初のゼロ設定はありません。否定は、引き算の場合と考えることができます。具体的には、ゼロからの引き算です。
しかし、結果を c に入れる必要があります。それほど発育不良でない言語では、割り当てるだけです。しかし、私たちには割り当てがありません。2 つの否定と一時レジスタを使用して割り当てを行うことができます。しかし、1 つの否定で間に合わせることができます。最初に ba をその場で計算し、次にそれを c に否定します。
while a != 0
a = a-1
b = b-1 ;this reduces b to the value of b-a
c = 0 ; also a loop
while b != 0
b = b-1
c = c-1
または、アセンブリで:
SubLoop: ; B = B-A
DBNZ B
DBNZ A, SubLoop
CZeroLoop: ; C = 0
DBNZ C, CZeroLoop
NegLoop: ; C = C-B
DBNZ C
DBNZ B, NegLoop