第七篇 乘法器

2024-06-05 00:44
文章标签 第七篇 乘法器

本文主要是介绍第七篇 乘法器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实验七 乘法器

7.1 实验目的

  1. 回顾实验五中讲解的加法器的实现,掌握使用全加器实现任意乘数的乘法器的基本原理;

  2. 掌握使用串行进位加法器实现任意乘数的乘法器的基本原理;

  3. 掌握使用树形加法器实现任意乘数的乘法器的基本原理。

7.2 原理介绍

乘法器(multiplier)是一种完成两个互不相关的模拟信号相乘作用的电子器件,它可以将两个二进制数相乘。乘法器的模型是基于"移位和相加"的算法,是由更基本的加法器组成的。

7.2.1 使用全加器实现阵列乘法器

图7.1给出了乘法运算 p = a × b 的竖式计算示意图,其中,a = 11,b = 12。我们利用加法运算来实现乘法运算,第一个加数等于 b 的个位数字乘 a,第二个加数等于 b 的十位数字乘 a 并向左移一位,再将这两个数相加,就得到了乘法运算的结果:p = 132。

图7.1 11×12的竖式计算示意图

我们将十进制数字11、12分别以二进制的形式表示为1011和1100,同样地,画出竖式计算示意图如图7.2所示,首先将 a 分别与 b 的每一位相乘得到4个加数,由于二进制数 b 的每一位不是"1"就是"0",因此,这4个加数为 a 的移位形式或"0000"。

图7.2 1011×1100的竖式计算示意图

将乘数 a 的每一位表示为 a_3、a_2、a_1、a_0,将乘数 b 的每一位表示为 b_3、b_2、b_1、b_0,乘积 p 的每一位表示为 p_7、p_6、p_5、p_4、p_3、p_2、p_1、p_0,则可得到二进制乘法运算的竖式计算示意图,如图7.3所示。

图7.3 二进制乘法运算的竖式计算示意图

图7.4为实现4位二进制乘法运算 p = a × b 的电路图,这种结构被称为阵列乘法器(array multiplier)。下图中的阴影区域与图7.3中的阴影区域相对应,每行的与门用来产生全加器的加数,全加器相加产生本位和以及进位输出(这里使用的全加器就是在实验五中实现的全加器)。其中,PP1_4、PP1_3、PP1_2 对应第一行的第2、3、4个加法器的本位和,c\_b1_1、c\_b1_2、c\_b1_3、PP1_5 对应第一行的第1、2、3、4个加法器的进位输出;PP2_3、PP2_4、PP2_5 对应第二行的第2、3、4个加法器的本位和,c\_b2_1、c\_b2_2、c\_b2_3、PP2_6 对应第二行的第1、2、3、4个加法器的进位输出;c\_b3_1、c\_b3_2、c\_b3_3 对应第三行的第1、2、3个加法器的进位输出。

图7.4 使用全加器实现阵列乘法器电路

使用全加器实现阵列乘法器的部分代码如下:

// 例化第1行的4个全加器
fa b1_a0 (.a(a[1] & b[0]), .b(a[0] & b[1]), .ci(1'b0),    .s(p[1]),   .co(c_b1[1]));
fa b1_a1 (.a(a[2] & b[0]), .b(a[1] & b[1]), .ci(c_b1[1]), .s(pp1[2]), .co(c_b1[2]));
fa b1_a2 (.a(a[3] & b[0]), .b(a[2] & b[1]), .ci(c_b1[2]), .s(pp1[3]), .co(c_b1[3]));
fa b1_a3 (.a(1'b0),        .b(a[3] & b[1]), .ci(c_b1[3]), .s(pp1[4]), .co(pp1[5]));
​
// 例化第2行的4个全加器
fa b2_a0 (.a(pp1[2]), .b(a[0] & b[2]), .ci(1'b0),    .s(p[2]),   .co(c_b2[1]));
fa b2_a1 (.a(pp1[3]), .b(a[1] & b[2]), .ci(c_b2[1]), .s(pp2[3]), .co(c_b2[2]));
fa b2_a2 (.a(pp1[4]), .b(a[2] & b[2]), .ci(c_b2[2]), .s(pp2[4]), .co(c_b2[3]));
fa b2_a3 (.a(pp1[5]), .b(a[3] & b[2]), .ci(c_b2[3]), .s(pp2[5]), .co(pp2[6]));
​
// 例化第3行的4个全加器
fa b3_a0 (.a(pp2[3]), .b(a[0] & b[3]), .ci(1'b0),    .s(p[3]), .co(c_b3[1]));
fa b3_a1 (.a(pp2[4]), .b(a[1] & b[3]), .ci(c_b3[1]), .s(p[4]), .co(c_b3[2]));
fa b3_a2 (.a(pp2[5]), .b(a[2] & b[3]), .ci(c_b3[2]), .s(p[5]), .co(c_b3[3]));
fa b3_a3 (.a(pp2[6]), .b(a[3] & b[3]), .ci(c_b3[3]), .s(p[6]), .co(p[7]));

代码7.1 使用全加器实现阵列乘法器的部分代码

7.2.2 使用串行进位加法器实现阵列乘法器

接下来,我们将图7.4中每一行的4个全加器整合为一个4位串行进位加法器,每个4位串行进位加法器将本行计算得到的乘积(a 或 a 的移位形式)与上一行的运算结果相加,这样就把乘法运算等效为一系列的加法运算。如图7.5所示。

图7.5 使用4位串行进位加法器实现阵列乘法器电路

使用4位串行进位加法器实现阵列乘法器的部分代码如下:

assign pp0 = { 4'd0, a & {4{b[0]}} };
assign pp1 = pp0 + { 3'd0, a & {4{b[1]}}, 1'd0 };
assign pp2 = pp1 + { 2'd0, a & {4{b[2]}}, 2'd0 };
assign p   = pp2 + { 1'd0, a & {4{b[3]}}, 3'd0 };

代码7.2 使用4位串行进位加法器实现阵列乘法器的部分代码

7.2.3 使用树形加法器实现阵列乘法器

在前面我们介绍了使用4位串行进位加法器实现阵列乘法器,接下来我们将使用树形加法器来实现阵列乘法器。树形加法器采用并行相加的方式来计算多个数据的和,如图7.6所示,先并行计算出 A+B、C+D 的和PP0、PP1,再将PP0、PP1相加计算出总和P。

图7.6 使用树形加法器计算4个数据的和

使用树形加法器实现阵列乘法器的电路图如图7.7所示。

图7.7 使用树形加法器实现阵列乘法器电路

可以看到,在图7.7中我们没有将6位串行进位加法器的进位输出位 c_o 作为 p_8 输出,这是因为,在第二个4位串行进位加法器中,a_3 = 0,因此其 c_o 和 s_3 位不可能同时为1,在6位串行加法器中 b_4 = b_5 = 0,因此6位串行加法器的进位输出位 c_o = 0。

使用树形加法器实现阵列乘法器的部分代码如下:

assign pp0 = { 4'd0, a & {4{b[0]}} }       + { 3'd0, a & {4{b[1]}}, 1'd0 };
assign pp1 = { 2'd0, a & {4{b[2]}}, 2'd0 } + { 1'd0, a & {4{b[3]}}, 3'd0 };
assign p   = pp0 + pp1;

代码7.3 使用树形加法器实现阵列乘法器的部分代码

7.3 实验任务

  • 使用Verilog HDL硬件描述语言设计实现2个4位二进制数的乘法运算;

  • 将实验六计算器中使用移位寄存器实现的乘2运算替换为2个4位二进制数的乘法器。

7.4 设计实现

7.4.1 设计思路

如图7.8所示为本实验实现的计算器的系统框图,本实验是在实验六的基础上,将移位寄存器实现的乘2运算替换为2个4位二进制数的乘法器。SW3 ~ SW0作为乘法器的乘数 a,将乘法器的乘积 p​ 以十六进制的形式显示在数码管HEX1 ~ HEX0上,并以二进制的形式显示在LEDR7 ~ LEDR0上。

image-20240521155019915

图7.8 计算器系统框图

当数据选择器的选择位输入为 101 时,计算器可实现乘法器(p = a × b)的功能。

7.4.2 代码实现
  • 使用全加器实现阵列乘法器

    module c6 (input   [ 3: 0] a,          // 乘数ainput   [ 3: 0] b,          // 乘数boutput  [ 7: 0] f           // 乘积f
    );// 变量声明
    wire [7:0] p;
    wire [3:1] c_b1;    // 第1行加法器的部分进位标志位
    wire [5:2] pp1;     // 第1行加法器的部分和、进位标志位
    wire [3:1] c_b2;    // 第2行加法器的部分进位标志位
    wire [6:3] pp2;     // 第2行加法器的部分和、进位标志位
    wire [3:1] c_b3;    // 第3行加法器的部分进位标志位
    ​
    assign p[0] = a[0] & b[0];
    ​
    // 例化第1行的4个全加器
    fa b1_a0 (.a(a[1] & b[0]), .b(a[0] & b[1]), .ci(1'b0),    .s(p[1]),   .co(c_b1[1]));
    fa b1_a1 (.a(a[2] & b[0]), .b(a[1] & b[1]), .ci(c_b1[1]), .s(pp1[2]), .co(c_b1[2]));
    fa b1_a2 (.a(a[3] & b[0]), .b(a[2] & b[1]), .ci(c_b1[2]), .s(pp1[3]), .co(c_b1[3]));
    fa b1_a3 (.a(1'b0),        .b(a[3] & b[1]), .ci(c_b1[3]), .s(pp1[4]), .co(pp1[5]));
    ​
    // 例化第2行的4个全加器
    fa b2_a0 (.a(pp1[2]), .b(a[0] & b[2]), .ci(1'b0),    .s(p[2]),   .co(c_b2[1]));
    fa b2_a1 (.a(pp1[3]), .b(a[1] & b[2]), .ci(c_b2[1]), .s(pp2[3]), .co(c_b2[2]));
    fa b2_a2 (.a(pp1[4]), .b(a[2] & b[2]), .ci(c_b2[2]), .s(pp2[4]), .co(c_b2[3]));
    fa b2_a3 (.a(pp1[5]), .b(a[3] & b[2]), .ci(c_b2[3]), .s(pp2[5]), .co(pp2[6]));
    ​
    // 例化第3行的4个全加器
    fa b3_a0 (.a(pp2[3]), .b(a[0] & b[3]), .ci(1'b0),    .s(p[3]), .co(c_b3[1]));
    fa b3_a1 (.a(pp2[4]), .b(a[1] & b[3]), .ci(c_b3[1]), .s(p[4]), .co(c_b3[2]));
    fa b3_a2 (.a(pp2[5]), .b(a[2] & b[3]), .ci(c_b3[2]), .s(p[5]), .co(c_b3[3]));
    fa b3_a3 (.a(pp2[6]), .b(a[3] & b[3]), .ci(c_b3[3]), .s(p[6]), .co(p[7]));
    ​
    assign f = p;endmodule

    代码7.4 使用全加器实现阵列乘法器

    使用全加器实现阵列乘法器的RTL代码综合出的RTL视图如图7.9所示,这与前面图7.4中的电路图一致。

    图7.9 使用全加器实现阵列乘法器的RTL视图

  • 使用串行进位加法器实现阵列乘法器

    module c6 (input   [ 3: 0] a,          // 乘数ainput   [ 3: 0] b,          // 乘数boutput  [ 7: 0] f           // 乘积f
    );// 变量声明
    wire [7:0] pp0, pp1, pp2;
    wire [7:0] p;
    ​
    assign pp0 = { 4'd0, a & {4{b[0]}} };
    assign pp1 = pp0 + { 3'd0, a & {4{b[1]}}, 1'd0 };
    assign pp2 = pp1 + { 2'd0, a & {4{b[2]}}, 2'd0 };
    assign p   = pp2 + { 1'd0, a & {4{b[3]}}, 3'd0 };assign f = p;endmodule

    代码7.5 使用串行进位加法器实现阵列乘法器

    使用串行进位加法器实现阵列乘法器的RTL代码综合出的RTL视图如图7.10所示,这与前面图7.5中的电路图一致。

    图7.10 使用串行进位加法器实现阵列乘法器的RTL视图

  • 使用树形加法器实现阵列乘法器

    module c6 (input   [ 3: 0] a,          // 乘数ainput   [ 3: 0] b,          // 乘数boutput  [ 7: 0] f           // 乘积f
    );// 变量声明
    wire [7:0] pp0, pp1;
    wire [7:0] p;
    ​
    assign pp0 = { 4'd0, a & {4{b[0]}} }       + { 3'd0, a & {4{b[1]}}, 1'd0 };
    assign pp1 = { 2'd0, a & {4{b[2]}}, 2'd0 } + { 1'd0, a & {4{b[3]}}, 3'd0 };
    assign p   = pp0 + pp1;assign f = p;endmodule

    代码7.6 使用树形加法器实现阵列乘法器

    使用树形加法器实现阵列乘法器的RTL代码综合出的RTL视图如图7.11所示,这与前面图7.7中的电路图一致。

    图7.11 使用树形加法器实现阵列乘法器的RTL视图

  • 计算器模块

    module calculator(input   [ 3: 0] a,// input   [ 3: 0]   b,input           carry_in,input   [ 2: 0] sel,input           en,input           clk,input           rst_n,output  [ 6: 0] hex1_out,output  [ 6: 0] hex0_out,output  [ 7: 0] ledr_out
    );
    ​
    wire [3:0] b;
    wire [3:0] f1,f2,f3,f4;
    wire [5:0] f5,f7;
    wire [7:0] f6,f,g;
    wire carry_out;
    wire overflow;// 将输入a存入寄存器中reg4bits reg4bits_inst (.clk(clk), .rst_n(rst_n), .en(~en), .d(a), .q(b));  // a和b做与运算
    c1 c1_inst (.a(a), .b(b), .f(f1));
    // a和b做或运算
    c2 c2_inst (.a(a), .b(b), .f(f2));
    // a和b做异或运算
    c3 c3_inst (.a(a), .b(b), .f(f3));
    // a做位取反运算
    c4 c4_inst (.a(a), .f(f4));
    // a和b做加(减)法运算
    c5 c5_inst (.a(a), .b(b), .ci(carry_in), .f(f5));
    // a和b做乘法运算
    c6 c6_inst (.a(a), .b(b), .f(f6));
    // a做除2运算
    c7 c7_inst (.a(a), .f(f7));// 在前面的f1,f2,f3,f4,f5,f6,f7五种运算结果中,选择一个运算结果作为计算器的输出。
    // 其中,f1,f2,f3,f4,f5,f7需要将高位补0组成8位
    mux8x1 mux8x1_inst (.r({4'd0, f1}),.t({4'd0, f2}),.u({4'd0, f3}),.v({4'd0, f4}),.w({2'd0, f5}),.x(f6),.y({2'd0, f7}),.z(8'd0),.s(sel),.m(f)
    );// 将运算结果f存入寄存器中reg8bits reg8bits_inst (.clk(clk), .rst_n(rst_n), .en(~en), .d(f), .q(g));// 当执行c1、c2、c3、c4的逻辑运算时,g[3:0]为逻辑运算结果
    // 当执行c5的加法运算时,g[3:0]为和数s,g[5:4]分别为溢出标志位和进位标志位
    // 当执行c6的乘法运算时,g[7:0]为乘积
    // 当执行c7的除法运算时,g[5:0]为商
    // 将g[7:4]以十六进制的形式显示在hex1_out上,g[3:0]显示在hex0_out上
    decod7seg decod7seg_inst0 (.hex(g[3:0]), .display(hex0_out));
    decod7seg decod7seg_inst1 (.hex(g[7:4]), .display(hex1_out));
    ​
    // 将g[7:0]以二进制的形式显示在ledr_out上
    assign ledr_out = g;endmodule

    代码7.7 calculator.v

    calculator子模块的RTL代码综合出的RTL视图如图7.12所示,这与前面图7.8中的框图一致。

    image-20240521174652924

    图7.12 calculator子模块RTL视图

7.5 实验步骤

7.5.1 创建工程和代码输入
  1. 点击电脑右下角的开始菜单找到Quartus软件,双击Quartus (Quartus Prime 17.1)打开Quartus Prime软件。

  2. 点击菜单File-->New Project Wizard弹出工程创建的对话框。在弹出的对话框中点击Next。

  3. 在您的DE1-SOC 工作文件夹下创建一个lab7的文件夹,并将工程路径指向该文件夹,且工程的名称也命名calculator。如图7.13所示。

    image-20240521161305984

    图7.13 选择实验

  4. 连续点击三次Next后,选择器件5CSEMA5F31C6,继续点击Next,最后点击Finish完成工程创建。

    image-20240521161419813

    图7.14 创建Quartus工程

  5. 完成创建工程后,Quartus Prime软件会打开lab7工程,如图7.15所示。

    image-20240521161439104

    图7.15 Quartus软件打开lab7工程

  6. 打开lab7工程路径,新建名为v的文件夹,如图7.16所示。

    image-20240521163008988

    图7.16 在lab7文件夹下新建v文件夹

  7. 实验六 移位寄存器中的c1.v、c2.v、c3.v、c4.v、c5.v、c6.v、c7.v、calculator.v、decod7seg.v、fa.v、mux2x1.v、mux8x1.v、reg6bits.v文件拷贝至lab7的v文件夹中,然后将reg6bits.v文件重命名为reg8bits.v,如图7.17所示。

    image-20240521164204305

    图7.17 拷贝文件到v文件夹中

  8. 点击Quartus软件工具栏的Assignments --> Settings --> Files,将前面拷贝的文件添加至本实验的Quartus工程,如图7.19所示。

    image-20240521164258049

    图7.18 添加拷贝的文件到Quartus工程

  9. 点击Project Navigator下拉框,选中Files,然后双击v/c6.v打开c6.v文件,参考代码7.6修改c6.v文件(代码7.4、代码7.5和代码7.6实现的功能相同,在这里我们以代码7.6为例进行实验)。

    image-20240521163919770

    图7.19 Quartus软件中的c6.v文件

  10. 然后双击v/mux8x1.v打开mux8x1.v文件,将mux8x1.v文件中的代码替换为代码7.8中的设计代码,将6位的八选一数据选择器修改为8位的八选一数据选择器。

    module mux8x1(// 8个8位的数据输入input       [7:0]   r,input       [7:0]   t,input       [7:0]   u,input       [7:0]   v,input       [7:0]   w,input       [7:0]   x,input       [7:0]   y,input       [7:0]   z,// 3位的选择输入input       [2:0]   s,// 1个8位的数据输出output  reg [7:0]   m
    );always@(r, t, u, v, w, x, y, z, s)
    begincase(s)3'b000: m = r;      // 当s = 000时,输出m = r3'b001: m = t;      // 当s = 001时,输出m = t3'b010: m = u;      // 当s = 010时,输出m = u3'b011: m = v;      // 当s = 011时,输出m = v3'b100: m = w;      // 当s = 100时,输出m = w3'b101: m = x;      // 当s = 101时,输出m = x3'b110: m = y;      // 当s = 110时,输出m = y3'b111: m = z;      // 当s = 111时,输出m = zendcase
    end
    ​
    endmodule

    代码7.8 mux8x1.v

    image-20240521164338901

    图7.20 Quartus软件中的mux8x1.v文件

  11. 打开reg8bits.v文件,将reg8bits.v文件中的代码替换为代码7.9中的设计代码。

    module reg8bits(input               clk,        // 时钟 50MHzinput               rst_n,      // 异步复位信号,低电平有效input               en,         // 同步使能信号,高电平有效input       [7:0]   d,          // 并行输入数据output  reg [7:0]   q           // 并行输出数据
    );//当 always 块中的敏感列表为检测到 clk 上升沿或 rst_n 下降沿时执行下面的语句
    always@(posedge clk, negedge rst_n)
    beginif(~rst_n)              // rst_n 为低电平复位,且不需要等待 clk 上升沿到来后再复位q <= 8'b00000000;else if(en)q <= d;elseq <= q;
    endendmodule

    代码7.9 reg8bits.v

    image-20240521164421201

    图7.21 reg8bits.v文件

  12. 参考代码7.7修改calculator.v文件。

    image-20240521164652954

    图7.22 Quartus软件中的calculator.v文件

  13. 点击Quartus软件工具栏的Processing --> Start --> Start Analysis & Synthesis或点击

    image-20210603145513555

    按钮对Verilog HDL代码执行语法检查和综合。如果在该过程中提示有错误,请检查Verilog HDL代码语法,确保与上述代码块完全一致。

    image-20240521165345602

    图7.24 对Verilog代码进行分析和综合

7.5.2 仿真
  1. 点击Quartus软件工具栏的File --> New --> Verilog HDL File,点击OK,新建一个空白Verilog HDL文件,再点击File --> Save As ...保存,命名为calculator_tb.v,保存在v文件夹中,如图7.25所示。

    image-20240521165455132

    图7.25 新建并保存test bench文件

  2. 在calculator_tb.v文件中输入如下代码,并保存。

    `timescale 1ns / 1ns
    module calculator_tb;// 产生时钟信号
    reg clk;
    localparam  PERIOD = 20;    // T = 1/frequency = 1/50MHz = 20ns
    initial beginclk = 1'b0;forever#(PERIOD/2) clk = ~clk;
    end// 产生复位信号,用作8位寄存器的异步复位
    reg rst_n;
    initial beginrst_n = 1'b0;#(PERIOD)rst_n = 1'b1;
    end// 定义计算器的两个操作数a、b,加法器的进位输入carry_in,执行的运算选择位sel,8位寄存器的使能信号en
    reg [3:0]	a;
    //reg [3:0]	b;
    reg [2:0]	sel;
    reg			en;initial 
    begin#0;	sel = 3'b101;en = 1'b0;rst_n = 1'b1;a = 4'b0010;		// 0010 × 0000 = 0000_0000//b = 4'b0010;#(PERIOD)sel = 3'b101;//en = 1'b1;rst_n = 1'b1;a = 4'b0110;		// 0110 × 0010 = 0000_1100//b = 4'b0011;#(PERIOD)sel = 3'b101;//en = 1'b1;rst_n = 1'b1;a = 4'b1001;		// 1001 × 0110 = 0101_0100//b = 4'b0111;#(PERIOD)sel = 3'b101;//en = 1'b1;rst_n = 1'b1;a = 4'b1111;		// 1111 × 1001 = 0011_0101//b = 4'b1011;#(PERIOD)	$stop;	
    end// 例化
    wire [6:0] hex1_out;
    wire [6:0] hex0_out;
    wire [7:0] ledr_out;calculator calculator_inst (
    /* input			*/		.clk		(clk),
    /* input			*/		.rst_n		(rst_n),
    /* input			*/		.en			(en),	
    /* input	[3:0]	*/		.a			(a),/* input	[3:0]	*/		//.b			(b),
    /* input			*/		.carry_in	(),
    /* input	[2:0]	*/		.sel		(sel),/* output	[6:0]	*/		.hex1_out	(hex1_out),
    /* output	[6:0]	*/		.hex0_out	(hex0_out),
    /* output	[7:0]	*/		.ledr_out	(ledr_out)
    );endmodule

    代码7.11 calculator_tb.v

图7.26 Quartus软件中的calculator_tb.v文件

  1. 点击Quartus软件工具栏的Assignments --> Settings,在弹出的Settings窗口中,选中Simulation栏,Tool name选择ModelSim-Altera,设置Quartus自动调用ModelSim。然后选择添加Test Bench文件,如图7.27所示。

    image-20240521171656160

    图7.27 设置Quartus仿真选项

  2. 依次执行下面的步骤添加calculator_tb.v文件:

    ① 在弹出的Test Benches窗口中点击New

    image-20240521171724191

    图7.28 添加Test Bench文件(步骤1)

    ② 在弹出的New Test Bench Settings窗口中,在Test bench name栏填入calculator_tb

    ③ 点击

    图标;

    image-20240521171909487

    图7.29 添加Test Bench文件(步骤2、3)

    ④ 在弹出的Select File窗口,选中第一步中创建的calculator_tb.v文件;

    ⑤ 点击Open

    image-20240521171959379

    图7.30 添加Test Bench文件(步骤4、5)

    ⑥ 在File name栏会出现选中的calculator_tb.v文件;

    ⑦ 点击Add添加test bench文件;

    ⑧ 添加后会出现在下面的框格中;

    ⑨ 点击OK,退出当前窗口;

    image-20240521172059916

    图7.31 添加Test Bench文件(步骤6、7、8、9)

    ⑩ 返回到Test Benches窗口,在Existing test bench settings框格中会出现前面设置好的test bench文件;

    ⑪ 点击OK,退出当前窗口;

    image-20240521172124388

    图7.32 添加Test Bench文件(步骤10、11)

    ⑫ 返回到Simulation设置界面,可以看到Compile test bench栏成功添加了calculator_tb仿真文件;

    ⑬ 点击Apply应用新的设置;

    ⑭ 点击Close关闭设置窗口。

    image-20240521172201443

    图7.33 添加Test Bench文件(步骤12、13、14)

  3. 点击Quartus软件工具栏的Tools --> Run Simulation Tool --> RTL Simulation启动ModelSim仿真,再点击Wave选项卡切换到仿真波形窗口,如图7.34所示。

    image-20240521173012215

    图7.34 点击Wave选项卡切换到仿真波形窗口

  4. 此时还看不到完整的仿真波形,可以通过点击如图7.35所示的Zoom Full按钮来显示完整的波形。

    图7.35 Zoom Full按钮

image-20240521173908958

image-20240521174021939

image-20240521174454035

  1. 完整的仿真波形如图7.36所示。

    image-20240522154931204

    图7.36 calculator仿真波形

    下面对仿真波形进行分析:

    本次仿真的重点是仿真乘法器的功能,因此将功能选择输入 sel 固定为 (101)_B 。

    1. 0 ~ 30 ns

      a = (0010)_B = (2)_H,b = (0000)_B = (0)_H,p = a × b = (0000\,\,0000)_B = (00)_H;

      运算结果先是被存储到寄存器中,当 clk 上升沿到来时再输出,即在第10ns时:

      输出ledr\_out = 0000\,\,0000;输出hex1\_out = 1000000,hex0\_out = 1000000,即在数码管上显示十六进制数字00。

    2. 30 ~ 50 ns

      a = (0110)_B = (6)_H,b = (0010)_B = (2)_H,p = a × b = (0000\,\,1100)_B = (12)_H;

      运算结果先是被存储到寄存器中,当 clk 上升沿到来时再输出,即在第30ns时:

      输出ledr\_out = 0000\,\,1100;输出hex1\_out = 1000000,hex0\_out = 1000110,即在数码管上显示十六进制数字c。

    3. 50 ~ 70 ns

      a = (1001)_B = (9)_H,b = (0110)_B = (6)_H,p = a × b = (0011\,\,0110)_B = (36)_H;

      运算结果先是被存储到寄存器中,当 clk 上升沿到来时再输出,即在第50ns时:

      输出ledr\_out = 0011\,\,0110;输出hex1\_out = 0110000,hex0\_out = 0000010,即在数码管上显示十六进制数字36。

    4. 70 ~ 80 ns

      a = (1111)_H = (F)_H,b = (1001)_B = (b)_H,p = a × b = (1000\,\,0111)_B = (A5)_H。

      运算结果先是被存储到寄存器中,当 clk 上升沿到来时再输出,即在第70ns时:

      输出ledr\_out = 1000\,\,0111;输出hex1\_out = 0000000,hex0\_out = 1111000,即在数码管上显示十六进制数字87。

7.5.3 引脚分配、全编译与烧录

这个实验的引脚绑定跟实验六是一样的,只是新增了LEDR6、LEDR7。

操作数a及sel可以通过拨码开关SW0~SW3以及SW7~SW9来控制,carry_in从SW6输入。out信号分别输出到LEDR0到LEDR7,hex0_out输出到数码管0,hex1_out输出到数码管1,en和rst_n连接到按键key1和key0。

  1. 点击Quartus菜单Assignments——Pin Planner进行引脚分配。

img

图4.41

关于引脚分配信息可以查看DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\UserManual\DE1-SoC_User_manual.pdf第 22、25、26、28页或者E:\CD_Package\01-DE1-SoC\DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\Schematic\DE1-SoC.pdf的第3页。

img

image-20240517165745573

img

image-20240517165857589

image-20240521091242725

image-20240522160846326

image-20240522160950763

  1. 点击Quartus软件工具栏的Processing --> Start Compilation或点击

    image-20210603145755433

    按钮编译工程,编译完成后,如图7.37所示。

    image-20240522161410628

    图7.37 编译Verilog代码

    此外还可以看到在output_files文件夹中生成了calculator.sof文件,如图7.38所示。

    image-20240522161517000

    图7.38 编译生成lab7.sof文件

  2. 使用上一步中编译生成的calculator.sof文件对FPGA进行编程。连接DE1-SOC开发板到PC, 给开发板上电开机。

  3. 点击Quartus软件工具栏的Tools --> Programmer或点击

    image-20210603150014201

    按钮打开Programmer窗口,如图7.39所示。

    image-20240522161658529

    图7.39 Programmer窗口

  4. 点击Hardware Setup...打开Hardware Setup窗口,在Currently selected hardware的下拉框中选择"DE-SoC[USB-1]",点击Close,如图7.40所示。

    image-20240522161838106

    图7.40 Hardware Setup窗口

  5. 点击Auto Detect按钮,在弹出的Select Device窗口中,选择5CSEMA5(DE1-SOC开发板上的FPGA器件为Cyclone V 5CSEMA5F31C6),并点击OK,如图7.41所示。

    image-20240522161917436

    图7.41 选择5CSEBA6器件

    在弹出的Quartus Prime提示窗口中,点击Yes

    image-20240522162052756

    图7.42 提示弹窗

    然后在Programmer窗口会出现SOCVHPS和FPGA两个器件,如图7.43所示。

    image-20240522162254050

    图7.43 Programmer窗口出现SOCVHPS和FPGA两个器件

  6. 左键单击选中5CSEBA6器件,然后点击Change File按钮,添加lab7.sof文件,添加完成后如图7.44所示。

    图7.44 添加lab7.sof文件

  7. 勾选Program/Configure,点击Start按钮,开始烧录lab1.sof文件,如图7.45所示。

    image-20240522162343724

    图7.45 开始烧录

  8. 烧录完成后,Progress进度条显示100%,如图7.46所示。

    image-20240522162402338

    图7.46 烧录完成

7.5.4 实验现象观察
  1. 通过切换滑动开关SW9~SW0到 up 或 down 位置,并按下按键KEY1KEY0,观察数码管HEX1~HEX0以及LEDR7~LEDR0的状态来测试设计的功能。

    本实验重点验证乘法器的功能,因此将SW9~SW7拨动并保持为"up、down、up",即选择执行乘法运算。

    SW3~SW0位置为"down、down、up、down"时,按下按键KEY1,此时操作数b也等于2,LEDR7~LEDR0显示为熄灭、熄灭、熄灭、熄灭、熄灭、点亮、熄灭、熄灭,HEX1HEX0上会显示十六进制数字04。

    即a = (0010)_B = (2)_H,b = (0010)_B = (2)_H,p = (0000\,\,0100)_B = (04)_H;

    4d06f15083cee5e82621c3cfeea15d1d

    图7.50 运行结果(1)

    • SW3~SW0位置为"down、up、up、down"时,按下按键KEY1,此时操作数b也等于6,LEDR7~LEDR0显示为熄灭、熄灭、熄灭、点亮、熄灭、熄灭、点亮、熄灭,HEX1HEX0上会显示十六进制数字12。

      即a = (0110)_B = (6)_H,b = (0110)_B = (6)_H,p = (0010\,\,0100)_B = (24)_H;

      ea96df3a73c430570798850766ed7f0a

      图7.51 运行结果(2)

    • SW3~SW0位置为"up、down、down、up"时,按下按键KEY1,此时操作数b也等于9,LEDR7~LEDR0显示为熄灭、熄灭、点亮、点亮、点亮、点亮、点亮、点亮,HEX1HEX0上会显示十六进制数字3F。

      即a = (1001)_B = (9)_H,b = (1001)_B = (9)_H,p = (0101\,\,0001)_B = (51)_H;

      a4aecb71f24f227516a4ca8019bd6213

      图7.52 运行结果(3)

    • SW3~SW0位置为"up、up、up、up"时,按下按键KEY1,此时操作数b也等于F,LEDR7~LEDR0显示为点亮、熄灭、点亮、熄灭、熄灭、点亮、熄灭、点亮,HEX1HEX0上会显示十六进制数字A5。

      即a = (1111)_H = (F)_H,b = (1111)_B = (F)_H,p = (1110\,\,0001)_B = (E1)_H。

      64636139a537d6e49a0a81326e7708b6

      图7.53 运行结果(4)

7.6 实验小结

通过本实验,可掌握使用全加器、串行进位加法器和树形加法器等多种方式构造多位数的乘法运算,并验证乘法器的功能。

这篇关于第七篇 乘法器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1031596

相关文章

iOS笔记:第七篇 C语言 数组

第一节            数   组 1. 数组  作用:用来存储多个数据.  数组与普通变量的区别:      1)数组可以存储多个数据,普通变量只能存储一个数据      2)数组中的多个数据共存,普通变量只能有一个.  数组的特点:      1)存储多个数据      2)存储的多个数据的类型必须要相同.这个类型在创建数组的时候指定.      3)数组的长度

nginx教程第七篇:ngx_http_core_module模块提供的变量

在记录access_log访问日志文件时, 可以使用ngx_http_core_module模块处理请求时所产 生的丰富的变量, 当然, 这些变量还可以用于其他HTTP模块。 例如:当URI中的某个参数满足设定的条件时, 有些HTTP模块的配置项可以使用类似 $arg_PARAMETER 这样的变量。又如:若想把每个请求中的限速信息记录到access日志文件中, 则可以使用 $limit_ra

第七篇:稳定性之提升团队潜意识【提前预防、裕度设计】

提前预防 提前预防是告诉我们从失败中学习,防止同样的故障再次发生,海因里希法则告诉我们,一次重大事故的背后必然有一百次未遂事件和几十次轻度损失。这个法则对于我们有两个启示:一是事故的发生必然有其关联起因和先发信号;二是事故发生前一定有足够的提示,我们要及时遏制苗头,防患于未然。 从失败中学习吸取经验教训,例如每次出现事故,都需要对事故进行复盘,分析和总结事故原因,包括事故处理过程,包括后期

多线程第七篇:互斥和同步总结

同步:多个线程(进程)之间有严格的先后顺序,一个线程(进程)的执行,依赖于另一个.    互斥:多个线程(进程)没有先后顺序,谁抢到算谁的.   注意:线程的创建和执行是分开的,并不是创建后立即执行,而是创建后,等待cpu调度. window中的四种线程(进程)间同步与互斥. criticalSection,mutex,event,sema

关于FPGA设计16位乘法器的两…

原文地址:关于FPGA设计16位乘法器的两种算法 作者:ChrisChan 部分原代码如下: 用特权的右移算法虽复杂点,但节省不少LEs,如下图: 用左移算法尽管浅显易懂,但因每次都会从最右端移位,会占用更大面积,速度暂不说,如下图:

第七篇 zabbix监控本机

创建好主机群组后,就可以在主机群组中添加我们要监控的主机,这里我们对本机进行监控。 点击创建主机,填上主机的名称和对应的IP即可,主机群组就选择我们之前建好的zabbix group1 点击模板,这里就选用系统自带的模板,我的本地系统是CentOs7,就选择模板Template OS Linux和Template App Zabbix Server即可,模板中带有很多已经写好的监控任务

【Oracle篇】Oracle数据库坏块处理:rman修复坏块实践与案例分析(第七篇,总共八篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️ 💖💖💖大佬们都喜欢静静的看文章,并且也会默默的点赞收藏加关注💖💖💖     今天这篇文章作为Oracle rman系列的倒数第二篇,那

【第七篇】SpringSecurity核心组件和核心过滤器

一、SpringSecurity中的核心组件 在SpringSecurity中的jar分为4个,作用分别为 jar作用spring-security-coreSpringSecurity的核心jar包,认证和授权的核心代码都在这里面spring-security-config如果使用SpringSecurity XML命名空间进行配置或者SpringSecurity的<br />Java co

FPGA通过移位相加实现无符号乘法器(参数化,封装成IP可直接调用)

目录 1.前言2.原理3.移位无符号乘法器实现,并参数化 微信公众号获取更多FPGA相关源码: 1.前言 在硬件设计中,乘法器是非常重要的一个器件,乘法器的种类繁多,常见的有并行乘法器、移位相加乘法器和查找表乘法器。 并行乘法器的实现非常简单,在Verilog中只需要通过 * 实现,若要进行有符号的乘法,需使用 系统函数$signed。 查找表乘法器实际上是先将乘法的计算

大数据Scala教程从入门到精通第七篇:Scala在IDEA中编写Hello World

一:Scala在IDEA中编写Hello World         想让我们的idea支持scala的编写,需要安装一个插件。