3

これは非常に素朴な質問です (私は知っています) が、CPU の基本的な命令セットが実際にどのように実行されるかを検討するための良い出発点になると思います。

2 の補数システムでは、実装で表現できる最大の負数の符号を反転することはできません。これの理論的な理由は、最も負の数の否定が実装の範囲外になるという点で明らかです (範囲は常に
-128 から 127 のようなものです)。

ただし、最も負の数に対して否定演算を実行しようとすると、実際に何が起こるかはかなり奇妙です。たとえば、8 ビット表現では、最も負の数は -128、つまり 2 進数で 1000 0000 です。通常、数値を否定するには、すべてのビットを反転してから 1 を追加します。ただし、これを -128 で実行しようとすると、次のようになります。

1000 0000 ->
0111 1111 ->
1000 0000

あなたが始めたのと同じ番号。このため、ウィキペディアはそれを「奇妙な数」と呼んでいます。

同じウィキペディアの記事では、上記の否定は

最上位ビットへのキャリーがあったが、最上位ビットからのキャリーがなかったため、オーバーフロー状態として検出されました。

だから私の質問はこれです:
A) 一体どういう意味ですか? B) CPU は、
この否定に関連するアクシデントを回避するために、基本的な算術演算を実行するたびに追加のエラー チェック ステップを実行する必要があり、大きなオーバーヘッドが発生するようです。その場合、表現できる数値の範囲を切り捨てて、奇妙な数値を除外しないのはなぜですか (つまり、8 ビットの場合、-127 から 127 まで)。そうでない場合、余分なオーバーヘッドを発生させずにそのようなエラー チェックを実装するにはどうすればよいでしょうか?

4

4 に答える 4

4

MSB からのキャリーアウト ビットは、さらにビットが必要であることを示すフラグとして使用されます。それがなければ、いつラップアラウンドするかを検出する方法のない剰余算術1のシステムができてしまいます。

剰余算術では、数値を扱うのではなく 、同じ剰余を持つ数値の等価クラスを扱います。このようなシステムでは、127 に 1 を追加すると、-128 が得られ、+128 と -128 は同じ等価クラスに属すると結論付けられます。

−127 から +127 の範囲の数に制限した場合、127 + 1 = −127 はナンセンスなので、加算を再定義する必要があります。

2 の補数演算は、コンピューターから提示された場合、本質的にモジュラー演算であり、オーバーフローを検出する機能を備えています。

0001に加算する と、4 ビット加算器は次のようになり0111ます。MSB では、キャリーインとキャリーアウトが異なることがわかります。

     0        0        0        1
     | 0      | 1      | 1      | 1
     | |      | |      | |      | |
     v v      v v      v v      v v
0 <- ADD <-1- ADD <-1- ADD <-1- ADD <- 0
^     |    ^   |        |        |
      v        v        v        v
      1        0        0        0

ALU がオーバーフローが発生したことを通知するために使用するのはこのフラグであり、余分な手順は必要ありません。

1. 剰余演算は、-127 から 128 ではなく 0 から 255 になりますが、基本的な考え方は同じです。

于 2010-10-28T20:16:28.433 に答える
3

CPUが別のチェックを行うのではなく、トランジスタがこれが発生したときに気付くように配置されている. エンジニアが設計を開始する前に 2 の補数を選択したため、そのように構築されています。

その結果、オーバーフローしない結果が返されるのと同じクロック サイクルで発生します。


それはどのように機能しますか?

「1 を追加」段階では、カスケード ロジックが実装されます。LSB から始めて、各ビットが順番に真理値表に適用されます。

old-bit  carry-in  new-bit  carry-out
-------------------------------------
   0        0        0         0
   0        1        1         0
   1        0        1         0
   1        1        0         1

(つまりnew-bit = old-bit xor carry-incarry-out = old-bit and carry-in)。LSB の「キャリーイン」は追加する 1 であり、残りのビットは前のビットの「キャリーアウト」です (これがカスケードで実行する必要がある理由です)。 .

これらの回路の最後は、 の回路を追加するだけですsigned-overflow = (carry-in and not carry-out)

于 2010-10-28T19:29:23.577 に答える
2

まず、ウィキペディアの記事では、負の符号付きの数値から符号付きの数値に否定することはできないと述べています。そして、それらが意味するのは、正の128を表すのに9ビットかかるためです。これは、8ビットレジスタでは実行できません。変換として負の符号付きから正の符号なしに移行する場合は、十分なビットがあります。そして、あなたが0x80を否定するとき、それが正しい答えであるため、ハードウェアはあなたに0x80を与えるはずです。

足し算、引き算、掛け算などの2の補数の足し算は、小学校の小数の数学と同じです。2進数を並べて列を追加すると、その列の結果が最下位桁になり、残りは次の列に繰り越されます。たとえば、0b001を0b001に追加します

1
001
001
===
010

右端の列に2つを追加すると、結果は0b10(10進数の2)になり、ゼロを書き込んでから1を実行します。1プラスゼロプラスゼロは1、何も実行しません。ゼロプラスゼロはゼロです。結果は0b010です。

1 + 1が0b10であり、0と書く右端の列は、1をキャリーします。同時に、1をキャリーするのは、右端の列のキャリーアウトであり、2番目の列のキャリーインです。また、鉛筆と紙の数学では、通常、ゼロ以外の場合にのみ何かの持ち運びについて話しますが、それについて考えると、常に2番目の列のような数字を持ちます。1プラスゼロはゼロを運ぶものです。

2の補数の否定は、反転して1を加算するか、ビットをウォークしてポイントまで反転してから反転しないか、ゼロから数値を引いた結果をとることと考えることができます。

あなたはそれが価値があるもののために鉛筆と紙を使って二進法で引き算をすることができます、小数と比較して借りるときあなたの頭を傷つけますが、働きます。あなたが求めていることについては、反転を考えて追加してください。

これを8ビットよりもさらに少ないビットに減らすと、頭を包み込むのが簡単になります。3は管理可能な数であり、すべてそこからスケーリングされます。

したがって、以下の最初の列は入力であり、2番目の列は反転バージョンであり、3番目の列は2番目の列に1を加えたものです。4番目の列はmsbitへのキャリーインであり、5番目の列はmsbitのキャリーアウトです。

000 111 000 1 1
001 110111 0 0
010101110 0 0
011 100101 0 0
100 011 100 1 0
101 010 011 0 0
110 001 010 0 0
111 000 001 0 0

1〜2ビットを追加する方法を簡単に説明します。

00 + 1 = 001
01 + 1 = 010
10 + 1 = 011
11 + 1 = 100

数値に1を加算する場合、2番目のビットから3番目のビットに実行する唯一のケースは、ビットがすべて1の場合であり、そこにある1つのゼロはカスケードキャリービットを停止します。したがって、上記の3ビット反転テーブルでは、msbitにキャリーがある2つのケースは111と011です。これは、これらの下位ビットがすべて設定されている2つのケースだけだからです。111の場合、msbitにはキャリーインとキャリーアウトがあります。011の場合、msbitにはキャリーインがありますが、キャリーアウトはありません。

したがって、他の誰かが述べているように、チップにトランジスタが配線されています。msbitキャリーインが設定されていて、msbitキャリーアウトが設定されていない場合は、どこかにフラグを設定します。それ以外の場合は、フラグをクリアします。

したがって、上記の3ビットの例はスケーリングされていることに注意してください。反転した後、追加する前に0b01111111がある場合は、キャリーを実行せずにキャリーインを取得します。0b11111111をお持ちの場合は、キャリーインとキャリーアウトを取得します。ゼロは、反転したときに同じ数値が返される数値でもあることに注意してください。違いは、ビットが符号付きと見なされる場合、否定されたときにゼロを表すことができ、すべてゼロの1はできないことです。

肝心なのは、これは危機や世界の終わりではないということです。プロセッサには、キャリービットと重要なビットがどちらか一方から落ちてオーバーフローとアンダーフローが発生する数学やその他の操作がたくさんあります。ほとんどの場合、プログラマーはそのような状態をチェックせず、それらのビットが床に落ちて、プログラムがクラッシュしたり、プログラマーが8ビットの計算に16ビットの数値を使用して悪いことが起こらないことを確認したりします。 、または同じ理由で5ビットの計算に8ビットの数値を使用します。

ハードウェアは、加算と減算の符号付きまたは符号なしを認識しないことに注意してください。また、ハードウェアは減算する方法を知りません。ハードウェア加算器は、結果と実行を伴う3ビット加算器(2つのオペランドとキャリーイン)です。これらのワイヤ8には、8ビットの加算器または減算器があります。キャリーなしの加算は、lsbitキャリーインとしてゼロが配線された状態で直接配線された2つのオペランドです。キャリー付きの加算は、キャリービットが配線された状態で直接配線された2つのオペランドです。 lsbitキャリーイン。減算は、2番目のオペランドが反転され、1がキャリーインビットで加算されます。少なくとも高レベルの観点からは、そのロジックはすべて、カジュアルな検査では理解しにくい方法で最適化および実装できます。

本当に楽しい演習は乗算です。鉛筆と紙で2進数の乗算を行うことを考えてから、一連のシフトと加算であるため、10進数よりもはるかに簡単であることに気付きます。十分なゲートがあれば、各結果ビットを方程式として表すことができ、方程式への入力がオペランドになります。つまり、必要に応じて単一クロックの乗算を実行できます。初期にはゲートが多すぎたため、マルチクロックのシフトと加算が行われ、今日はゲートを焼き付けて単一クロックの乗算を取得します。また、これを理解すると、16ビット= 8ビット×8ビット乗算と言った場合、下位8ビットの結果は符号付き乗算でも符号なしでも同じになることに注意してください。ほとんどの人はint=int*int;のようなことをするので。結果ビットだけが気になる場合は、符号付きまたは符号なしの乗算は本当に必要ありません(フラグのチェックなし、等)。楽しいもの..

于 2010-10-28T21:53:41.293 に答える
0

ARM アーキテクチャ マニュアル (DDI100E):

OverflowFrom
     Returns 1 if the addition or subtraction specified as its parameter 
     caused a 32-bit signed overflow. [...]
     Subtraction causes an overflow if the operands have different signs,
     and the first operand and the result have different signs.

NEG
     [...]
     V Flag = OverflowFrom(0 - Rm)

NEG は、数値の否定、つまり 2 の補数を計算するための命令です。

フラグはV符号付きオーバーフローを通知し、条件分岐に使用できます。これは、他の 3 つのフラグ Z (ゼロ)、C (キャリー)、および N (負) と共に、さまざまなプロセッサ アーキテクチャ間でかなり標準的です。

0 - (-128) = 0 + 128 = -1281 オペランドが0で、第 2 オペランドと結果が-128であるため、オーバーフローの条件が満たされ、Vフラグが設定されます。

于 2010-10-29T09:25:42.747 に答える