加算、減算、乗算など、これらの種類の ALU 項目を処理する場合はいつでも、2 または 3 ビットの数値から開始します。32 または 64 ビットの数値よりもはるかに簡単に処理できます。2 ビットか 3 ビットの後は、22 ビットか 2200 ビットかは問題ではなく、それ以降はまったく同じように動作します。基本的に、テーブル全体を視覚的に調べることができるように、すべての 3 ビット オペランドとその結果のテーブルを作成したい場合は手動で行うことができますが、すべての 32 ビット オペランドとその結果に対するすべての 32 ビット オペランドのテーブルはできません。合理的な時間内に手動で行うため、テーブル全体を視覚的に調べることはできません。
これは、正と負の数を表すための単なるスキームであり、理由があるのは恣意的なものではありません。狂気の理由は、加算器のロジックです(これは減算器が使用するものでもあり、同じです乗数が使用する種類のもの) 署名されていないか署名されているかは気にしません。それは違いがわからない。プログラマーが気にかけているのは、私の 3 ビットの世界では、ビット パターン 0b111 は正の 7 (+7) または負の 1 である可能性があります。同じビット パターンを追加ロジックに渡すと、同じ結果が出て、出てくる答えを符号なしまたは2 の補数として解釈することを選択できます (オペランドと結果をすべて符号なしまたはすべてとして解釈する限り)なので2 の補数)。2 の補数には、負の数の場合は最上位ビット (msbit) が設定され、正の数の場合はゼロになるという特徴もあります。したがって、符号と大きさではありませんが、msbit が符号ビットであるという話はまだあります。これは、数値の符号である 2 つの特別な数値を除いて、他のビットが実際に大きさを示しているためです。sign+magnitude notationのような符号なしの大きさではありません。
したがって、この質問全体の鍵は、自分の限界を理解することです。3 ビットの符号なし数値の場合、範囲は 0 ~ 7、0b000 ~ 0b111 です。3 ビットの符号付き ( 2 の補数) 解釈の場合、範囲は -4 から +3 (0b100 から 0b011) です。今のところ、7 + 1 を追加すると 3 ビットに制限されます0b111 + 0b001 = 0b1000
が、3 ビット システムしかないため、0b000、7 + 1 = 8 です。システムでは 8 を表すことができないため、オーバーフローです。ビットを符号なしと解釈すると、キャリー ビットまたはフラグとしても知られる「符号なしオーバーフロー」が見られます。同じビットを符号付きとして解釈すると、0b111 (-1) + 0b001 (+1) = 0b000 (0) となります。マイナス 1 プラス 1 はゼロです。オーバーフローなし、「符号付きオーバーフロー」が設定されていません...符号付きオーバーフローとは何ですか?
まず、「符号なしオーバーフロー」とは何ですか。
レジスターのビット数に関係なく「すべて同じように機能する」理由は、10 進数を基数とする小学校の数学と同じです。両方とも 1 の列にある 9 + 1 を足すと、9 + 1 = ゼロが 1 を運ぶと言います。ゼロを運ぶ1です。10 列に 1 があり、1 列に 0 があります。
1
09
+01
====
10
1 の列の数字のみに制限されていると宣言した場合、10 の列を入れる余地はありません。キャリー ビットが非ゼロであることは、オーバーフローがあることを意味します。結果を適切に計算するには、バイナリと同じように別の列が必要です。
111
111
+ 001
=======
1000
7 + 1 = 8 ですが、3 ビット システムを宣言すると 8 は実行できません。キャリー ビットをセットして 7 + 1 = 0 を実行できます。ここで、2 の補数の美しさが発揮されます。
111
111
+ 001
=======
000
上記の 3 ビットの加算を見ると、7 + 1 = 0 でキャリー ビットが設定されているのか、それとも -1 + 1 = 0 なのかはわかりません。
unsigned addの場合、ゼロ以外の次の列へのキャリー オーバーは、多くのプレースホルダーがオーバーフローしたことを意味し、実際の答えを保持するには、もう 1 つのプレースホルダー、もう 1 つの列が必要であることを小学校時代から知っています。
符号付きオーバーフロー。msbit 列のキャリーインがキャリーアウトと一致しない場合は、アカデミックな答えのようなものです。3 ビットの世界でいくつかの例を見てみましょう。したがって、2 の補数では -4 から +3 に制限されます。-2 + -3 = -5 を追加すると、正しく動作しませんか? マイナス 2 を計算するには、反転して 0b010 を 1 つ追加し、0b101 を反転して 0b110 を 1 つ追加します。マイナス 3 は 0b011 -> 0b100 -> 0b101
だから今、これを行うことができます:
abc
100
110
+ 100
======
010
b の下の数字は msbit 列への「キャリー イン」であり、a の下の数字 1 はキャリー アウトです。これら 2 つが一致しないため、「符号付きオーバーフロー」があることがわかります。
2 + 2 = 4 を試してみましょう:
abc
010
010
+ 010
======
100
あなたは言うかもしれませんが、それは正しいように見えます、確かに符号なしですが、ここでは符号付きの計算を行っているので、結果は実際には正の 4 ではなく -4 になります。2 + 2 != -4. b の下にあるキャリー インは 1、msbit のキャリーアウトは 0、キャリーインとキャリー アウトは一致しません。 符号付きオーバーフロー。
キャリーイン(またはキャリーアウト)を見なくても、符号付きオーバーフローを把握するための近道があります。 符号付きオーバーフロー、そうでなければ符号付きオーバーフローなし。opa は 1 つのオペランド、opb はもう 1 つのオペランド、res は結果です。if ( msbit(opa) == msbit(opb) ) && ( msbit(res) != msbit(opb) )
010
+ 010
======
100
これを +2 + +2 = -4 とします。msbit(opa) と msbit(opb) は等しく、結果の msbit は opb msbit と等しくないため、これは符号付きオーバーフローです。次の表を使用して考えることができます。
x ab cr
0 00 00
0 01 01
0 10 01
0 11 10 signed overflow
1 00 01 signed overflow
1 01 10
1 10 10
1 11 11
この表は、単一の列のキャリーインビット、オペランド a、オペランド b、キャリーアウト、および結果ビットのすべての可能な組み合わせです。頭を左に横向きにして、この x がキャリーインであり、a および b 列が2 つのオペランド。 cr
ペアとしてxab
011 の結果は 0+1+1 = 2 の 10 進数、つまり 0b10 の 2 進数です。したがって、キャリーインとキャリーアウトが一致しない場合、それは符号付きオーバーフローであるという、私たちに指示されたルールを取ります. x 列の項目が c 列の項目と一致しない 2 つのケースは、a と b の入力が互いに一致するが、結果ビットが a と b の反対である場合を示しています。したがって、ルールが正しいと仮定すると、キャリービットが何であるかを知る必要のないこの簡単なショートカットは、符号付きオーバーフローがあったかどうかを教えてくれます。
今あなたはH&Pの本を読んでいます。これはおそらく、mips または dlx を意味します。mips も dlx も、他のほとんどのプロセッサが行う方法でキャリーと符号付きフラグを処理しません。mips は IMO の最初の最高の命令セットではありません。その理由は主にそのためです。彼らのアプローチは決して間違っているわけではありません。典型的な znvc フラグ (ゼロ フラグ、負のフラグ、v=符号付きオーバーフロー、c=キャリーまたは符号なしオーバーフロー) の方法を学習した場合は、mips に移動するときにのみ変換する必要があります。通常、これらはすべての alu 操作で計算されます (非 mips タイプのプロセッサの場合)。符号付きおよび符号なしのオーバーフローが表示されます。加算と減算が計算されます。(私は古いミップに慣れています。おそらくこの世代の本と現在の命令セットには何か違うものがあります)。これを mips の開始時に addu add unsigned と呼ぶのは、加算器回路が符号付きと符号なしを区別しないことについて上記のすべてを学んだ後で、これは mips の大きな問題であり、この単純なことを理解するための間違った考え方に陥ってしまいます。符号付き加算と符号なし加算の間に違いがない場合でも、違いがあるという信念につながります。異なる方法で計算されるのは、オーバーフロー フラグだけです。乗算と除算には間違いなく 2 の補数と符号なしの差があり、理想的には符号付き乗算と符号なし乗算が必要です。または、制限に対処する必要があります。
シンプルをお勧めします(ビット操作の強さと2の補数に応じて)) 高級言語で書ける練習問題。基本的には0~7に0~7を加算した符号なし数字の組み合わせを全て取り、結果を保存します。10 進数と 2 進数 (オペランドに 3 ビット、結果に 4 ビット) の両方で出力し、結果が 7 より大きい場合はオーバーフローも出力します。-4 から +3 に追加された -4 から +3 の数字を使用して、符号付き変数を使用してこれを繰り返します。+/- 記号付きの 10 進数と 2 進数の両方を出力します。結果が -4 未満または +3 より大きい場合は、オーバーフローが出力されます。これら 2 つの表から、上記の規則が正しいことがわかるはずです。許可されたサイズ (この場合は 3 ビット) のオペランドと結果のビット パターンを厳密に見ると、加算演算で同じ結果が得られることがわかります。これらのビット パターンが符号なしと見なされるか、2 の補数と見なされるかに関係なく、指定された入力ペアの同じビット パターン。また、あなたはそれを確認することができます符号なしオーバーフローは、結果がその 4 番目の列を使用する必要がある場合であり、msbit のキャリーアウトがあります。キャリーインがキャリーアウトと一致しない場合の符号付きについては、オペランドと結果のミリ秒ビットを調べるショートカットを使用して確認できます。さらに良いのは、プログラムでこれらの比較を行い、何かを出力することです。したがって、結果が 7 より大きいという注記がテーブルに表示され、結果にビット 3 が設定されているという注記が表に表示されている場合、符号なしの表は常にそうであることがわかります (0 の入力に制限されます)。 7)に。そして、より複雑なもの、符号付きオーバーフロー、結果が-4未満で3より大きい場合、およびオペランドの上位ビットが一致し、結果の上位ビットがオペランドと一致しない場合は常にです。
私はこれが非常に長く、非常に初歩的であることを知っています. ここでマークを完全に見逃した場合は、コメントしてください。この回答を削除または書き直します。
2の残りの半分は魔法を補完します。ハードウェアには減算ロジックがありません。2 の補数に「変換」する 1 つの方法は、「反転して 1 を追加する」ことです。2 の補数を使用して 3 - 2 を引きたい場合、実際に起こることは +3 + (-2) と同じです。+2 から -2 にするには、反転して 1 を追加します。私たちの小学校の追加を見て、最初の列のキャリーインの穴に気づきましたか?
111H
111
+ 001
=======
1000
穴の上にHをつけました。キャリーインビットはオペランドに追加されますよね?私たちの加算ロジックは 2 入力加算器ではなく、3 入力加算器です。はい? ほとんどの列は、2 つのオペランドを計算するために 3 つの 1 ビット数を加算する必要があります。最初の列で 3 入力加算器を使用すると、追加する場所ができました。3 - 2 = 3 + (-2) = 3 + (~2) + 1 を減算したい場合:
1
011
+ 101
=====
開始して記入する前に、次のとおりです。
1111
011
+ 101
=====
001
3 - 2 = 1。
ロジックの機能は次のとおりです。
追加の場合はキャリーイン= 0; b オペランドは反転されず、キャリーアウトも反転されません。減算の場合はキャリーイン= 1; b オペランドは反転され、キャリーアウトは反転される可能性があります。
上記の追加はキャリーアウトを示していますが、これが符号なし演算 3 - 2 = 1 であることは言及しませんでした。2 の補数のトリックを使用して符号なし演算を実行しました。 unsigned if add または if reduction に同じルールが適用されます。実行が反転される可能性があると言った理由は、一部のプロセッサは実行を反転し、一部のプロセッサは反転しないためです。カスケード操作に関係していますたとえば、32 ビットの加算ロジックを使用し、キャリー フラグとキャリー付きの加算またはボロー付きの減算命令を使用して、64 ビットの加算または減算、またはベース レジスタ サイズの任意の倍数を作成します。32 ビット システム a:b + c:d に 2 つの 64 ビット数値があるとします。ここで、a:b は 64 ビット数値ですが、2 つのレジスタ a と b に保持されます。ここで、a は上半分、b は下半分です。半分。したがって、a:b + c:d = e:f は、キャリー ビットを持ち、キャリーを追加する符号なしの 32 ビット システムでは次のようになります。
add f,b,d
addc e,a,c
加算は、ステータス レジスタのキャリー フラグの最上位ビット レーンからキャリーアウトaddc
ビットを残します。命令はキャリー付き加算で、オペランド a+c を取り、キャリー ビットが設定されている場合はさらに 1 つ追加します。a+c+1 は、結果を e に入れ、キャリーをキャリー フラグに入れるので、次のようになります。
add f,b,d
addc e,a,c
addc x,y,z
96ビット追加などです。ここでも、他のプロセッサのようにフラグを使用しないため、mips には非常になじみのないものです。符号付きキャリーアウトで反転または非反転が発生するのは、特定のプロセッサの借用による減算です。減算の場合:
減算の場合はキャリーイン= 1; b オペランドは反転され、キャリーアウトは反転される可能性があります。
ボロー付き減算の場合、ステータス レジスタからのキャリー フラグがボローを示している場合、キャリー インは 0 であり、それ以外の場合はキャリー インは 1 であり、キャリー アウトをステータス レジスタに取得してボローを示す必要があります。 .
基本的に、通常の減算では、一部のプロセッサは b オペランドを反転し、途中でキャリーを実行し、一部のプロセッサは b オペランドを反転し、途中でキャリーを実行しますが、途中で実行を反転しません。次に、条件付き分岐を実行する場合は、キャリーフラグがより大きいか小さいかを知る必要があります(多くの場合、構文には大きい場合は分岐があり、小さい場合は分岐があり、キャリーの場合はどれが単純化された分岐であるかがわかります)キャリークリアの場合はセットまたは分岐します)。(私が今言ったことを「理解」しない場合、それは別の同様に長い答えであり、ミップを勉強している限り何の意味もありません)。