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 end103 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 // Outputs10 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 begin24 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 end41 42 always #(CLK_PERIOD/2) clk = ~clk;43 44 always@(posedge clk)45 if(!rst_n)46 begin47 oper_data[15:8] = 0;48 oper_data[7:0] = 0;49 end50 else51 begin52 oper_data[15:8] = oper_data[15:8] + 1;53 oper_data[7:0] = oper_data[7:0] + 1;54 end55 56 endmodule
分析仿真结果,代码满足所需功能。
综合RTL图:
(xilinx的RTL图很底层,不太容易看懂)