Verilog生活-简单的ALU实现

1. 实验目的

  1. 熟悉MIPS指令集中的运算指令,学会对这些指令进行归纳分类。

  2. 了解MIPS指令结构。

  3. 熟悉并掌握ALU的原理、功能和设计。

  4. 进一步加强运用verilog语言进行电路设计的能力。

  5. 为后续设计cpu的实验打下基础。

2. 实验内容说明

  1. 原有的操作码为12位,请压缩到操作码控制型号位宽为4位。

  2. 在操作码调整到4位之后,应该能支持15种不同运算,请添加至少三种运算功能(有符号数比较和无符号数比较的大于置位运算、一种未实现的位运算),然后上实验箱验证(可以不用仿真)。

  3. 实验报告中的原理图就用图5.3即可,不再是顶层模块图。

3. 实验原理图

实验设计

控制信号ALU操作
11109876543210
000000000000
100000000000加法
010000000000减法
001000000000有符号比较,小于置位
000100000000无符号比较,小于置位
000010000000按位与
000001000000按位或非
000000100000按位或
000000010000按位异或
000000001000逻辑左移
000000000100逻辑右移
000000000010算术右移
000000000001高位加载

4. 源代码

alu.v

 `timescale 1ns / 1ps
 ​
 module alu(
     input  [11:0] alu_control,  // ALU控制信号
     input  [31:0] alu_src1,     // ALU操作数1,为补码
     input  [31:0] alu_src2,     // ALU操作数2,为补码
     output [31:0] alu_result    // ALU结果
     );
 ​
     // ALU控制信号,独热码
     wire alu_add;   //加法操作
     wire alu_sub;   //减法操作
     wire alu_slt;   //有符号比较,小于置位,复用加法器做减法
     wire alu_sltu;  //无符号比较,小于置位,复用加法器做减法
     wire alu_and;   //按位与
     wire alu_nor;   //按位或非
     wire alu_or;    //按位或
     wire alu_xor;   //按位异或
     wire alu_sll;   //逻辑左移
     wire alu_srl;   //逻辑右移
     wire alu_sra;   //算术右移
     wire alu_lui;   //高位加载
 ​
     assign alu_add  = alu_control[11];
     assign alu_sub  = alu_control[10];
     assign alu_slt  = alu_control[ 9];
     assign alu_sltu = alu_control[ 8];
     assign alu_and  = alu_control[ 7];
     assign alu_nor  = alu_control[ 6];
     assign alu_or   = alu_control[ 5];
     assign alu_xor  = alu_control[ 4];
     assign alu_sll  = alu_control[ 3];
     assign alu_srl  = alu_control[ 2];
     assign alu_sra  = alu_control[ 1];
     assign alu_lui  = alu_control[ 0];
 ​
     wire [31:0] add_sub_result;
     wire [31:0] slt_result;
     wire [31:0] sltu_result;
     wire [31:0] and_result;
     wire [31:0] nor_result;
     wire [31:0] or_result;
     wire [31:0] xor_result;
     wire [31:0] sll_result;
     wire [31:0] srl_result;
     wire [31:0] sra_result;
     wire [31:0] lui_result;
 ​
     assign and_result = alu_src1 & alu_src2;      // 与结果为两数按位与
     assign or_result  = alu_src1 | alu_src2;      // 或结果为两数按位或
     assign nor_result = ~or_result;               // 或非结果为或结果按位取反
     assign xor_result = alu_src1 ^ alu_src2;      // 异或结果为两数按位异或
     assign lui_result = {alu_src2[15:0], 16'd0};  // 立即数装载结果为立即数移位至高半字节
 ​
 //-----{加法器}begin
 //add,sub,slt,sltu均使用该模块
     wire [31:0] adder_operand1;
     wire [31:0] adder_operand2;
     wire        adder_cin     ;
     wire [31:0] adder_result  ;
     wire        adder_cout    ;
     assign adder_operand1 = alu_src1; 
     assign adder_operand2 = alu_add ? alu_src2 : ~alu_src2; 
     assign adder_cin      = ~alu_add; //减法需要cin 
     adder adder_module(
     .operand1(adder_operand1),
     .operand2(adder_operand2),
     .cin     (adder_cin     ),
     .result  (adder_result  ),
     .cout    (adder_cout    )
     );
 ​
     //加减结果
     assign add_sub_result = adder_result;
 ​
     //slt结果
     //adder_src1[31] adder_src2[31] adder_result[31]
     //       0             1           X(0或1)       "正-负",显然小于不成立
     //       0             0             1           相减为负,说明小于
     //       0             0             0           相减为正,说明不小于
     //       1             1             1           相减为负,说明小于
     //       1             1             0           相减为正,说明不小于
     //       1             0           X(0或1)       "负-正",显然小于成立
     assign slt_result[31:1] = 31'd0;
     assign slt_result[0]    = (alu_src1[31] & ~alu_src2[31]) | (~(alu_src1[31]^alu_src2[31]) & adder_result[31]);
 ​
     //sltu结果
     //对于32位无符号数比较,相当于33位有符号数({1'b0,src1}和{1'b0,src2})的比较,最高位0为符号位
     //故,可以用33位加法器来比较大小,需要对{1'b0,src2}取反,即需要{1'b0,src1}+{1'b1,~src2}+cin
     //但此处用的为32位加法器,只做了运算:                             src1   +    ~src2   +cin
     //32位加法的结果为{adder_cout,adder_result},则33位加法结果应该为{adder_cout+1'b1,adder_result}
     //对比slt结果注释,知道,此时判断大小属于第二三种情况,即源操作数1符号位为0,源操作数2符号位为0
     //结果的符号位为1,说明小于,即adder_cout+1'b1为2'b01,即adder_cout为0
     assign sltu_result = {31'd0, ~adder_cout};
 //-----{加法器}end
 ​
 //-----{移位器}begin
     // 移位分三步进行,
     // 第一步根据移位量低2位即[1:0]位做第一次移位,
     // 第二步在第一次移位基础上根据移位量[3:2]位做第二次移位,
     // 第三步在第二次移位基础上根据移位量[4]位做第三次移位。
     wire [4:0] shf;
     assign shf = alu_src1[4:0];
     wire [1:0] shf_1_0;
     wire [1:0] shf_3_2;
     assign shf_1_0 = shf[1:0];
     assign shf_3_2 = shf[3:2];
     
      // 逻辑左移
     wire [31:0] sll_step1;
     wire [31:0] sll_step2;
     assign sll_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                   // 若shf[1:0]="00",不移位
                      | {32{shf_1_0 == 2'b01}} & {alu_src2[30:0], 1'd0}     // 若shf[1:0]="01",左移1位
                      | {32{shf_1_0 == 2'b10}} & {alu_src2[29:0], 2'd0}     // 若shf[1:0]="10",左移2位
                      | {32{shf_1_0 == 2'b11}} & {alu_src2[28:0], 3'd0};    // 若shf[1:0]="11",左移3位
     assign sll_step2 = {32{shf_3_2 == 2'b00}} & sll_step1                  // 若shf[3:2]="00",不移位
                      | {32{shf_3_2 == 2'b01}} & {sll_step1[27:0], 4'd0}    // 若shf[3:2]="01",第一次移位结果左移4位
                      | {32{shf_3_2 == 2'b10}} & {sll_step1[23:0], 8'd0}    // 若shf[3:2]="10",第一次移位结果左移8位
                      | {32{shf_3_2 == 2'b11}} & {sll_step1[19:0], 12'd0};  // 若shf[3:2]="11",第一次移位结果左移12位
     assign sll_result = shf[4] ? {sll_step2[15:0], 16'd0} : sll_step2;     // 若shf[4]="1",第二次移位结果左移16位
 ​
     // 逻辑右移
     wire [31:0] srl_step1;
     wire [31:0] srl_step2;
     assign srl_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                   // 若shf[1:0]="00",不移位
                      | {32{shf_1_0 == 2'b01}} & {1'd0, alu_src2[31:1]}     // 若shf[1:0]="01",右移1位,高位补0
                      | {32{shf_1_0 == 2'b10}} & {2'd0, alu_src2[31:2]}     // 若shf[1:0]="10",右移2位,高位补0
                      | {32{shf_1_0 == 2'b11}} & {3'd0, alu_src2[31:3]};    // 若shf[1:0]="11",右移3位,高位补0
     assign srl_step2 = {32{shf_3_2 == 2'b00}} & srl_step1                  // 若shf[3:2]="00",不移位
                      | {32{shf_3_2 == 2'b01}} & {4'd0, srl_step1[31:4]}    // 若shf[3:2]="01",第一次移位结果右移4位,高位补0
                      | {32{shf_3_2 == 2'b10}} & {8'd0, srl_step1[31:8]}    // 若shf[3:2]="10",第一次移位结果右移8位,高位补0
                      | {32{shf_3_2 == 2'b11}} & {12'd0, srl_step1[31:12]}; // 若shf[3:2]="11",第一次移位结果右移12位,高位补0
     assign srl_result = shf[4] ? {16'd0, srl_step2[31:16]} : srl_step2;    // 若shf[4]="1",第二次移位结果右移16位,高位补0
  
     // 算术右移
     wire [31:0] sra_step1;
     wire [31:0] sra_step2;
     assign sra_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                                 // 若shf[1:0]="00",不移位
                      | {32{shf_1_0 == 2'b01}} & {alu_src2[31], alu_src2[31:1]}           // 若shf[1:0]="01",右移1位,高位补符号位
                      | {32{shf_1_0 == 2'b10}} & {{2{alu_src2[31]}}, alu_src2[31:2]}      // 若shf[1:0]="10",右移2位,高位补符号位
                      | {32{shf_1_0 == 2'b11}} & {{3{alu_src2[31]}}, alu_src2[31:3]};     // 若shf[1:0]="11",右移3位,高位补符号位
     assign sra_step2 = {32{shf_3_2 == 2'b00}} & sra_step1                                // 若shf[3:2]="00",不移位
                      | {32{shf_3_2 == 2'b01}} & {{4{sra_step1[31]}}, sra_step1[31:4]}    // 若shf[3:2]="01",第一次移位结果右移4位,高位补符号位
                      | {32{shf_3_2 == 2'b10}} & {{8{sra_step1[31]}}, sra_step1[31:8]}    // 若shf[3:2]="10",第一次移位结果右移8位,高位补符号位
                      | {32{shf_3_2 == 2'b11}} & {{12{sra_step1[31]}}, sra_step1[31:12]}; // 若shf[3:2]="11",第一次移位结果右移12位,高位补符号位
     assign sra_result = shf[4] ? {{16{sra_step2[31]}}, sra_step2[31:16]} : sra_step2;    // 若shf[4]="1",第二次移位结果右移16位,高位补符号位
 //-----{移位器}end
 ​
     // 选择相应结果输出
     assign alu_result = (alu_add|alu_sub) ? add_sub_result[31:0] : 
                         alu_slt           ? slt_result :
                         alu_sltu          ? sltu_result :
                         alu_and           ? and_result :
                         alu_nor           ? nor_result :
                         alu_or            ? or_result  :
                         alu_xor           ? xor_result :
                         alu_sll           ? sll_result :
                         alu_srl           ? srl_result :
                         alu_sra           ? sra_result :
                         alu_lui           ? lui_result :
                         32'd0;
 endmodule
 ​

alu_display.v

 module alu_display(
     //时钟与复位信号
      input clk,
     input resetn,    //后缀"n"代表低电平有效
 ​
     //拨码开关,用于选择输入数
     input [1:0] input_sel, //00:输入为控制信号(alu_control)
                            //10:输入为源操作数1(alu_src1)
                            //11:输入为源操作数2(alu_src2)
 ​
     //触摸屏相关接口,不需要更改
     output lcd_rst,
     output lcd_cs,
     output lcd_rs,
     output lcd_wr,
     output lcd_rd,
     inout[15:0] lcd_data_io,
     output lcd_bl_ctr,
     inout ct_int,
     inout ct_sda,
     output ct_scl,
     output ct_rstn
     );
 //-----{调用ALU模块}begin
     reg   [11:0] alu_control;  // ALU控制信号
     reg   [31:0] alu_src1;     // ALU操作数1
     reg   [31:0] alu_src2;     // ALU操作数2
     wire  [31:0] alu_result;   // ALU结果
     alu alu_module(
         .alu_control(alu_control),
         .alu_src1   (alu_src1   ),
         .alu_src2   (alu_src2   ),
         .alu_result (alu_result )
     );
 //-----{调用ALU模块}end
 ​
 //---------------------{调用触摸屏模块}begin--------------------//
 //-----{实例化触摸屏}begin
 //此小节不需要更改
     reg         display_valid;
     reg  [39:0] display_name;
     reg  [31:0] display_value;
     wire [5 :0] display_number;
     wire        input_valid;
     wire [31:0] input_value;
 ​
     lcd_module lcd_module(
         .clk            (clk           ),   //10Mhz
         .resetn         (resetn        ),
 ​
         //调用触摸屏的接口
         .display_valid  (display_valid ),
         .display_name   (display_name  ),
         .display_value  (display_value ),
         .display_number (display_number),
         .input_valid    (input_valid   ),
         .input_value    (input_value   ),
 ​
         //lcd触摸屏相关接口,不需要更改
         .lcd_rst        (lcd_rst       ),
         .lcd_cs         (lcd_cs        ),
         .lcd_rs         (lcd_rs        ),
         .lcd_wr         (lcd_wr        ),
         .lcd_rd         (lcd_rd        ),
         .lcd_data_io    (lcd_data_io   ),
         .lcd_bl_ctr     (lcd_bl_ctr    ),
         .ct_int         (ct_int        ),
         .ct_sda         (ct_sda        ),
         .ct_scl         (ct_scl        ),
         .ct_rstn        (ct_rstn       )
     ); 
 //-----{实例化触摸屏}end
 ​
 //-----{从触摸屏获取输入}begin
 //根据实际需要输入的数修改此小节,
 //建议对每一个数的输入,编写单独一个always块
     //当input_sel为00时,表示输入数控制信号,即alu_control
     always @(posedge clk)
     begin
         if (!resetn)
         begin
             alu_control <= 12'd0;
         end
         else if (input_valid && input_sel==2'b00)
         begin
             alu_control <= input_value[11:0];
         end
     end
     
     //当input_sel为10时,表示输入数为源操作数1,即alu_src1
     always @(posedge clk)
     begin
         if (!resetn)
         begin
             alu_src1 <= 32'd0;
         end
         else if (input_valid && input_sel==2'b10)
         begin
             alu_src1 <= input_value;
         end
     end
 ​
     //当input_sel为11时,表示输入数为源操作数2,即alu_src2
     always @(posedge clk)
     begin
         if (!resetn)
         begin
             alu_src2 <= 32'd0;
         end
         else if (input_valid && input_sel==2'b11)
         begin
             alu_src2 <= input_value;
         end
     end
 //-----{从触摸屏获取输入}end
 ​
 //-----{输出到触摸屏显示}begin
 //根据需要显示的数修改此小节,
 //触摸屏上共有44块显示区域,可显示44组32位数据
 //44块显示区域从1开始编号,编号为1~44,
     always @(posedge clk)
     begin
         case(display_number)
             6'd1 :
             begin
                 display_valid <= 1'b1;
                 display_name  <= "SRC_1";
                 display_value <= alu_src1;
             end
             6'd2 :
             begin
                 display_valid <= 1'b1;
                 display_name  <= "SRC_2";
                 display_value <= alu_src2;
             end
             6'd3 :
             begin
                 display_valid <= 1'b1;
                 display_name  <= "CONTR";
                 display_value <={20'd0, alu_control};
             end
             6'd4 :
             begin
                 display_valid <= 1'b1;
                 display_name  <= "RESUL";
                 display_value <= alu_result;
             end
             default :
             begin
                 display_valid <= 1'b0;
                 display_name  <= 40'd0;
                 display_value <= 32'd0;
             end
         endcase
     end
 //-----{输出到触摸屏显示}end
 //----------------------{调用触摸屏模块}end---------------------//
 endmodule
 ​

adder.v

 `timescale 1ns / 1ps
 ​
 module adder(
     input  [31:0] operand1,
     input  [31:0] operand2,
     input         cin,
     output [31:0] result,
     output        cout
     );
     assign {cout,result} = operand1 + operand2 + cin;
 ​
 endmodule
 ​

alu.xdc

 #时钟信号连接
 set_property PACKAGE_PIN AC19 [get_ports clk]
 ​
 #脉冲开关,用于输入作为复位信号,低电平有效
 set_property PACKAGE_PIN Y3 [get_ports resetn]
 ​
 #拨码开关连接,用于输入,依次为sw0,sw1
 set_property PACKAGE_PIN Y6   [get_ports input_sel[0]]
 set_property PACKAGE_PIN AD24 [get_ports input_sel[1]]
 ​
 set_property IOSTANDARD LVCMOS33 [get_ports clk]
 set_property IOSTANDARD LVCMOS33 [get_ports resetn]
 set_property IOSTANDARD LVCMOS33 [get_ports input_sel[1]]
 set_property IOSTANDARD LVCMOS33 [get_ports input_sel[0]]
 ​
 #触摸屏引脚连接
 set_property PACKAGE_PIN J25 [get_ports lcd_rst]
 set_property PACKAGE_PIN H18 [get_ports lcd_cs]
 set_property PACKAGE_PIN K16 [get_ports lcd_rs]
 set_property PACKAGE_PIN L8 [get_ports lcd_wr]
 set_property PACKAGE_PIN K8 [get_ports lcd_rd]
 set_property PACKAGE_PIN J15 [get_ports lcd_bl_ctr]
 set_property PACKAGE_PIN H9 [get_ports {lcd_data_io[0]}]
 set_property PACKAGE_PIN K17 [get_ports {lcd_data_io[1]}]
 set_property PACKAGE_PIN J20 [get_ports {lcd_data_io[2]}]
 set_property PACKAGE_PIN M17 [get_ports {lcd_data_io[3]}]
 set_property PACKAGE_PIN L17 [get_ports {lcd_data_io[4]}]
 set_property PACKAGE_PIN L18 [get_ports {lcd_data_io[5]}]
 set_property PACKAGE_PIN L15 [get_ports {lcd_data_io[6]}]
 set_property PACKAGE_PIN M15 [get_ports {lcd_data_io[7]}]
 set_property PACKAGE_PIN M16 [get_ports {lcd_data_io[8]}]
 set_property PACKAGE_PIN L14 [get_ports {lcd_data_io[9]}]
 set_property PACKAGE_PIN M14 [get_ports {lcd_data_io[10]}]
 set_property PACKAGE_PIN F22 [get_ports {lcd_data_io[11]}]
 set_property PACKAGE_PIN G22 [get_ports {lcd_data_io[12]}]
 set_property PACKAGE_PIN G21 [get_ports {lcd_data_io[13]}]
 set_property PACKAGE_PIN H24 [get_ports {lcd_data_io[14]}]
 set_property PACKAGE_PIN J16 [get_ports {lcd_data_io[15]}]
 set_property PACKAGE_PIN L19 [get_ports ct_int]
 set_property PACKAGE_PIN J24 [get_ports ct_sda]
 set_property PACKAGE_PIN H21 [get_ports ct_scl]
 set_property PACKAGE_PIN G24 [get_ports ct_rstn]
 ​
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_rst]
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_cs]
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_rs]
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_wr]
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_rd]
 set_property IOSTANDARD LVCMOS33 [get_ports lcd_bl_ctr]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[0]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[1]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[2]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[3]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[4]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[5]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[6]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[7]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[8]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[9]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[10]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[11]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[12]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[13]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[14]}]
 set_property IOSTANDARD LVCMOS33 [get_ports {lcd_data_io[15]}]
 set_property IOSTANDARD LVCMOS33 [get_ports ct_int]
 set_property IOSTANDARD LVCMOS33 [get_ports ct_sda]
 set_property IOSTANDARD LVCMOS33 [get_ports ct_scl]
 set_property IOSTANDARD LVCMOS33 [get_ports ct_rstn]
 ​

testbench.v

 `timescale 1ns / 1ps
 ​
 module alu_tb;
 ​
     // Inputs
     reg [3:0] alu_control;
     reg [31:0] alu_src1;
     reg [31:0] alu_src2;
 ​
     // Outputs
     wire [31:0] alu_result;
 ​
     // Instantiate the Unit Under Test (UUT)
     alu uut (
         .alu_control(alu_control),
         .alu_src1(alu_src1),
         .alu_src2(alu_src2),
         .alu_result(alu_result)
     );
 ​
     initial begin
         // Initialize Inputs
         alu_control = 0;
         alu_src1 = 0;
         alu_src2 = 0;
 ​
         // Wait 100 ns for global reset to finish
         #100;
         
         // Test Case 1: Addition
         $display("Test Case 1: Addition");
         alu_control = 4'b0001; // ADD
         alu_src1 = 32'h0000_0005;
         alu_src2 = 32'h0000_0007;
         #10;
         $display("5 + 7 = %h (Expected: 0xC)", alu_result);
         
         // Test Case 2: Subtraction
         $display("\nTest Case 2: Subtraction");
         alu_control = 4'b0010; // SUB
         alu_src1 = 32'h0000_0007;
         alu_src2 = 32'h0000_0005;
         #10;
         $display("7 - 5 = %h (Expected: 0x2)", alu_result);
         
         // Test Case 3: Signed comparison (slt)
         $display("\nTest Case 3: Signed comparison (slt)");
         alu_control = 4'b0011; // SLT
         // Case 3.1: 5 < 7
         alu_src1 = 32'h0000_0005;
         alu_src2 = 32'h0000_0007;
         #10;
         $display("5 < 7? %h (Expected: 0x1)", alu_result);
         // Case 3.2: -5 < 7 (signed)
         alu_src1 = 32'hFFFF_FFFB; // -5 in two's complement
         alu_src2 = 32'h0000_0007;
         #10;
         $display("-5 < 7? %h (Expected: 0x1)", alu_result);
         
         // Test Case 4: Unsigned comparison (sltu)
         $display("\nTest Case 4: Unsigned comparison (sltu)");
         alu_control = 4'b0100; // SLTU
         // Case 4.1: 5 < 7
         alu_src1 = 32'h0000_0005;
         alu_src2 = 32'h0000_0007;
         #10;
         $display("5 < 7? %h (Expected: 0x1)", alu_result);
         // Case 4.2: -5 < 7 (unsigned)
         alu_src1 = 32'hFFFF_FFFB; // Large unsigned number
         alu_src2 = 32'h0000_0007;
         #10;
         $display("0xFFFFFFFB < 7? %h (Expected: 0x0)", alu_result);
         
         // Test Case 5: Bitwise AND
         $display("\nTest Case 5: Bitwise AND");
         alu_control = 4'b0101; // AND
         alu_src1 = 32'h0000_00F0;
         alu_src2 = 32'h0000_00FF;
         #10;
         $display("0xF0 & 0xFF = %h (Expected: 0xF0)", alu_result);
         
         // Test Case 6: Bitwise NOR
         $display("\nTest Case 6: Bitwise NOR");
         alu_control = 4'b0110; // NOR
         alu_src1 = 32'h0000_00F0;
         alu_src2 = 32'h0000_00FF;
         #10;
         $display("0xF0 NOR 0xFF = %h (Expected: 0xFFFF_FF00)", alu_result);
         
         // Test Case 7: Bitwise OR
         $display("\nTest Case 7: Bitwise OR");
         alu_control = 4'b0111; // OR
         alu_src1 = 32'h0000_00F0;
         alu_src2 = 32'h0000_00FF;
         #10;
         $display("0xF0 | 0xFF = %h (Expected: 0xFF)", alu_result);
         
         // Test Case 8: Bitwise XOR
         $display("\nTest Case 8: Bitwise XOR");
         alu_control = 4'b1000; // XOR
         alu_src1 = 32'h0000_00F0;
         alu_src2 = 32'h0000_00FF;
         #10;
         $display("0xF0 ^ 0xFF = %h (Expected: 0x0F)", alu_result);
         
         // Test Case 9: Logical Shift Left
         $display("\nTest Case 9: Logical Shift Left");
         alu_control = 4'b1001; // SLL
         alu_src1 = 32'h0000_0004; // Shift amount
         alu_src2 = 32'h0000_000F; // Value to shift
         #10;
         $display("0xF << 4 = %h (Expected: 0xF0)", alu_result);
         
         // Test Case 10: Logical Shift Right
         $display("\nTest Case 10: Logical Shift Right");
         alu_control = 4'b1010; // SRL
         alu_src1 = 32'h0000_0004; // Shift amount
         alu_src2 = 32'h0000_00F0; // Value to shift
         #10;
         $display("0xF0 >> 4 = %h (Expected: 0x0F)", alu_result);
         
         // Test Case 11: Arithmetic Shift Right
         $display("\nTest Case 11: Arithmetic Shift Right");
         alu_control = 4'b1011; // SRA
         alu_src1 = 32'h0000_0004; // Shift amount
         // Case 11.1: Positive number
         alu_src2 = 32'h0000_00F0; 
         #10;
         $display("0xF0 >>> 4 = %h (Expected: 0x0F)", alu_result);
         // Case 11.2: Negative number
         alu_src2 = 32'hFFFF_FFF0; // -16 in two's complement
         #10;
         $display("0xFFFF_FFF0 >>> 4 = %h (Expected: 0xFFFF_FFFF)", alu_result);
         
         // Test Case 12: Load Upper Immediate (LUI)
         $display("\nTest Case 12: Load Upper Immediate (LUI)");
         alu_control = 4'b1100; // LUI
         alu_src2 = 32'h0000_1234; // Immediate value
         #10;
         $display("LUI 0x1234 = %h (Expected: 0x1234_0000)", alu_result);
         
         $display("\nAll test cases completed");
         
         // Test Case 13: Unsigned Greater Than (SGTU)
         $display("\nTest Case 13: Unsigned Greater Than (SGTU)");
         alu_control = 4'b1101; // SGTU
         // Case 13.1: 7 > 5
         alu_src1 = 32'h0000_0007;
         alu_src2 = 32'h0000_0005;
         #10;
         $display("7 > 5? %h (Expected: 0x1)", alu_result);
         // Case 13.2: -5 > 7 (unsigned)
         alu_src1 = 32'hFFFF_FFFB; // Large unsigned number
         alu_src2 = 32'h0000_0007;
         #10;
         $display("0xFFFFFFFB > 7? %h (Expected: 0x1)", alu_result);
 ​
         // Test Case 14: Signed Greater Than (SGT)
         $display("\nTest Case 14: Signed Greater Than (SGT)");
         alu_control = 4'b1110; // SGT
         // Case 14.1: 7 > 5
         alu_src1 = 32'h0000_0007;
         alu_src2 = 32'h0000_0005;
         #10;
         $display("7 > 5? %h (Expected: 0x1)", alu_result);
         // Case 14.2: -5 > 7 (signed)
         alu_src1 = 32'hFFFF_FFFB; // -5 in two's complement
         alu_src2 = 32'h0000_0007;
         #10;
         $display("-5 > 7? %h (Expected: 0x0)", alu_result);
 ​
         // Test Case 15: Logical NOT
         $display("\nTest Case 15: Logical NOT");
         alu_control = 4'b1111; // NOT
         alu_src2 = 32'h0000_00FF;
         #10;
         $display("~0xFF = %h (Expected: 0xFFFF_FF00)", alu_result);
         $finish;
     end
 endmodule

5. 修改后代码

 `timescale 1ns / 1ps
 ​
 module alu(
     input  [3:0] alu_control,  // ALU控制信号,修改为4位
     input  [31:0] alu_src1,     // ALU操作数1,为补码
     input  [31:0] alu_src2,     // ALU操作数2,为补码
     output [31:0] alu_result    // ALU结果
 );
 ​
     // 解码4位控制信号
     wire alu_add  = (alu_control == 4'b0001);  // 加法
     wire alu_sub  = (alu_control == 4'b0010);  // 减法
     wire alu_slt  = (alu_control == 4'b0011);  // 有符号小于
     wire alu_sltu = (alu_control == 4'b0100);  // 无符号小于
     wire alu_and  = (alu_control == 4'b0101);  // 按位与
     wire alu_nor  = (alu_control == 4'b0110);  // 按位或非
     wire alu_or   = (alu_control == 4'b0111);  // 按位或
     wire alu_xor  = (alu_control == 4'b1000);  // 按位异或
     wire alu_sll  = (alu_control == 4'b1001);  // 逻辑左移
     wire alu_srl  = (alu_control == 4'b1010);  // 逻辑右移
     wire alu_sra  = (alu_control == 4'b1011);  // 算术右移
     wire alu_lui  = (alu_control == 4'b1100);  // 高位加载
     wire alu_sgtu = (alu_control == 4'b1101);  // 无符号大于
     wire alu_sgt  = (alu_control == 4'b1110);  // 有符号大于
     wire alu_not  = (alu_control == 4'b1111);  // 按位非
 ​
     // 中间结果
     wire [31:0] add_sub_result;
     wire [31:0] slt_result;
     wire [31:0] sltu_result;
     wire [31:0] sgt_result;
     wire [31:0] sgtu_result;
     wire [31:0] and_result;
     wire [31:0] nor_result;
     wire [31:0] not_result;
     wire [31:0] or_result;
     wire [31:0] xor_result;
     wire [31:0] sll_result;
     wire [31:0] srl_result;
     wire [31:0] sra_result;
     wire [31:0] lui_result;
     wire [31:0] seq_result;
 ​
     // 基本逻辑运算
     assign and_result = alu_src1 & alu_src2;
     assign or_result  = alu_src1 | alu_src2;
     assign nor_result = ~or_result;
     assign not_result = ~alu_src2;
     assign xor_result = alu_src1 ^ alu_src2;
     assign lui_result = {alu_src2[15:0], 16'd0};
 ​
     // 加减法模块
     wire [31:0] adder_operand1 = alu_src1;
     wire [31:0] adder_operand2 = alu_add ? alu_src2 : ~alu_src2;
     wire        adder_cin      = ~alu_add;
     
     wire [31:0] adder_result;
     wire        adder_cout;
     
     adder adder_module(
         .operand1(adder_operand1),
         .operand2(adder_operand2),
         .cin     (adder_cin),
         .result  (adder_result),
         .cout    (adder_cout)
     );
 ​
     assign add_sub_result = adder_result;
 ​
     // 比较运算
     assign slt_result[31:1] = 31'd0;
     assign slt_result[0]    = (alu_src1[31] & ~alu_src2[31]) | (~(alu_src1[31]^alu_src2[31]) & adder_result[31]);
     
     assign sltu_result = {31'd0, ~adder_cout};
     
     assign sgt_result[31:1] = 31'd0;
     assign sgt_result[0]    = (~alu_src1[31] & alu_src2[31]) | (~(alu_src1[31]^alu_src2[31]) & ~adder_result[31] & (|adder_result));
     
     assign sgtu_result = {31'd0, adder_cout};
     
     assign seq_result = {31'd0, adder_result == 32'd0};
 ​
     // 移位运算
     wire [4:0] shf = alu_src1[4:0];
     wire [1:0] shf_1_0 = shf[1:0];
     wire [1:0] shf_3_2 = shf[3:2];
     
     // 逻辑左移
     wire [31:0] sll_step1;
     wire [31:0] sll_step2;
     assign sll_step1 = {32{shf_1_0 == 2'b00}} & alu_src2
                      | {32{shf_1_0 == 2'b01}} & {alu_src2[30:0], 1'd0}
                      | {32{shf_1_0 == 2'b10}} & {alu_src2[29:0], 2'd0}
                      | {32{shf_1_0 == 2'b11}} & {alu_src2[28:0], 3'd0};
     assign sll_step2 = {32{shf_3_2 == 2'b00}} & sll_step1
                      | {32{shf_3_2 == 2'b01}} & {sll_step1[27:0], 4'd0}
                      | {32{shf_3_2 == 2'b10}} & {sll_step1[23:0], 8'd0}
                      | {32{shf_3_2 == 2'b11}} & {sll_step1[19:0], 12'd0};
     assign sll_result = shf[4] ? {sll_step2[15:0], 16'd0} : sll_step2;
 ​
     // 逻辑右移
     wire [31:0] srl_step1;
     wire [31:0] srl_step2;
     assign srl_step1 = {32{shf_1_0 == 2'b00}} & alu_src2
                      | {32{shf_1_0 == 2'b01}} & {1'd0, alu_src2[31:1]}
                      | {32{shf_1_0 == 2'b10}} & {2'd0, alu_src2[31:2]}
                      | {32{shf_1_0 == 2'b11}} & {3'd0, alu_src2[31:3]};
     assign srl_step2 = {32{shf_3_2 == 2'b00}} & srl_step1
                      | {32{shf_3_2 == 2'b01}} & {4'd0, srl_step1[31:4]}
                      | {32{shf_3_2 == 2'b10}} & {8'd0, srl_step1[31:8]}
                      | {32{shf_3_2 == 2'b11}} & {12'd0, srl_step1[31:12]};
     assign srl_result = shf[4] ? {16'd0, srl_step2[31:16]} : srl_step2;
  
     // 算术右移
     wire [31:0] sra_step1;
     wire [31:0] sra_step2;
     assign sra_step1 = {32{shf_1_0 == 2'b00}} & alu_src2
                      | {32{shf_1_0 == 2'b01}} & {alu_src2[31], alu_src2[31:1]}
                      | {32{shf_1_0 == 2'b10}} & {{2{alu_src2[31]}}, alu_src2[31:2]}
                      | {32{shf_1_0 == 2'b11}} & {{3{alu_src2[31]}}, alu_src2[31:3]};
     assign sra_step2 = {32{shf_3_2 == 2'b00}} & sra_step1
                      | {32{shf_3_2 == 2'b01}} & {{4{sra_step1[31]}}, sra_step1[31:4]}
                      | {32{shf_3_2 == 2'b10}} & {{8{sra_step1[31]}}, sra_step1[31:8]}
                      | {32{shf_3_2 == 2'b11}} & {{12{sra_step1[31]}}, sra_step1[31:12]};
     assign sra_result = shf[4] ? {{16{sra_step2[31]}}, sra_step2[31:16]} : sra_step2;
 ​
     // 结果选择
     assign alu_result = alu_add  ? add_sub_result :
                         alu_sub  ? add_sub_result :
                         alu_slt  ? slt_result :
                         alu_sltu ? sltu_result :
                         alu_sgt  ? sgt_result :
                         alu_sgtu ? sgtu_result :
                         alu_and  ? and_result :
                         alu_nor  ? nor_result :
                         alu_not  ? not_result :
                         alu_or   ? or_result :
                         alu_xor  ? xor_result :
                         alu_sll  ? sll_result :
                         alu_srl  ? srl_result :
                         alu_sra  ? sra_result :
                         alu_lui  ? lui_result :
                         32'd0;
 endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值