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
2万+

被折叠的 条评论
为什么被折叠?



