本文主要是介绍第七篇 乘法器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
实验七 乘法器
7.1 实验目的
-
回顾实验五中讲解的加法器的实现,掌握使用全加器实现任意乘数的乘法器的基本原理;
-
掌握使用串行进位加法器实现任意乘数的乘法器的基本原理;
-
掌握使用树形加法器实现任意乘数的乘法器的基本原理。
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上。
图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中的框图一致。
图7.12 calculator子模块RTL视图
7.5 实验步骤
7.5.1 创建工程和代码输入
-
点击电脑右下角的开始菜单找到Quartus软件,双击Quartus (Quartus Prime 17.1)打开Quartus Prime软件。
-
点击菜单File-->New Project Wizard弹出工程创建的对话框。在弹出的对话框中点击Next。
-
在您的DE1-SOC 工作文件夹下创建一个lab7的文件夹,并将工程路径指向该文件夹,且工程的名称也命名calculator。如图7.13所示。
图7.13 选择实验
-
连续点击三次Next后,选择器件5CSEMA5F31C6,继续点击Next,最后点击Finish完成工程创建。
图7.14 创建Quartus工程
-
完成创建工程后,Quartus Prime软件会打开lab7工程,如图7.15所示。
图7.15 Quartus软件打开lab7工程
-
打开lab7工程路径,新建名为v的文件夹,如图7.16所示。
图7.16 在lab7文件夹下新建v文件夹
-
将实验六 移位寄存器中的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所示。
图7.17 拷贝文件到v文件夹中
-
点击Quartus软件工具栏的Assignments --> Settings --> Files,将前面拷贝的文件添加至本实验的Quartus工程,如图7.19所示。
图7.18 添加拷贝的文件到Quartus工程
-
点击Project Navigator下拉框,选中Files,然后双击v/c6.v打开c6.v文件,参考代码7.6修改c6.v文件(代码7.4、代码7.5和代码7.6实现的功能相同,在这里我们以代码7.6为例进行实验)。
图7.19 Quartus软件中的c6.v文件
-
然后双击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
图7.20 Quartus软件中的mux8x1.v文件
-
打开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
图7.21 reg8bits.v文件
-
参考代码7.7修改calculator.v文件。
图7.22 Quartus软件中的calculator.v文件
-
点击Quartus软件工具栏的Processing --> Start --> Start Analysis & Synthesis或点击
按钮对Verilog HDL代码执行语法检查和综合。如果在该过程中提示有错误,请检查Verilog HDL代码语法,确保与上述代码块完全一致。
图7.24 对Verilog代码进行分析和综合
7.5.2 仿真
-
点击Quartus软件工具栏的File --> New --> Verilog HDL File,点击OK,新建一个空白Verilog HDL文件,再点击File --> Save As ...保存,命名为calculator_tb.v,保存在v文件夹中,如图7.25所示。
图7.25 新建并保存test bench文件
-
在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文件
-
点击Quartus软件工具栏的Assignments --> Settings,在弹出的Settings窗口中,选中Simulation栏,Tool name选择ModelSim-Altera,设置Quartus自动调用ModelSim。然后选择添加Test Bench文件,如图7.27所示。
图7.27 设置Quartus仿真选项
-
依次执行下面的步骤添加calculator_tb.v文件:
① 在弹出的Test Benches窗口中点击New;
图7.28 添加Test Bench文件(步骤1)
② 在弹出的New Test Bench Settings窗口中,在Test bench name栏填入calculator_tb;
③ 点击
图标;
图7.29 添加Test Bench文件(步骤2、3)
④ 在弹出的Select File窗口,选中第一步中创建的calculator_tb.v文件;
⑤ 点击Open;
图7.30 添加Test Bench文件(步骤4、5)
⑥ 在File name栏会出现选中的calculator_tb.v文件;
⑦ 点击Add添加test bench文件;
⑧ 添加后会出现在下面的框格中;
⑨ 点击OK,退出当前窗口;
图7.31 添加Test Bench文件(步骤6、7、8、9)
⑩ 返回到Test Benches窗口,在Existing test bench settings框格中会出现前面设置好的test bench文件;
⑪ 点击OK,退出当前窗口;
图7.32 添加Test Bench文件(步骤10、11)
⑫ 返回到Simulation设置界面,可以看到Compile test bench栏成功添加了calculator_tb仿真文件;
⑬ 点击Apply应用新的设置;
⑭ 点击Close关闭设置窗口。
图7.33 添加Test Bench文件(步骤12、13、14)
-
点击Quartus软件工具栏的Tools --> Run Simulation Tool --> RTL Simulation启动ModelSim仿真,再点击Wave选项卡切换到仿真波形窗口,如图7.34所示。
图7.34 点击Wave选项卡切换到仿真波形窗口
-
此时还看不到完整的仿真波形,可以通过点击如图7.35所示的Zoom Full按钮来显示完整的波形。
图7.35 Zoom Full按钮
-
完整的仿真波形如图7.36所示。
图7.36 calculator仿真波形
下面对仿真波形进行分析:
本次仿真的重点是仿真乘法器的功能,因此将功能选择输入 sel 固定为 (101)_B 。
-
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。
-
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。
-
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。
-
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。
-
点击Quartus菜单Assignments——Pin Planner进行引脚分配。
图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页。
-
点击Quartus软件工具栏的Processing --> Start Compilation或点击
按钮编译工程,编译完成后,如图7.37所示。
图7.37 编译Verilog代码
此外还可以看到在output_files文件夹中生成了calculator.sof文件,如图7.38所示。
图7.38 编译生成lab7.sof文件
-
使用上一步中编译生成的calculator.sof文件对FPGA进行编程。连接DE1-SOC开发板到PC, 给开发板上电开机。
-
点击Quartus软件工具栏的Tools --> Programmer或点击
按钮打开Programmer窗口,如图7.39所示。
图7.39 Programmer窗口
-
点击Hardware Setup...打开Hardware Setup窗口,在Currently selected hardware的下拉框中选择"DE-SoC[USB-1]",点击Close,如图7.40所示。
图7.40 Hardware Setup窗口
-
点击Auto Detect按钮,在弹出的Select Device窗口中,选择5CSEMA5(DE1-SOC开发板上的FPGA器件为Cyclone V 5CSEMA5F31C6),并点击OK,如图7.41所示。
图7.41 选择5CSEBA6器件
在弹出的Quartus Prime提示窗口中,点击Yes。
图7.42 提示弹窗
然后在Programmer窗口会出现SOCVHPS和FPGA两个器件,如图7.43所示。
图7.43 Programmer窗口出现SOCVHPS和FPGA两个器件
-
左键单击选中5CSEBA6器件,然后点击Change File按钮,添加lab7.sof文件,添加完成后如图7.44所示。
图7.44 添加lab7.sof文件
-
勾选Program/Configure,点击Start按钮,开始烧录lab1.sof文件,如图7.45所示。
图7.45 开始烧录
-
烧录完成后,Progress进度条显示100%,如图7.46所示。
图7.46 烧录完成
7.5.4 实验现象观察
-
通过切换滑动开关SW9~SW0到 up 或 down 位置,并按下按键KEY1或KEY0,观察数码管HEX1~HEX0以及LEDR7~LEDR0的状态来测试设计的功能。
本实验重点验证乘法器的功能,因此将SW9~SW7拨动并保持为"up、down、up",即选择执行乘法运算。
SW3~SW0位置为"down、down、up、down"时,按下按键KEY1,此时操作数b也等于2,LEDR7~LEDR0显示为熄灭、熄灭、熄灭、熄灭、熄灭、点亮、熄灭、熄灭,HEX1和HEX0上会显示十六进制数字04。
即a = (0010)_B = (2)_H,b = (0010)_B = (2)_H,p = (0000\,\,0100)_B = (04)_H;
图7.50 运行结果(1)
-
SW3~SW0位置为"down、up、up、down"时,按下按键KEY1,此时操作数b也等于6,LEDR7~LEDR0显示为熄灭、熄灭、熄灭、点亮、熄灭、熄灭、点亮、熄灭,HEX1和HEX0上会显示十六进制数字12。
即a = (0110)_B = (6)_H,b = (0110)_B = (6)_H,p = (0010\,\,0100)_B = (24)_H;
图7.51 运行结果(2)
-
当SW3~SW0位置为"up、down、down、up"时,按下按键KEY1,此时操作数b也等于9,LEDR7~LEDR0显示为熄灭、熄灭、点亮、点亮、点亮、点亮、点亮、点亮,HEX1和HEX0上会显示十六进制数字3F。
即a = (1001)_B = (9)_H,b = (1001)_B = (9)_H,p = (0101\,\,0001)_B = (51)_H;
图7.52 运行结果(3)
-
当SW3~SW0位置为"up、up、up、up"时,按下按键KEY1,此时操作数b也等于F,LEDR7~LEDR0显示为点亮、熄灭、点亮、熄灭、熄灭、点亮、熄灭、点亮,HEX1和HEX0上会显示十六进制数字A5。
即a = (1111)_H = (F)_H,b = (1111)_B = (F)_H,p = (1110\,\,0001)_B = (E1)_H。
图7.53 运行结果(4)
-
7.6 实验小结
通过本实验,可掌握使用全加器、串行进位加法器和树形加法器等多种方式构造多位数的乘法运算,并验证乘法器的功能。
这篇关于第七篇 乘法器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!