简单ALU(算术逻辑单元)的verilog实现

2013-06-14 21:39:56

简单ALU(算术逻辑单元)的verilog实现,可实现两数相加、相减,或一个数的加1、减1操作。

小结:

  • 要学会看RTL图,能够根据RTL图大致判断功能的正确性

代码:

  1 module alu_add_sub(
  2                         rst_n,
  3                         clk,
  4                         oper_cmd,
  5                         oper_data,
  6                         dout
  7                              );
  8                              
  9 parameter DATA_SIZE = 4'd8;    //操作数宽度                         
 10 
 11 input rst_n;
 12 input clk;
 13 
 14 input [1:0] oper_cmd;
 15 input [2*DATA_SIZE - 1:0] oper_data;
 16 
 17 output [DATA_SIZE:0] dout;
 18 
 19 reg [1:0] oper_cmd_r;
 20 reg [2*DATA_SIZE - 1:0] oper_data_r;
 21 
 22 wire  [2*DATA_SIZE:0] add_sub_oper;
 23 
 24 reg [DATA_SIZE:0] dout_tmp;
 25 reg [DATA_SIZE:0] dout;
 26 
 27 //输入数据打一拍
 28 always@(posedge clk)
 29     if(!rst_n)
 30         begin
 31             oper_cmd_r <= 8'd0;
 32             oper_data_r <= 16'd0;
 33         end
 34     else
 35         begin
 36             oper_cmd_r <= oper_cmd;
 37             oper_data_r <= oper_data;
 38         end    
 39 
 40 //根据输入数据,求操作码,相当于指令译码
 41 assign add_sub_oper = add_sub_func(oper_cmd_r,oper_data_r);
 42 
 43 //根据译码结果,求输出
 44 always@(posedge clk)
 45 if(!rst_n)
 46     begin
 47         dout_tmp <= 9'd0;
 48     end
 49 else
 50     begin
 51         if(add_sub_oper[2*DATA_SIZE])
 52             dout_tmp <= add_sub_oper[2*DATA_SIZE-1 : DATA_SIZE] + add_sub_oper[DATA_SIZE-1 : 0];
 53         else
 54             dout_tmp <= add_sub_oper[2*DATA_SIZE-1 : DATA_SIZE] - add_sub_oper[DATA_SIZE-1 : 0];
 55     end
 56 
 57 //输出数据打一拍
 58 always@(posedge clk)
 59     if(!rst_n)
 60             dout <= 9'd0;
 61     else
 62         dout <= dout_tmp;
 63 
 64 //指令译码函数
 65 function [2*DATA_SIZE:0] add_sub_func;  //关键字function标志函数开始
 66     input [1:0] oper_cmd;
 67     input [2*DATA_SIZE - 1:0] oper_data;
 68 
 69     reg [1:0] mode;
 70     reg [DATA_SIZE - 1:0] oper1;
 71     reg [DATA_SIZE - 1:0] oper2;
 72 
 73     //always@(oper_cmd or oper_data)
 74     begin     //函数体须在过程块中
 75         case(oper_cmd)
 76             2'b00 :         //两数相加
 77                 begin
 78                     mode = 1;
 79                     oper1 = oper_data[2*DATA_SIZE - 1:DATA_SIZE];
 80                     oper2 = oper_data[DATA_SIZE - 1:0];
 81                 end
 82             2'b01 :     //加1
 83                 begin
 84                     mode = 1;
 85                     oper1 = oper_data[2*DATA_SIZE - 1:DATA_SIZE];
 86                     oper2 = 1'b1;
 87                 end
 88             2'b10 :         //两数相减
 89                 begin
 90                     mode = 0;
 91                     oper1 = oper_data[2*DATA_SIZE - 1:DATA_SIZE];
 92                     oper2 = oper_data[DATA_SIZE - 1:0];
 93                 end
 94             default :     //减1
 95                 begin
 96                     mode = 0;
 97                     oper1 = oper_data[2*DATA_SIZE - 1:DATA_SIZE];
 98                     oper2 = 1'b1;
 99                 end    
100         endcase    
101         add_sub_func = {mode,oper1,oper2};
102     end
103 
104 endfunction  //关键字endfunction标志函数结束
105 
106 endmodule

testbench:

 1 module alu_add_sub_tb;
 2 
 3     // Inputs
 4     reg rst_n;
 5     reg clk;
 6     reg [1:0] oper_cmd;
 7     reg [15:0] oper_data;
 8 
 9     // Outputs
10     wire [8:0] dout;
11 
12     // Instantiate the Unit Under Test (UUT)
13     alu_add_sub uut (
14         .rst_n(rst_n), 
15         .clk(clk), 
16         .oper_cmd(oper_cmd), 
17         .oper_data(oper_data), 
18         .dout(dout)
19     );
20     
21     parameter CLK_PERIOD = 10;
22 
23     initial begin
24         rst_n = 0;
25         clk = 1;
26         oper_cmd = 0;
27         //oper_data = 0;
28 
29         #100;
30         rst_n = 1;
31         
32         # (10*CLK_PERIOD) oper_cmd = 2'b00;  //两数相加测试
33         
34         # (10*CLK_PERIOD) oper_cmd = 2'b01;     //加1测试
35         
36         # (10*CLK_PERIOD) oper_cmd = 2'b10;     //两数相减测试
37         
38             # (10*CLK_PERIOD) oper_cmd = 2'b11;    //减1测试
39  
40     end
41     
42     always #(CLK_PERIOD/2) clk = ~clk;
43     
44     always@(posedge clk)
45     if(!rst_n)
46         begin
47             oper_data[15:8] = 0;
48             oper_data[7:0] = 0;
49         end
50     else
51         begin
52             oper_data[15:8] = oper_data[15:8] + 1;
53             oper_data[7:0] = oper_data[7:0] + 1;
54         end
55       
56 endmodule

分析仿真结果,代码满足所需功能。

综合RTL图:

(xilinx的RTL图很底层,不太容易看懂)

原文地址:https://www.cnblogs.com/youngforever/p/3136800.html