基于vivado使用verilog语言设计简单的32位ALU

在vivado上使用verilog语言设计32位ALU,包含16种不同的算数、逻辑、比较、移位运算。

32位ALU
  • 顶层设计
    • 输入:
      • n0 ,第一个数据输入,32比特
      • in1 ,第二个数据输入,32比特
      • op ,ALU计算类型码,11比特
    • 输出
      • out ,输出,32比特
      • overflow ,溢出标志,1比特
      • zero ,零标志,1比特
      • carryout ,进位标志,1比特
算数运算
运算OP编码具体含义
add00000100000有符号数加法
addu00000100001无符号数加法
sub00000100010有符号数减法
subu00000100011无符号数减法
逻辑运算
运算OP编码具体含义
and00000100100按位与
or00000100101按位或
xor00000100110异或
nor00000100111或非
比较运算
运算OP编码具体含义
slt00000101010slt $1,$2,$3 意为If($2<$3) $1=1 else $1=0;有符号数的比较
altu00000101011sltu $1,$2,$3 意为If($2<$3) $1=1 else $1=0;无符号数的比较
移位运算
运算OP编码具体含义
sll00000000000sll $1,$2,10 意为$1=$2<<10;左移10位
srl00000000010srl $1,$2,10 意为$1=$2>>10;右移10位
sra00000000011sra $1,$2,10 意为$1=$2>>10;注意符号位保留
sllv00000000100sllv $1,$2,$3 意为$1=$2<<$3
srlv00000000110srlv $1,$2,$3 意为$1=$2>>$3
srav00000000111srav $1,$2,$3 意为$1=$2>>$3;注意符号位的保留
设计代码
module alu_32(
 reset, in0, in1, op, out, overflow, zero, carryout
    );
    input reset;               //reset用于初始化置零
    input[31:0] in0,in1;       //操作对象
    input[10:0] op;            //操作码
    output[31:0] out;         
    output overflow,zero,carryout;
    reg[31:0] out;
    reg overflow,zero,carryout;
always@(*)              
begin
     if(reset)           //初始化
         begin
          out=0;
          overflow=0;
          zero=0;
          carryout=0;
         end
     else
         alutask( in0, in1, op, out, overflow, zero, carryout);      //把具体功能模块封装成一个任务
end
task alutask;                  //任务定义
   input[31:0] in0,in1;       
   input[10:0] op;           
   output[31:0] out;         
   output overflow,zero,carryout;
   reg[31:0] out;
   reg overflow,zero,carryout;
begin
            overflow=0;            //每次进行不同的运算的时候,标志位需要置0
            carryout=0;
            case( op )
            11'b00000100000: 
                            begin
                            out=$signed(in0)+$signed(in1);                               //$signed是强制转换,把无符号数转为有符号数
                            overflow=in0[31]&in1[31] ^ in0[30]&in1[30];         //有符号数的溢出是通过overflow,判断条件为--最高位进位状态^次高位进位状态=1,则溢出。具体可百度。
                            end
            11'b00000100001: 
                            begin               //增加了判断语句,如果操作对象不是无符号数,则结果输出为不确定的值,下同
                            if(in0[31]==1||in1[31]==1)
                            out=32'bx;
                            else
                            {carryout,out}=$unsigned(in0)+$unsigned(in1);                             //无符号数的溢出通过进借位判断,这里使用用连接符{},使得将carryout作为最高位与out连接在一起            
                            end
            11'b00000100010:
                             begin
                             out=$signed(in0)-$signed(in1);
                             overflow=in0[31]&in1[31] ^ in0[30]&in1[30];
                             end
            11'b00000100011: 
                             begin
                             if(in0[31]==1||in1[31]==1)
                             out=32'bx;
                             else
                             {carryout,out}=$unsigned(in0)-$unsigned(in1);
                             end
            11'b00000100100: out=in0&in1;
            11'b00000100101: out=in0|in1;
            11'b00000100110: out=in0^in1;
            11'b00000100111: out=~(in0|in1);
            11'b00000101010: out=( $signed(in0)<$signed(in1) )? 1:0;
            11'b00000101011: out=(in0<in1)? 1:0;
            11'b00000000000: out=in0<<10;
            11'b00000000010: out=in0>>10;
            11'b00000000011: out=in0>>>10;
            11'b00000000100: out=in0<<in1;
            11'b00000000110: out=in0>>in1;
            11'b00000000111: out=in0>>>in1;
            endcase
            zero=out==0;          //zero通过直接判断out是否为0
end
endtask
endmodule
仿真文件
module addtest;
reg reset;           
reg [31:0] in0,in1;      
reg[10:0] op;            
wire[31:0] out;         
wire overflow,zero,carryout;

alu_32 unit(            //模块实例化
    .reset(reset),
    .in0(in0),
    .in1(in1),
    .op(op),
    .out(out),
    .overflow(overflow),
    .zero(zero),
    .carryout(carryout)
);
initial
begin
    #10 reset=1;
    #10 reset=0;in0=32'd1; in1=32'd2;        //对操作对象都是正数进行仿真,相当于对无符号数验证,且作为有符号数参与运算是没有问题的
    for(op=11'b00000100000;op<11'b00000100111;op=op+1)
    #20;
    #20 op=11'b00000101010;
    #20 op=11'b00000101011;
    #20 op=11'b00000000000;
    #20 op=11'b00000000010;
    #20 op=11'b00000000011;
    #20 op=11'b00000000100;
    #20 op=11'b00000000110;
    #20 op=11'b00000000111;
    
    #10 reset=1;
    #10 reset=0;in0=-32'd1; in1=32'd2;            //对有负数的情况进行仿真,也就是有符号数的情况
    for(op=11'b00000100000;op<11'b00000100111;op=op+1)
    #20;
    #20 op=11'b00000101010;
    #20 op=11'b00000101011;
    #20 op=11'b00000000000;
    #20 op=11'b00000000010;
    #20 op=11'b00000000011;
    #20 op=11'b00000000100;
    #20 op=11'b00000000110;
    #20 op=11'b00000000111;
    
    #100 $finish;
end
initial
$monitor ($time,,,"reset=%b in0=%b in1=%b op=%b out=%b overflow=%b zero=%b carryout=%b ",
reset,in0,in1,op,out,overflow,zero,carryout);
endmodule
电路图

电路图

仿真波形图

在这里插入图片描述

附上monitor监视器的监视结果(monitor语句)

在这里插入图片描述
扩展:由于vivado自带的加法器非常简单,如果直接使用该加法器的话,会造成加法结果延迟时间较长,因此可以考虑使用自己写的32位超前进位加法器,但是在组织上会复杂一些。
关于有无符号数溢出问题可以参见:有无符号数溢出判断

另:欢迎大家对博客内容批评指正。

  • 41
    点赞
  • 279
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值