初学者在这里.我正在尝试在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;
Run Code Online (Sandbox Code Playgroud)
这是减法:
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;
Run Code Online (Sandbox Code Playgroud)
控制矩阵负责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
Run Code Online (Sandbox Code Playgroud)
带负数
-3 : [1]1101
+ -3 : [1]1101
= -6 : [1]1010
Run Code Online (Sandbox Code Playgroud)
现在导致溢出:结果应为+8但不能以4位表示.
+7 : [0]0111
+1 : [0]0001
+8 : [0]1000
Run Code Online (Sandbox Code Playgroud)
现在导致下溢:结果应为-9但不能以4位表示.
-8 : [1]1000
+ -1 : [1]1111
-9 : [1]0111
Run Code Online (Sandbox Code Playgroud)
因此,如果我们将输入延长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
Run Code Online (Sandbox Code Playgroud)
关于乘法,我不明白为什么你不能有32位寄存器.即使你将最终输出减少到16.
执行位减少时,您需要检查该值是否低于最大值,并且可以使用减小的宽度支持最小负数.
注意:此外,结果比最大输入增加1位.截断到原始宽度时发生溢出/下溢.
通过乘法,结果是两者相加的宽度,16位*16位导致32位答案.很确定你不需要33位.如果你没有保持整个宽度,那么很难判断截断时结果是否会溢出.设计具有宽组合结果的这些东西并且仅通过触发器输出如此多的位以用于ALU的最终输出是很常见的.
我认为保持32位输出并将其与有符号16位数的最大值/最小值进行比较,将比仅使用16位乘法器和额外逻辑来检测溢出条件.