一.实验目的

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

2. 了解 MIPS 指令结构。

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

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

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

二.实验设备

1. 装有 Xilinx Vivado 的计算机一台。

2. LS-CPU-EXB-002 教学系统实验箱一套。

. 实验内容与步骤

1.设计框图

2.核心代码

`timescale 1ns / 1ps

//*************************************************************************

//   > 文件名: alu.v

//   > 描述  :ALU模块,可做12种操作

//   > 作者  : LOONGSON

//   > 日期  : 2016-04-14

//*************************************************************************

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

3.创新点说明

4.仿真曲线截图

5.硬件实现照片

图一

图二

图三

图四

6.实验结果分析

图一:实现加法操作。

图二:实现减法操作。

图三:实现按位与操作。

图四:实现按位异或。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐