1

ここに電卓コードの短い部分があります。負の数で算術演算を実行する方法について助けを求めたいです。

これが私のコードです:

ASSCII_LOOP : MOV EDX , 0
                  DIV ECX 
                  OR DL , 30H       ;MAKE REMINDER ASSCII
                  MOV [ESI] , DL    ;PUT ASSCII IN ASSCII_NUM
                  DEC ESI
                  INC EBP           ;ADD ONE TO THE CHAR'S COUNTER
                  CMP EAX , 0       ;IF AX > 0 GOTO 
                  JA ASSCII_LOOP    ;ASSCII_LOOP

    CMP EDI , 0                     ;CHECK IF THAT WAS A NEGETIVE NUMBER
    JZ REST                         ;IF THATS NOT NEGETIVE GOTO REST
    MOV DL , '-'
    MOV [ESI] , DL                  ;ADD A MINES SIGN TO THE STRING
    DEC ESI
    INC EBP

REST :
    LEA EDI , ASSCII_NUM

    ;MOVE THE ASSCII CODE TO IT'S RIGHT PLCAE IN ASSCII_NUM
    ORDER_ASSCII : INC ESI
                   MOV AL , BYTE PTR [ESI] 
                   MOV BYTE PTR [EDI] , AL
                   INC EDI
                   DEC EBP
                   CMP EBP , 0
                   JA ORDER_ASSCII

    MOV CL , '$'           
    MOV BYTE PTR [EDI] , CL         ;AT LAST PUT A DOLLOR SIGN AT THE END OF ASSCII_NUM

このプログラムは、入力が負かどうかをチェックし、負の場合は REST に進みます。このことを次のように問いたい。

*このプログラムにおける REST の機能は何ですか?

*このプログラムで負の数の演算を行うコードを書き始める方法についてアドバイスをお願いしたいです。2' の補数については既に知っています。必要なのは 2 の補数のコードです。どこから、どのように開始すればよいかわかりません。私はアセンブリプログラミングに本当に慣れていません。あなたが私を助けてくれることを願っています。

試したコードは次のとおりですが、機能しません。理解を深めるために個別に配置します。

neg_num: 
  mov ax, data
  mov ds, ax
  mov es, ax
  mov ah, 0000h
  mov al, num
  NOT al
  mov bl, al
  adc al, 00000001B
  mov bl, al
4

2 に答える 2

1

Scarface23、あなたはこれであまりにも多くの問題を抱えています! x86 は 1 の補数を使用しないため、この例が役立つ場合とそうでない場合があります。2 の補数を使用するのは、「うまく機能する」ためです (とにかく、そうなるはずです)。最新のコードは 2 の補数を提供する必要があります (adc実際には正しくありません) neg al

最初の例のREST部分は、バッファの「最後」に配置した文字をバッファの「先頭」に移動するだけです。正しい位置 ( esi) で印刷位置を開始した場合は、その必要さえありません。

表示する直前にtest eax, 8000h、数値が負かどうかを判断するようなことをしました。負の場合は、マイナス記号が必要であることを示すneg eaxフラグ ( ) を設定します。edi全体で32ビットの数値を使用しているので、私はそうします...

test eax, eax
jns is_positive

ビット 15 だけをテストしても 16 ビットの数値では機能しますが、ここでは 32 ビットのレジスタ/命令を使用しています。数字のサイズが混在していると、問題が発生する可能性があります。完全に優れた (テストされていませんが、問題はありません) 32 ビット数値から ASCII へのルーチンを作成したので、それに 32 ビット数値を入力します。または、全体で 16 ビット レジスタに切り替えても、ルーチンは引き続き機能すると思います。文字列を「$」で終了すると、これが 16 ビット コードである可能性があるという手がかりが得られます。32 ビットの数値/レジスタ/命令を使用しても機能しますが、数値の 1 つのサイズに固執します。悩むことは少ないと思います。

表示されていない部分-キーボードから数字を取得する-ユーザーがマイナス記号で始まる場合、マイナス記号をスキップしてフラグを設定します。ascii をそのまま数値に変換し、フラグが設定されている場合は最後にneg axorを変換します。neg eax

mov eax, 3
sub eax, 4

今、eax負になります-2の補数-それを使用してください。正の数に変更したい場合は、すべてのビットを「反転」して (notまたはxorすべて 1 で)、1 を追加します (これは、正から負または負から正のいずれかで機能します)。neg単一の命令でそれを行うだけです。

符号を保持しながら数値のサイズを変更する必要がある場合、movsx eax, alまたはそのように変更できますが、同じサイズに固執する方が簡単です。

あなたのコードには、私が見ていない重大なエラーがあるかもしれませんが、あなたが示したものは私にはかなりまともに見えます (mov al, RESULT +1一部を除く)。問題は他の場所にあると思われます-おそらく数値のサイズが混在しています...

于 2013-02-14T07:22:13.290 に答える
1

単純な減算を実行するために 2 の補数を実装する方法の例を示します。これを達成する方法を示すために、独自の一般的なニーモニックを使用します。その後、それをアセンブリ プログラムに適用できます。

AB = A + (B( 1 の補数) + 1) のモデルに従います。

では、アキュムレータ B の内容を A (AB) から減算するとします。

アキュムレータ A 値のオペランドが設定されていると仮定します ([AccA]<-someValue)。

最初に: メモリから必要な値を取得し、アキュムレータ B に格納します。

    MOVM   B   'Move contents of memory into Acc B   ([AccB]<-someOtherValue)

2 番目: B の値を補完して、その否定を取得します。

    CMPL   B   'AccB = -B   

3 番目: 1 の補数値を一時記憶域用のレジスタに移動します。

    MOVBR R0  'Move contents of Acc B to Register 0

4 番目: 現在使用可能なアキュムレータ B に「1」をロードします。

   MOVB   #1  'Move a '1' immediately to Acc B  [AccB]<- 1

5番目: AccB の内容を -B が保存されている RO に追加したい

   ADDB   RO    ' This takes care of the (B(complement) +1 part of our model)
                ' The resulting value will be stored in AccB

6: 最後に、AccA と AccB を追加します。

   ADAB     'Mnemonic for "Add AccA to AccB, result stored in AccA"

これにより、A + (B(補数) + 1) の要件が満たされます。

これはすべて、アーキテクチャで単純な SUBA または SUBB コマンドが許可されていないことを前提としています。一部のプロセッサにはそれが組み込まれていますが、その仕組みを学んでいるので、上記の基本的なコード構造がより良い絵を描くことを願っています.

于 2013-02-13T19:42:32.677 に答える