これらの単純な乗算と除算をアセンブリで解決しようとしています。
5*4 + 35/7
私はこれをやった
mov al,5
mov bl,4
mul bl
mov ax,35
mov bl,7
div bl
AXレジスタの乗算の以前の値は、除算の新しい結果で上書きされます。これを修正するにはどうすればよいですか?
これらの単純な乗算と除算をアセンブリで解決しようとしています。
5*4 + 35/7
私はこれをやった
mov al,5
mov bl,4
mul bl
mov ax,35
mov bl,7
div bl
AXレジスタの乗算の以前の値は、除算の新しい結果で上書きされます。これを修正するにはどうすればよいですか?
AX レジスタの乗算の以前の値は、除算の新しい結果で上書きされます。これを修正するにはどうすればよいですか?
十分に単純です。乗算の結果を追加のレジスタ (私は を使用DX
) に入れ、式の次の項を計算し、最後に両方の結果を加算します。商はレジスタにのみあることに注意することが重要なAL
ので、加算を行う前にレジスタをクリアする必要がありますAH
! ( 「35/7」の例で使用されている数字は、余りが 0 になりAH
ますが、プログラムを書くように求められたときに、これを当てにしてはいけません! )
mov al,5
mov bl,4
mul bl ; -> Result is in AX
mov dx, ax
mov ax,35
mov bl,7
div bl ; -> Result is in AL
mov ah, 0
add ax, dx ; -> Final result is in AX
Emu8086 は 8086 命令に基づいているため、MULおよびDIVの単一オペランド バージョンしかありません。IMULはMULの署名付きバージョンであり、 IDIVはDIVの署名付きバージョンです。符号なしの算術演算を行うつもりであると仮定すると、コードは次のようになります。
mov al,5
mov bl,4
mul bl
mov cx, ax ; Save AX to CX
mov ax,35
mov bl,7
div bl
xor ah, ah ; Result(quotient) of DIV in AL, ensure AH is zero
add ax, cx ; AX=AX+CX
MULおよびDIVの 8086 固有の命令でAXが破壊されるのを防ぐ方法はありません。値をスクラッチ領域に移動する必要があります。上記のコードでは、レジスタCXを使用します。MUL命令の結果をCXに保存するので、それをDIV命令の結果に追加するだけです(商はALにあります)。AHに格納されている剰余をゼロにして、商をALに残します。AXには、 CXに追加する商 (16 ビット値として) が含まれます。、方程式の最終結果はAXに格納されます。
4 で乗算する単純化は、値を 2 ビット左にシフトすることです。このコード:
mov al,5
mov bl,4
mul bl
mov cx, ax ; Save AX to CX
次のように削減できます。
mov cx, 5
shl cx, 2 ; Multiply CX by 4
8086 プロセッサは、 CLレジスタを使用する場合を除き、1 ビットを超えるSHLシフトをサポートしていません。EMU8086 のアセンブラは、命令を 1 つまたは複数の命令に自動的に変換します。この場合、次のように翻訳されました。SHL reg, imm
SHL, reg, 1
SHL CX, 2
shl cx, 1 ; Multiply CX by 2
shl cx, 1 ; Multiply CX by 2 again
ほとんどの 8086 アセンブラーは、この変換を行いません。または、シフトするビット数をCLレジスタで指定することもできます。これ (または同等のもの) は、ほとんどの 8086 アセンブラで機能します。
mov cl, 2 ; Number of bits to shift left by in CL
mov dx, 5
shl dx, cl ; Shift DX to the left by CL(2) is equivalent to multiply by 4
mov ax,35
mov bl,7
div bl
xor ah, ah ; Result(quotient) of DIV in AL, ensure AH is zero
add ax, dx ; AX=AX+DX
5 * 4 を掛けてから、値をスタックにプッシュする必要があります。次に、2 番目の計算である除算を行います。次に、スタックから最初の値をポップし、それらの値を加算します。
主な質問に答えるには: を使用imul reg, reg, imm
して、乗算を別のレジスタに行うことができます。またはmov ecx, eax
、必要のないレジスタに結果を保存することもできますdiv
。
データがどこから来なければならないかを言わなかったので、当然のことは、アセンブル時に計算を実行することです。
mov eax, 5*4 + 35/7
それでも実行時に計算したい場合は、即時定数、レジスター、またはメモリー内の値から始める必要があります。ここでそれらを組み合わせて説明すると便利です (div
直接オペランド形式がないため)。
通常は、デフォルトのオペランド サイズ (32 および 64 ビット モードでは 32 ビット) を使用するのが最適です。ただし、通常、8 ビット ops は遅くはありません。
mov eax, 35
div byte [seven] ; al = ax/7, ah=ax%7. wider operand sizes divide edx:eax by the src.
mov cl, 5
lea eax, [ecx*4 + eax] ; al = cl*4 + al. Ignore the garbage in the high bits.
; result in al
section .rodata
seven: db 7
div
は遅いため、コンパイラは定数による除算をファンキーな定数による乗算に置き換え、結果をシフトします。これは、2 の補数のオーバーフローで可能になるためです。
結果の下位部分のみが必要な場合、入力の上位ビットをゼロにせずに使用できる 2 の補数の整数演算はどれですか? lea
上位ビットをクリアせずに、4 を掛けて加算するために使用する正当化のため。