1. 实验目的
-
熟悉MIPS指令集中的运算指令,学会对这些指令进行归纳分类。
-
了解MIPS指令结构。
-
熟悉并掌握ALU的原理、功能和设计。
-
进一步加强运用verilog语言进行电路设计的能力。
-
为后续设计cpu的实验打下基础。
2. 实验内容说明
-
原有的操作码为12位,请压缩到操作码控制型号位宽为4位。
-
在操作码调整到4位之后,应该能支持15种不同运算,请添加至少三种运算功能(有符号数比较和无符号数比较的大于置位运算、一种未实现的位运算),然后上实验箱验证(可以不用仿真)。
-
实验报告中的原理图就用图5.3即可,不再是顶层模块图。
3. 实验原理图
实验设计
控制信号 | ALU操作 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 无 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 加法 |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 减法 |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 有符号比较,小于置位 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 无符号比较,小于置位 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 按位与 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 按位或非 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 按位或 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 按位异或 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 逻辑左移 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 逻辑右移 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 算术右移 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 高位加载 |
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