3

したがって、符号なしの数値を加算して1を実行するとオーバーフローし、減算を使用して0を実行すると、オーバーフローします。しかし、これはすべての場合に機能しますか?

5-0を行う場合:0101-0000

= 0101 +(1111 + 1)

= 0101 +0000

= 0101 ...ここでは、1ではなくゼロの実行があります。この場合、どのように説明しますか?それを行う別の方法はありますか?

(MIPSアーキテクチャーなどを使用)

- -編集

アマダンに感謝します。しかし、私はその部分を理解しています。私の問題は、ゼロが特殊なケースのように見えることです。正規数の動作に従わないようです。上記の例では、1の実行はありません。

私は現在、ALUを使用して回路設計を行っており、オーバーフロー検出を実装しようとしています。この1つのケースが発生したとき、他のケースの動作に従わない場合があります。

減算では、2番目のオペランドがALUに入る前に事前に反転されている(2の補数)(次に最初のオペランドに追加される)と想定しています。したがって、減算の「invert_b」が1に設定されている場合は常に、bが反転され、チェックしているケースが減算であると想定します。

4

3 に答える 3

6

msbitの実行ビットは、それ自体が符号なしでカバーされていると思います。符号付きの場合は、msbitへのキャリーインとキャリーアウトが異なるかどうかを確認してください。

結果が使用可能なビット数に適合するため、5-0はオーバーフローしません。15-1が符号付き数値の4ビットシステムをオーバーフローしないのと同じ方法

5-0 = 0101 + 1111 + 1

    1
 0101
+1111
=====

11111
 0101
+1111
=====
 0101

したがって、5-0は確かに1を実行します。これは、オーバーフローではない減算であるためです。

15-1 = 1111 +〜1、キャリーインセット

    1
 1111
 1110
 ====

11111
 1111
 1110
 ====
 1110

あなたが述べたように、1アウトの減算は符号なしオーバーフローではありません

同様に、キャリーインビットが設定されている場合は-1 --1 = 1111 +〜1

11111
 1111
 1110
 ====
 1110

最後のビットへのキャリーインは1であり、キャリーアウトはそれらが一致する1であり、符号付きオーバーフローはありません。

キャリーインクリアで8+8 = 1000 + 1000

    0
 1000
+1000
=====

10000
 1000
+1000
=====
 0000

符号なしオーバーフロー。

うーん4+4

    0
 0100
+0100
=====

01000
 0100
+0100
=====
 1000

unsignedadd実行は0です。これはunsignedオーバーフローではありません。ただし、msbitへのキャリーインと実行が異なるため、これは符号付きオーバーフローです。+4 + +4 = +8、4ビットの符号付きシステムでは+8を表すことができないため、符号付きオーバーフローは正確です。

ビット数に関係なく、奇妙な数はすべてゼロと1であり、残りはゼロです。4ビットシステムの場合は0と8または-8です。

2、3、または4ビットの数字をすべて組み合わせてグラフを作成し、それらすべてを手動で調べて、意味があることを確認します。幅がいくつあってもスケーリングするものは何でも、100ビット加算器は10ビット加算器のように機能します...

add           C V  unsigned    signed
00 + 00 = 000 0 0  0 + 0 = 0   0 +  0 =  0
00 + 01 = 001 0 0  0 + 1 = 1   0 +  1 =  1
00 + 10 = 010 0 0  0 + 2 = 2   0 + -2 = -2
00 + 11 = 011 0 0  0 + 3 = 3   0 + -1 = -1
01 + 00 = 001 0 0  1 + 0 = 1   1 +  0 =  1
01 + 01 = 010 0 1  1 + 1 = 2   1 +  1 =  2  signed cannot represent a +2
01 + 10 = 011 0 0  1 + 2 = 3   1 + -2 = -1
01 + 11 = 100 1 0  1 + 3 = 4   1 + -1 =  0  unsigned cannot represent +4
10 + 00 = 010 0 0  2 + 0 = 2  -2 +  0 = -2 
10 + 01 = 011 0 0  2 + 1 = 3  -2 +  1 = -1
10 + 10 = 100 1 1  2 + 2 = 4  -2 + -2 = -4 neither +4 nor -4 will fit in 2 bits
10 + 11 = 101 1 1  2 + 3 = 5  -2 + -1 = -3 neither +4 nor -3 will fit in 2 bits
11 + 00 = 011 0 0  3 + 0 = 3  -1 +  0 = -1 
11 + 01 = 100 1 0  3 + 1 = 4  -1 +  1 = -2 +4 does not fit in 2 bits
11 + 10 = 101 1 1  3 + 2 = 5  -1 + -2 = -3 neither +5 nor -3 fit in 2 bits
11 + 11 = 110 1 0  3 + 3 = 6  -1 + -1 = -2 6 does not fit in 2 bits
sub
00 - 00 = 100 0 0
00 - 01 = 011 1 0  0 - 1 = -1   -1 does not fit in an unsigned result
00 - 10 = 010 1 1  0 - 2 = -2  0 - -2 = +2  
00 - 11 = 001 1 0  0 - 3 = -3
01 - 00 = 101 0 0
01 - 01 = 100 0 0
01 - 10 = 011 1 1  1 - 2 = -1  1 - -2 =  3
01 - 11 = 010 1 1  1 - 3 = -2  1 - -1 =  2
10 - 00 = 110 0 0  
10 - 01 = 101 0 1             -2 -  1 = -3
10 - 10 = 100 0 0
10 - 11 = 011 1 0  2 - 3 = -1
11 - 00 = 111 0 0
11 - 01 = 110 0 0
11 - 10 = 101 0 0
11 - 11 = 100 0 0

上記を生成したコード

printf("add\n");
for(ra=0;ra<4;ra++)
{
    for(rb=0;rb<4;rb++)
    {
        rd=(ra&1)+(rb&1);
        rc=ra+rb;
        rd=(rd>>1)&1;
        re=(rc>>2)&1;
        if(re) c=1; else c=0;
        if(rd!=re) v=1; else v=0;

        if(ra&2) printf("1"); else printf("0");
        if(ra&1) printf("1"); else printf("0");
        printf(" + ");
        if(rb&2) printf("1"); else printf("0");
        if(rb&1) printf("1"); else printf("0");
        printf(" = ");
        if(rc&4) printf("1"); else printf("0");
        if(rc&2) printf("1"); else printf("0");
        if(rc&1) printf("1"); else printf("0");
        printf(" %u %u\n",c,v);
    }
}
printf("sub\n");
for(ra=0;ra<4;ra++)
{
    for(rb=0;rb<4;rb++)
    {
        rd=(ra&1)+((~rb)&1)+1;
        rc=ra+((~rb)&3)+1;
        rd=(rd>>1)&1;
        re=(rc>>2)&1;
        if(re) c=0; else c=1;
        if(rd!=re) v=1; else v=0;

        if(ra&2) printf("1"); else printf("0");
        if(ra&1) printf("1"); else printf("0");
        printf(" - ");
        if(rb&2) printf("1"); else printf("0");
        if(rb&1) printf("1"); else printf("0");
        printf(" = ");
        if(rc&4) printf("1"); else printf("0");
        if(rc&2) printf("1"); else printf("0");
        if(rc&1) printf("1"); else printf("0");
        printf(" %u %u\n",c,v);
    }
}

さて、あなたの質問は符号なしの数字について話していましたね?したがって、Vビットや右半分(符号付きの半分)は気にしないかもしれません。

これが私が実装した小さな16ビットプロセッサ用のHDL/RTLです:

case 4b0000:
{
    //0000 add rd,rs
    op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
    op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
    op_res = op_a + op_b;
    reg[1].value[CBIT] <= op_res[16];
    reg[1].value[NBIT] <= op_res[15];

    if(op_res[16;0] == 16h0000)
    {
        reg[1].value[ZBIT] <= 1b1;
    }
    else
    {
        reg[1].value[ZBIT] <= 1b0;
    }
    if((op_a[15] == op_b[15]) && (op_res[15] != op_b[15] ) )
    {
        reg[1].value[VBIT] <= 1b1;
    }
    else
    {
            reg[1].value[VBIT] <= 1b0;
    }
    reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}
case 4b0001:
{
    //0001 sub rd,rs
    op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
    op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
    op_res = op_a - op_b;
    reg[1].value[CBIT] <= (~op_res[16]);
    reg[1].value[NBIT] <= op_res[15];

    if(op_res[16;0] == 16h0000)
    {
        reg[1].value[ZBIT] <= 1b1;
    }
    else
    {
        reg[1].value[ZBIT] <= 1b0;
    }
    if((op_a[15] != op_b[15]) && (op_res[15] == op_b[15] ) )
    {
        reg[1].value[VBIT] <= 1b1;
    }
    else
    {
        reg[1].value[VBIT] <= 1b0;
    }
    reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}

他のロジックで符号付きオーバーフローのmsbitを確認したことがありますが、直接分析で考えられるすべての組み合わせを試したときに、キャリーインとキャリーアウトの方法が一致しないケースを見つけることができませんでした。

私が答えで船外に出た場合、最初にそれを切り取ってもかまいません。5-0は1のキャリーアウトとして1を持っていることを示しています。これは、減算の場合はオーバーフローではありません。長い答えは、符号付きと符号なし、および加算器が一般的にロジックでどのように機能するかについて頭を悩ませるのが難しい場合があるためです。加算器は符号付きまたは符号なしを認識または考慮しません。加算と減算を考慮します。減算を使用すると、2番目のオペランドを反転し、キャリーインをlsbitに反転し、キャリーをmsbitから実行します(加算、キャリー付き加算について考えてください)。 、subおよびsub withキャリー)。符号付きvs符号なしは、それ自体が問題になります(2の補数の美しさ)。上記を符号なしのみの議論に還元すると、符号付きオーバーフローが(符号なしオーバーフローとして)カジュアルなオブザーバーには明白ではないため、半分以上単純になります。

デバッグされたHDLを切り取って貼り付けたところ、そうしなかった場合に多くの応答/修正が得られることを願っています...上記のすべてを納得させ、アクセスした他のプロセッサの結果と比較して、数日を費やしました。うまくいけば、これはあなたに数日を節約します。

于 2011-10-22T02:51:51.233 に答える
3

専門家ではありませんが、引き算に関する記述全体が間違っているようです。

減算は、2つの基本的な方法で実装できます。直接減算として、または2の補数の加算としてです。

2の補数の加算を使用する場合、それはあなたが言うようにです:1のキャリーはアンダーフローです。

5 - 6
= 0101 - 0110
= 0101 + (1001 + 1)
= 0101 + 1010
= (0)1111, carry 0 = underflow

直接減算すると、1つのキャリーがアンダーフローになります。

0101 - 0110:
0     to    1 is 1
1     to (1)0 is 1, carry 1
1 + 1 to (1)1 is 1, carry 1
0 + 1 to (1)0 is 1, carry 1 = underflow
于 2011-10-21T01:45:17.403 に答える
0

加算器のオーバーフロー検出ユニットを設計する他の同等の方法があるかもしれませんが、最も一般的なのはCin XOR Coutです。たとえば、講義4の終わりを参照してくださいhttp://cs.nyu.edu/~gottlieb/courses/2007-08-fall/arch/class-notes.html

追加される数値(2の補数で反転されているかどうかは関係ありません。後でこれらの値を確認します)が最後の桁の計算に反映されるが、サポートされているビットサイズを超える桁には反映されないかどうかを確認するだけです。反対。

これは、実行されて実行されない場合、結果は負である必要があり(MSBは1である必要があるため)、オペランドは正である必要があるため(負である場合は実行されるため)、理にかなっています。これはオーバーフローの定義です。2つの正の値を合計して負の値にすることはできないためです。

これは署名付きモデルですが、署名なしと言ったので、それがあなたが探しているものかどうかはわかりません。その場合、その通りです。実行が1の場合、単純な加算モデルはオーバーフローします(これは、各オペランドのMSBに追加の0があると見なす場合、上記と同等です。実行は次のようになります。キャリーインが1の場合、常に0であり、オーバーフローが発生します。この場合のキャリーインは、このモデルのキャリーインです)。

値が負の場合、減算するとアンダーフローが発生します。正のオペランドのMSBが0で、負のオペランドが1(符号拡張)であると見なすと、同等性を再び導き出すことができます。次に、結果のMSBが1の場合、負になります。これは、元のモデルでの実行(新しいモデルでのキャリーイン)が0の場合に発生します。これは、新しいモデルでの結果のMSBが1のままになるためです。 。

あなたの例も例外ではありません。結果が正であるため、キャリーアウトが1の0101 + 1111 + 1 = 0101であり、したがってアンダーフローはありません。

于 2011-10-21T02:43:54.283 に答える