简单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图很底层,不太容易看懂)