初学者在这里。我正在尝试在 Verilog 中编写一个简单的 16 位微处理器并在 Spartan 6 上实现它。 ALU 实现所有有符号操作(根本没有无符号操作)。所有输入都是连线并带有符号。结果存储在签名寄存器中。
我的问题是找到一种合理的方法来检测溢出。当前检测溢出的速度并不重要,因为它所做的只是触发故障并停止系统。
我相信我已经找到了如何检测加法和减法溢出的方法,但无论如何我都希望得到保证。
这是补充,其中 o 是溢出标志寄存器:
if((a_in >= 0) && (b_in >= 0) && (res_out < 0)) o <= 1'b1;
else if((a_in < 0) && (b_in < 0) && (res_out >= 0)) o <= 1'b1;
else o <= 1'b0;
这是减法:
if((a_in >= 0) && (b_in < 0) && (res_out < 0)) o <= 1'b1;
else if((a_in < 0) && (b_in > 0) && (res_out >= 0)) o <= 1'b1;
else o <= 1'b0;
控制矩阵负责 a_in 和 b_in 的保持时间,以便完成溢出检测,因为它仅在计算结果后(即下一个时钟周期)完成。
我在这里环顾四周,发现的只是检测其他语言(如 C 或 C++)中的溢出。我正在寻找一个在有符号乘法中检测溢出的示例实现。
输入 a_in 和 b_in 都是有符号线并且都是 16 位宽。结果寄存器 res_out 是有符号的,也是 16 位宽。理想情况下,我有一个 33 位宽的结果寄存器,无论如何都不会发生溢出,但这不是一个选项。
帮助表示赞赏。也欢迎任何更好的方法来检测加法和减法溢出。
最佳答案
另外看看检测溢出和下溢,分析一个简单的 4 位示例,符号扩展到 5 位。
添加所有 +ve
3 : [0]0011
+ 3 : [0]0011
= 6 : [0]0110
带负数
-3 : [1]1101
+ -3 : [1]1101
= -6 : [1]1010
现在导致溢出:结果应该是 +8,但不能用 4 位表示。
+7 : [0]0111
+1 : [0]0001
+8 : [0]1000
现在导致下溢:结果应该是 -9 但不能用 4 位表示。
-8 : [1]1000
+ -1 : [1]1111
-9 : [1]0111
因此,如果我们将输入符号扩展 1 位,很容易检测上溢和下溢
localparam WIDTH = 4;
localparam MSB = WIDTH-1;
logic [WIDTH-1:0] a;
logic [WIDTH-1:0] b;
logic [WIDTH-1:0] result;
logic extra;
logic overflow;
logic underflow;
always @* begin
{extra, result} = {a[MSB], a} + {b[MSB], b} ;
overflow = ({extra, result[MSB]} == 2’b01 );
underflow = ({extra, result[MSB]} == 2’b10 );
end
关于乘法,我不明白为什么您不能拥有 32 位寄存器。即使您将最终输出减少到 16。
执行位减少时,您需要检查该值是否低于最大值,并高于可以通过减少的宽度支持的最小负数。
注意:此外,结果比最大输入大 1 位。截断回原始宽度时会发生上溢/下溢。
乘法的结果是两者的宽度相加,16bits * 16bits 结果为 32 位答案。很确定你不需要 33 位。如果您不保持全宽,则很难判断结果在截断时是否会溢出。用广泛的组合结果来设计这些东西并且只通过触发器输出这么多位以供 ALU 的最终输出是很常见的。
我认为保持 32 位输出并将其与有符号的 16 位数字的最大值/最小值进行比较,将比仅使用 16 位乘法器和额外的逻辑来检测溢出条件合成更小。
关于verilog - Verilog 中的有符号乘法溢出检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24586842/