数字电子技术实验03-ALU

算术逻辑单元(ALU)是 CPU 的核心部件,实现算术及逻辑运算。

实验目的

熟悉用算术、逻辑的 Verilog 编程,练习多模块自顶向下编程方法。

实验内容

实验1

设计一个 4 位算术逻辑单元,输入信号为:
两组 4 位数据输入信号(A3—A0,B3—B0),一个进位输入信号 Cin;
数据输出信号为:4 位数据信号(F3—F0), 一个进位输出信号 Cout。
以上数据均为无符号正整数。功能控制信号有:S1、S0、M。
当 M=0 时为逻辑运算,M=1 时为算术运算,S1、S0 的功能如表 1 所示。

实验2

在 BASYS3 开发板上实现上述设计,SW 选择可以自己确定。
例如,SW[15]对应:M,
SW[14:13]对应:S1 和 S0,
SW[12]、SW[3:0]、SW[7:4]分别对应:Cin、A[3:0]、B[3:0],
左侧第 2 个七段数码管的小数点表示 Cin,最右侧的小数点表示 Cout。
当 SW 为 1 时,其上面的 LED 点亮,否则熄灭。
开发板上的 4 个七段数码管用于显示十六进制的输入数据和输出数据。

如, S1=0,S0=0,M=0,A=1, F=E,显示为:

如, S1=0,S0=1,M=0,A=1, B=0,F=0,显示为:

如, S1=0,S0=0,M=1(加法),
A=1,B=2,(B 的小数点) Cin=1,(F 的小数点) Cout=0,F=4,显示为:

参考示意图

实验方案

整体思路:
→输入(SW 拨码开关)
→ALU 运算模块(逻辑/算术运算+运算结果整合)
→输出模块(七段数码管分时复用+数字转七段数码管)
→输出(七段数码管+LED 灯)

代码分析

输入(Basys3_Master.xdc)

## Switches
set_property PACKAGE_PIN V17 [get_ports {A[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {A[0]}]
set_property PACKAGE_PIN V16 [get_ports {A[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {A[1]}]
set_property PACKAGE_PIN W16 [get_ports {A[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {A[2]}]
set_property PACKAGE_PIN W17 [get_ports {A[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {A[3]}]
set_property PACKAGE_PIN W15 [get_ports {B[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {B[0]}]
set_property PACKAGE_PIN V15 [get_ports {B[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {B[1]}]
set_property PACKAGE_PIN W14 [get_ports {B[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {B[2]}]
set_property PACKAGE_PIN W13 [get_ports {B[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {B[3]}]
set_property PACKAGE_PIN W2 [get_ports {Cin}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {Cin}]
set_property PACKAGE_PIN U1 [get_ports {S[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {S[0]}]
set_property PACKAGE_PIN T1 [get_ports {S[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {S[1]}]
set_property PACKAGE_PIN R2 [get_ports {M}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {M}]

开关分配

  • SW[3:0] <- A[3:0]
  • SW[7:4] <- B[3:0]
  • SW[14:13] <- S[1:0]
  • SW [15] <- M
  • SW [12] <- Cin

ALU 运算模块(mainDesign.sv)

变量定义

module mainDesign(
        input logic [1:0] S,    //运算功能控制器
        input logic [3:0] A,    //A输入
        input logic [3:0] B,    //B输入
        input logic M,          //逻辑or算术运算选择器
        input logic Cin,        //进位输入信号
        input  logic CLK100MHZ, //时钟频率
        output logic [1:0] SL,  //SW开关LED输出,下同
        output logic [3:0] AL,
        output logic [3:0] BL,
        output logic ML,
        output logic CinL,
        output logic [7:0] a2g, //七位数码管-阴极
        output logic [3:0] AN   //七位数码管-阳极
    );

    logic [4:0] temp;           //临时运算结果储存 
    logic nf;                   //负数标志
    logic zf;                   //零标志
    logic cf;                   //进位标志
    logic ovf;                  //溢出标志
    logic Cout;                 //进位输出信号
    logic [3:0] F;              //运算结果返回值
    logic [15:0] x;             //模块返回值

ALU模块

    //ALU模块-运算部分
    always_comb begin
        cf=0;
        ovf=0;
        temp=5'b00000;
        case(M)
            1'b0: begin //M=0 逻辑运算
                case(S)
                    2'b00: F= ~A; //F= not A
                    2'b01: F=A&B; //F= A and B
                    2'b10: F=A|B; //F= A or B
                    2'b11: F=A^B; //F= A xor B
                    default: F=A;
                endcase
            end
            1'b1: begin //M=1 算术运算
                case(Cin)
                    1'b0: begin //Cin=0 
                        case(S)
                            2'b00: begin //F=A+B+0 
                                temp={1'b0,A}+{1'b0,B}+{1'b0,1'b0};
                                F=temp[3:0];
                                cf=temp[4];
                                ovf=F[3]^A[3]^B[3]^cf;
                            end
                            2'b01: begin //F=A-B-0
                                temp={1'b0,A}-{1'b0,B}-{1'b0,1'b0};
                                F=temp[3:0];
                                cf=temp[4];
                                ovf=F[3]^A[3]^B[3]^cf;
                            end
                        endcase
                    end
                    1'b1: begin //Cin=1
                        case(S)
                            2'b00: begin //F=A+B+1
                                temp={1'b0,A}+{1'b0,B}+{1'b0,1'b1};
                                F=temp[3:0];
                                cf=temp[4];
                                ovf=F[3]^A[3]^B[3]^cf;
                            end
                            2'b01: begin //F=A-B-1
                                temp={1'b0,A}-{1'b0,B}-{1'b0,1'b1};
                                F=temp[3:0];
                                cf=temp[4];
                                ovf=F[3]^A[3]^B[3]^cf;
                            end
                        endcase
                    end
                endcase
            end
        endcase
        nf=F[3];
        if(F==4'b0000) zf=1;
        else           zf=0;
    end
  1. 运算规则基于实验内容建立
  2. ALU 整体通过 always 语句实现
  3. 分支结构通过 case 语句实现
  4. 参考项目: ppt 中的示例工程以及 GitHub 项目:
    jrmoulton/Simple-ALU: A calculator in Verilog for the Basys3 FPGA (github.com)

LED 模块&返回模块

    //LED模块-开关信号控制LED灯点亮
    assign AL=A;
    assign BL=B;
    assign SL=S;
    assign ML=M;
    assign CinL=Cin;

    //返回模块-运算结果返回给输出模块
    assign x[15:12]=A;  
    assign x[11:8]=B;
    assign x[3:0]=F;
    assign Cout=cf;
    assistDesign X7(.x(x),.Cin(Cin),.clk(CLK100MHZ),.a2g(a2g),.AN(AN),.Cout(Cout));
endmodule

输出模块

七段数码管分时复用(assistDesign.sv)

module assistDesign(
            input logic [15:0] x,
            input logic Cin,
            input logic Cout,
            input logic clk,
            input logic clr,
            output logic [7:0] a2g,
            output logic [3:0] AN           //数码管使能
        );
    
    logic [1:0] s;                          //选择哪个数码管
    logic [7:0] digit;
    logic [19:0] clkdiv;
    
    assign s = clkdiv[19:18];               // count every 10.4ms        
    
    //4个数码管 4选1 (MUX44)
    always_comb
        case(s)
            0: begin
                if(Cout==0) digit=x[3:0];   //分配给F
                else digit=x[3:0]+'h10;     //进位标志
            end
            1: digit='hff;                  //显示等号
            2: begin
                if(Cin==0) digit=x[11:8];   //分配给B
                else digit=x[11:8]+'h10;    //进位标志
            end
            3: digit=x[15:12];              //分配给A
            default: digit=x[3:0];
        endcase
    
    //4个数码管轮流点亮
    always_comb
        case(s)
            0: AN=4'b1110;
            1: AN=4'b1101;
            2: AN=4'b1011;
            3: AN=4'b0111;
            default: AN=4'b1110;
        endcase
        
    //时钟分频器(20位二进制计数器)
    always @(posedge clk, posedge clr)
      if(clr == 1) clkdiv <= 0;
      else         clkdiv <= clkdiv + 1;
    
    //实例化 7段数码管
    Dec7Seg s7(.x(digit),.a2g(a2g));    
endmodule

整体参考实验 2 相关,详见注释

数字转七段数码管(Dec7Seg.sv)

module Dec7Seg(
        input logic [7:0] x,
        output logic [7:0] a2g 
    ); 
 
    assign AN = 4'b0000;

    always_comb
        case (x) 
            'h00: a2g = 8'b00000011;    //数字并且不显示小数点,下同
            'h01: a2g = 8'b10011111; 
            'h02: a2g = 8'b00100101; 
            'h03: a2g = 8'b00001101; 
            'h04: a2g = 8'b10011001; 
            'h05: a2g = 8'b01001001; 
            'h06: a2g = 8'b01000001; 
            'h07: a2g = 8'b00011111; 
            'h08: a2g = 8'b00000001; 
            'h09: a2g = 8'b00001001;  
            'h0a: a2g = 8'b00010001; 
            'h0b: a2g = 8'b11000001; 
            'h0c: a2g = 8'b01100011; 
            'h0d: a2g = 8'b10000101; 
            'h0e: a2g = 8'b01100001; 
            'h0f: a2g = 8'b01110001;
            'h10: a2g = 8'b00000010;    //数字并且显示小数点,下同 
            'h11: a2g = 8'b10011110; 
            'h12: a2g = 8'b00100100; 
            'h13: a2g = 8'b00001100; 
            'h14: a2g = 8'b10011000; 
            'h15: a2g = 8'b01001000; 
            'h16: a2g = 8'b01000000; 
            'h17: a2g = 8'b00011110; 
            'h18: a2g = 8'b00000000; 
            'h19: a2g = 8'b00001000;  
            'h1a: a2g = 8'b00010000; 
            'h1b: a2g = 8'b11000000; 
            'h1c: a2g = 8'b01100010; 
            'h1d: a2g = 8'b10000100; 
            'h1e: a2g = 8'b01100000; 
            'h1f: a2g = 8'b01110000;
            'hff: a2g = 8'b11101101;    //显示等号
        default: a2g = 8'b00000000;     //完全显示
        endcase 
endmodule
  1. 整体参考实验 2 相关和 GitHub 项目:
    nganinho/Basys3_7segments (github.com)
  2. 由于需要控制单个小数点,于是取消了小数点位由 DP 变量同一控制,而将其
    整合入了 a2g 数组和其余数码管一同控制,依旧是高电平熄灭低电平点亮
  3. 等号的显示由特殊数值’hff 控制

输出(Basys3_Master.xdc)

## LEDs
set_property PACKAGE_PIN U16 [get_ports {AL[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AL[0]}]
set_property PACKAGE_PIN E19 [get_ports {AL[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AL[1]}]
set_property PACKAGE_PIN U19 [get_ports {AL[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AL[2]}]
set_property PACKAGE_PIN V19 [get_ports {AL[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AL[3]}]
set_property PACKAGE_PIN W18 [get_ports {BL[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {BL[0]}]
set_property PACKAGE_PIN U15 [get_ports {BL[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {BL[1]}]
set_property PACKAGE_PIN U14 [get_ports {BL[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {BL[2]}]
set_property PACKAGE_PIN V14 [get_ports {BL[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {BL[3]}]
set_property PACKAGE_PIN P3 [get_ports {CinL}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {CinL}]
set_property PACKAGE_PIN N3 [get_ports {SL[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {SL[0]}]
set_property PACKAGE_PIN P1 [get_ports {SL[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {SL[1]}]
set_property PACKAGE_PIN L1 [get_ports {ML}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {ML}]
	
##7 segment display
set_property PACKAGE_PIN W7 [get_ports {a2g[7]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[7]}]
set_property PACKAGE_PIN W6 [get_ports {a2g[6]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[6]}]
set_property PACKAGE_PIN U8 [get_ports {a2g[5]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[5]}]
set_property PACKAGE_PIN V8 [get_ports {a2g[4]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[4]}]
set_property PACKAGE_PIN U5 [get_ports {a2g[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[3]}]
set_property PACKAGE_PIN V5 [get_ports {a2g[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[2]}]
set_property PACKAGE_PIN U7 [get_ports {a2g[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[1]}]
set_property PACKAGE_PIN V7 [get_ports {a2g[0]}]							
	set_property IOSTANDARD LVCMOS33 [get_ports {a2g[0]}]

set_property PACKAGE_PIN U2 [get_ports {AN[0]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AN[0]}]
set_property PACKAGE_PIN U4 [get_ports {AN[1]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AN[1]}]
set_property PACKAGE_PIN V4 [get_ports {AN[2]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AN[2]}]
set_property PACKAGE_PIN W4 [get_ports {AN[3]}]					
	set_property IOSTANDARD LVCMOS33 [get_ports {AN[3]}]

总结与思考

  1. 在 ALU 中定义的输入输出变量需要和约束文件中定义的名称保持一致
  2. 在实验二中所有的小数点由 DP 变量统一控制点亮/熄灭,而本实验中则需要单独控制第二位和第四位的小数点,所以需要将原DP整合进入a2g数组统一控制,a2g 的长度从原来的 7 位二进制数变为 8 位二进制数
  3. 由于增加了小数点和等号的显示,实例化时需要返回 2 位十六进制数才能完整表示全部情况
  4. 收获:ALU 模块中 always 语句,case 语句,if 语句的使用,进行简单的逻辑与算术运算;输出模块中重写数码管约束文件和实例化文件
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇