实验三 ALU 模块实现
本实验旨在设计实现MIPS架构的ALU模块,支持12种运算指令。实验采用Verilog语言开发,使用Xilinx Vivado工具及教学实验箱进行验证。ALU模块包含加减法、逻辑运算(与/或/异或)、比较(有符号/无符号)、移位(左移/右移/算术右移)以及高位加载功能。核心设计包括:1) 复用加法器实现加减法和比较运算;2) 分步式移位器设计;3) 独热码控制信号选择运算结果。硬件测试验证了加法、
一.实验目的
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.实验结果分析
图一:实现加法操作。
图二:实现减法操作。
图三:实现按位与操作。
图四:实现按位异或。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)