【问题标题】:Implementing one-bit flags in a 32Bit ALU using Verilog使用 Verilog 在 32 位 ALU 中实现一位标志
【发布时间】:2015-12-06 00:35:35
【问题描述】:

我正在处理一项任务,有点迷茫,不知道如何开始。我需要在 32 位 ALU 中实现以下标志:

• Z(“零”):如果运算结果为零,则设置为 1(“真”)

• N ("Negative"):如果结果的第一位为1,则设置为1("True"),表示为负数

• O ("Overflow"):设置为 1 ("True") 表示操作溢出了总线宽度。

另外,一个比较函数,将输入 a 与输入 b 进行比较,然后设置三个标志之一:

• 如果输入 a 小于输入 b 则 LT

• 如果输入 a 大于输入 b,则 GT

• 输入 a 等于输入 b 的 EQ

我需要修改此 ALU 以包含三个标志和比较输出,然后更改测试台以测试所有这些修改。

这是我收到的关于这项作业的所有信息,实际上没有教科书或任何其他资源。这是一个在线课程,我无法得到老师的回应。所以我对如何开始有点困惑。在数字逻辑方面,我仍然是个新手,所以请多多包涵。我只需要一些帮助来理解这些标志和比较是如何工作的。如果有人能更好地向我解释它们是如何工作的,它们做了什么,以及我如何将它们实现到 ALU 和测试平台中,我将不胜感激。

我不希望任何人完成我的任务,我真的只需要帮助理解它。

ALU

module alu32 (a, b, out, sel);      
    input [31:0] a, b;    
    input [3:0] sel;   
    output [31:0] out,
    reg [31:0] out;  

    //Code starts here 
    always @(a, b, sel)   
    begin     
        case (sel)       
            //Arithmetic Functions       
            0  : out <= a + b;       
            1  : out <= a - b;       
            2  : out <= b - a;       
            3  : out <= a * b;       
            4  : out <= a / b;       
            5  : out <= b % a;       
            //Bit-wise Logic Functions       
            6  : out <= ~a; //Not       
            7  : out <= a & b; //And       
            8  : out <= a | b; //Or       
            9  : out <= a ^ b; //XOR       
            10 : out <= a ^~ b; //XNOR       
            //Logic Functions       
            11 : out <= !a;       
            12 : out <= a && b;       
            13 : out <= a || b;       
            default: out <= a + b;     
        endcase
    end  
endmodule 

ALU 测试台

module alu32_tb();  
    reg [31:0] a, b; 
    reg [3:0] sel; 
    wire [31:0] out; 

initial begin

$monitor("sel=%d a=%d b=%d out=%d", sel,a,b,out);   
    //Fundamental tests - all a+b   
    #0 sel=4'd0; a = 8'd0; b = 8'd0;    
    #1 sel=4'd0; a = 8'd0; b = 8'd25;   
    #1 sel=4'd0; a = 8'd37; b = 8'd0;   
    #1 sel=4'd0; a = 8'd45; b = 8'd75;  
    //Arithmetic   
    #1 sel=4'd1; a = 8'd120; b = 8'd25; //a-b   
    #1 sel=4'd2; a = 8'd30; b = 8'd120; //b-a   
    #1 sel=4'd3; a = 8'd75; b = 8'd3; //a*b   
    #1 sel=4'd4; a = 8'd75; b = 8'd3; //a/b   
    #1 sel=4'd5; a = 8'd74; b = 8'd3; //a%b  
    //Bit-wise Logic Functions   
    #1 sel=4'd6; a = 8'd31; //Not   
    #1 sel=4'd7; a = 8'd31; b = 8'd31; //And   
    #1 sel=4'd8; a = 8'd30; b = 8'd1; //Or   
    #1 sel=4'd9; a = 8'd30; b = 8'd1; //XOR   
    #1 sel=4'd10; a = 8'd30; b = 8'd1; //XNOR  
    //Logic Functions   
    #1 sel=4'd11; a = 8'd25; //Not   
    #1 sel=4'd12; a = 8'd30; b = 8'd0; //And   
    #1 sel=4'd13; a = 8'd0; b = 8'd30; //Or      
    #1 $finish; 
end  

alu32 myalu (.a(a), .b(b), .out(out), .sel(sel));  
endmodule  

【问题讨论】:

  • 我认为,您可以从添加一个或两个标志作为附加 alu32 参数(它们是输入、输出还是输入+输出?)开始,然后为一两个 alu 函数实现标志。例如,a+b 的零标志可以定义为逻辑函数 (a+b) == 0 的结果;如果 ab 大于 2^32... 将设置乘法 (ab) 的溢出标志
  • 给我们的指令并没有具体说明是输入、输出还是输入+输出。几天前,我给我的导师发了一封电子邮件,询问更多信息,但没有收到回复。我们没有得到关于这项任务的太多信息。不过感谢您的回复,这确实有帮助。我将首先在参数中添加一个零标志,看看我是否可以将它实现到其中一个函数中。然后转到溢出标志。
  • 邋遢的 Nerfherder,你知道标志的概念吗*(例如 en.wikibooks.org/wiki/Microprocessor_Design/ALU_Flagsen.wikipedia.org/wiki/Zero_flag)?通常它们由大多数算术运算设置;有时它们可​​能用于执行分支,或用于一些非常特殊的命令,如“带进位相加”(x86 adc)。所以,如果你没有“add with carry”,标志应该是......?
  • 据我所知,它们应该是输出......

标签: verilog digital-logic alu iverilog status-register


【解决方案1】:

您可以将这些标志输出添加到设计。像下面这样。只需在测试台中连接它们。

// In design:
output zero;
output overflow;
output negative;

// In testbench:
wire zero,overflow,negative;
alu32 myalu (.a(a), .b(b), .out(out), .sel(sel), .zero(zero), .overflow(overflow),.negative(negative));  

对于逻辑部分,您可以使用连续分配。您可能需要添加一些逻辑,以便仅在sel 的某些值期间使用这些标志。

Z("Zero"):如果运算结果为零,则设置为 1("True")

所以,我们可以有像 all 这样的条件,out 的位必须是 zero。这可以通过许多其他方式完成。

// Bit wise OR-ing on out
assign zero = ~(|out);

O(“溢出”):设置为1(“真”)表示操作溢出总线宽度。

根据这个描述和显示的代码,你这里只需要carry flag。也就是一个signed extension加法操作。溢出条件参考this page on WikiPedia

但是,溢出条件进位相同。溢出代表数据丢失,进位代表有点用于下一阶段的计算。

因此,执行以下操作可能会有所帮助:

// Extend the result for capturing carry bit
// Simply use this bit if you want result > bus width
{carry,out} <= a+b;
// overflow in signed arithmetic:
assign overflow = ({carry,out[31]} == 2'b01);

N("Negative"):如果结果的第一位为1,则设置为1("True"),表示为负数

这只是out 寄存器的MSB。但是,下溢条件完全是一个不同的东西。

// Depending on sel, subtraction must be performed here
assign negative = (out[31] == 1 && (sel == 1 || sel == 2));

此外,assign lt = (a&lt;b) ? 1 : 0; 等简单条件可以检测输入 LT、GT 和 EQ 条件。

请参阅the answer here 了解上溢/下溢标志Overflow-Carry 链接也可能有用。

有关 ALU 实施的更多信息,请参阅 Carryout-OverflowALU in VerilogALU PDF

【讨论】:

  • 好的,非常感谢!这绝对是一个巨大的帮助。但是,至于您列出的溢出标志 {carry,out} &lt;= a+b;assign overflow = ({carry,out[31]} == 2'b01); 那么我还需要添加一个 carry 属性吗?那会是输入/输出吗?
  • 这将是一个输出,一位。例如:在两位机器上将2'b10 与另一个2'b10 相加,结果为3'b100,其中,MSB 1 为进位位,其余00 显示为和位。因此,将输出进位位声明为output carry; reg carry;。将在测试台中进行相应的连接。
  • sharvil111,在乘法运算中检测溢出的基本方法是什么?我认为带有 32 位 a 和 b 的 verilog a*b 只会给出 32 位结果,对吗?
  • @osgx 只是猜测乘法。当a*b32位执行时,最大结果为64位。因此,结果必须存储在一个 64 位宽的变量中并加上一个 sign 位,从而产生 65 位 的最终结果。参考答案here,如果不使用那么宽的寄存器,则很难检测到溢出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-24
相关资源
最近更新 更多