基于Basys2的Booth乘法器的设计
目录
一、设计指标(老样子,鲲鲲定的,我直接贴上来)
二、Booth乘法原理
三、Verilog代码
1、Booth乘法器:
2、显示转换模块:
3、数值位译码器:
4、符号位译码器:
5、时钟分频模块:
6、数码管动态扫描模块:
7、LED显示模块:
8、顶层模块:
四、FPGA实现:
1、管脚约束
2、上板结果:
一、设计指标(老样子,鲲鲲定的,我直接贴上来)
在Basys2/3开发板上使用7段数码管和SW0-SW7实现一个4位输入的Booth乘法器,要求如下:
- 使用Verilog语言设计4位输入的Booth乘法器;
- 开关功能定义如下,乘数为:
SW0-SW3输入为乘数,输入数据格式为补码;
SW0-SW3输入为乘数,输入数据格式为补码;
- 输出功能定义如下:
7段数码管低2组作为加法器结果输出,十六进制格式输出;
- 完成功能电路设计、测试环境设计、完成测试激励设计、测试结果自动校验,测试激励覆盖输入信号全部取值范围组合;
- 使用ISE、Vivado执行Booth乘法器功能仿真、综合、布局布线并执行后仿和FPGA编程测试。
二、Booth乘法原理
Booth算法的显著优势是直接对补码进行乘法运算,其算法原理可以参考以下几个:(我不认为我讲的比他们更清楚,哈哈哈另一方面原因是我已经忘记了):
【FPGA基础知识】booth算法:Verilog乘法原理与Booth算法优化_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1vY4y1t7QG?spm_id_from=333.337.search-card.all.click&vd_source=c0a67d78218a5e3a4a7eb4d3591de45c Verilog -- 乘法器Booth算法 - love小酒窝 - 博客园 (cnblogs.com)https://www.cnblogs.com/lyc-seu/p/12842399.html
在理解Booth算法之后,这个实验题就已经解决了一大半了,剩下的就是用我们已经讲过的数码管动态扫描模块将结果显示出来了。
三、Verilog代码
应用模块化的思想来进行,系统框图大概张这个样子:
结合题目要求,我打算用数码管的后两位以十六进制补码形式显示运算结果(4位*4位结果为8位,所以转化为16进制就是2位),用8个LED作为输入的乘数和被乘数的显示(亮为1,灭为0)
具体代码如下:
1、Booth乘法器:
采用三段式状态机的结构来进行Booth乘法运算。输入时钟、复位、乘数、被乘数,输出结果到数码管显示模块转化为段选码显示在数码管上。
module Booth_mul
#(parameter DATA_WIDTH = 4)
(input clk,input rst,input [DATA_WIDTH-1:0]num1_comp,//被乘数input [DATA_WIDTH-1:0]num2_comp,//乘数output reg [2*DATA_WIDTH-1:0]result// output Done
);//状态机方式实现Radix_2 Booth乘法器//状态声明(格雷码)parameter IDLE = 2'b00;parameter ADD = 2'b01;parameter SHIFT = 2'b11;parameter OUTPUT = 2'b10;//内部寄存器、信号线声明reg [1:0]current_state;//寄存当前状态reg [1:0]next_state;//寄存下一状态wire [DATA_WIDTH-1:0]num2_comp_neg;//乘数的补码reg [DATA_WIDTH-1:0]iter_cnt;//控制迭代次数reg [2*DATA_WIDTH:0]p_reg;//P空间,用于右移reg [2*DATA_WIDTH:0]sum_reg;//暂存ADD操作之后的P空间数值assign num2_comp_neg = ~num2_comp + 1;//状态转移控制always@(posedge clk or posedge rst)beginif(rst)current_state <= IDLE;elsecurrent_state <= next_state;end//确定下一个状态always@(*)begincase(current_state)IDLE: next_state = ADD;ADD: next_state = SHIFT;SHIFT: beginif(iter_cnt == DATA_WIDTH)next_state = OUTPUT;elsenext_state = ADD;endOUTPUT: next_state = IDLE;default: next_state = 2'bxx;endcaseend//基2Booth乘法器算法实现always@(posedge clk or posedge rst)beginif(rst)beginp_reg <= 0;sum_reg <= 0;result <= 0;// is_Done <= 0;endelsebegincase(current_state)IDLE:beginp_reg <= {{(DATA_WIDTH){1'b0}},num1_comp,1'b0};iter_cnt <= 0;// is_Done <= 1'b0;endADD:begincase(p_reg[1:0])2'b01: sum_reg <= {p_reg[8:5] + num2_comp,p_reg[4:0]};//加乘数的补码2'b10: sum_reg <= {p_reg[8:5] + num2_comp_neg,p_reg[4:0]};//加乘数的负数的补码default: sum_reg <= p_reg;//不执行加操作endcaseiter_cnt <= iter_cnt + 1;// is_Done <= 1'b0;endSHIFT:beginp_reg <= {sum_reg[2*DATA_WIDTH],sum_reg[2*DATA_WIDTH:1]};//整体右移一位,符号拓展// is_Done <= 1'b0;endOUTPUT:beginresult <= p_reg[2*DATA_WIDTH:1];// is_Done <= 1'b1;endendcaseendend//输出计算完成信号// assign Done = is_Done;endmodule
2、显示转换模块:
由于十六进制补码形式很难一眼看出结果的十进制数值,于是我就加入了一个显示转换,将有符号十六进制数转换为无符号十六进制数(如果被转换的是负数,就在转换结果之前显示一个符号)
module output_conversion(input clk,input rst,input conversion,input [7:0]hex_number,output reg [3:0]L_bit,output reg [3:0]H_bit,output reg Sign);//声明内部信号wire mode_flag;//输出模式标志(1:无符号位十六进制输出,0:带符号位十六进制输出),默认十六进制输出wire sign_flag;//判断输入是否为负数wire [7:0]comp_reg;//用于计算负数的真值对应的二进制数//模式状态控制assign mode_flag = conversion;assign sign_flag = hex_number[7];assign comp_reg = ~hex_number+ 1'b1;//输出转换always@(posedge clk or posedge rst)beginif(rst)beginL_bit <= 4'd0;H_bit <= 4'd0;Sign <= 4'd0;endelse if(mode_flag)//无符号位十六进制输出beginif(sign_flag)//负数处理beginL_bit <= comp_reg[3:0];H_bit <= comp_reg[7:4];Sign <= 1'b1;endelse//正数处理beginL_bit <= hex_number[3:0];H_bit <= hex_number[7:4];Sign <= 1'b0;endendelse//带符号位十六进制输出beginL_bit <= hex_number[3:0];H_bit <= hex_number[7:4];Sign <= 1'b0;endendendmodule
3、数值位译码器:
将2位十六进制数转化为共阳极数码管段选码,用于数码管动态扫描
module wei_encoder(input [3:0]hex_number,output reg [7:0]display_code);//将输入的十六进制代码转换为共阳极数码管段选编码并输出always@(*)begincase(hex_number)4'b0000:display_code = 8'hc0;//04'b0001:display_code = 8'hf9;//14'b0010:display_code = 8'ha4;//24'b0011:display_code = 8'hb0;//34'b0100:display_code = 8'h99;//44'b0101:display_code = 8'h92;//54'b0110:display_code = 8'h82;//64'b0111:display_code = 8'hf8;//74'b1000:display_code = 8'h80;//84'b1001:display_code = 8'h90;//94'b1010:display_code = 8'h88;//A4'b1011:display_code = 8'h83;//B4'b1100:display_code = 8'hc6;//C4'b1101:display_code = 8'ha1;//D4'b1110:display_code = 8'h86;//E4'b1111:display_code = 8'h8e;//Fdefault:display_code = 8'hff;//无endcaseend
endmodule
4、符号位译码器:
如果是负数,就译码为一个“-”负号显示在数值位前面,如果是正数,就不显示
module sign_encoder(input Sign,output reg [7:0]display_code);always@(*)beginif(Sign)display_code = 8'hbf;//-elsedisplay_code = 8'hff;//无end
endmodule
5、时钟分频模块:
将板子输入的50MHz时钟通过计数分频的形式转化为1KHz时钟,用于动态扫描
module clk_div(input clk,input rst,output reg clk_div);//输入板子50MHz时钟,输出1KHz时钟//计数分频:50000次reg [15:0]cnt = 16'd0;always@(posedge clk or posedge rst)beginif(rst)begincnt <= 16'd0;endelse if(cnt == 16'd50000)begincnt <= 16'd0;endelsebegincnt <= cnt + 16'd1;endend//输出时钟控制always@(posedge clk or posedge rst)beginif(rst)beginclk_div <= 1'b0;endelse if(cnt <= 16'd24999)beginclk_div <= 1'b1;endelsebeginclk_div <= 1'b0;endend
endmodule
6、数码管动态扫描模块:
输入分频后的1KHz时钟和待输出的段选码,根据扫描计数器的状态控制动态扫描位选和段选
module Display(input clk_div,input rst,input [7:0]Out_number_1,input [7:0]Out_number_2,input [7:0]Out_number_3,output reg [7:0]duan_code,output reg [3:0]wei_code);//将输入的十六进制代码转换为共阳极数码管段选码动态扫描输出reg [1:0]sel_cnt;//扫描计数器//动态扫描//扫描计数器控制位选always@(posedge clk_div or posedge rst)beginif(rst)beginsel_cnt <= 2'd0; endelse if(sel_cnt == 2'd3)beginsel_cnt <= 2'd0;endelsebeginsel_cnt <= sel_cnt + 2'd1;endend//位选与段选对应always@(posedge clk_div or posedge rst)beginif(rst)beginwei_code <= 4'b0000;duan_code <= 8'hff;endelsebegincase(sel_cnt)2'd0:beginwei_code <= 4'b0001;duan_code <= Out_number_1;end2'd1:beginwei_code <= 4'b0010;duan_code <= Out_number_2;end2'd2:beginwei_code <= 4'b0100;duan_code <= Out_number_3;enddefault:beginwei_code <= 4'b0000;duan_code <= 8'hff;endendcaseendendendmodule
7、LED显示模块:
显示乘数和被乘数(高4位和低4位分别代表一个4位二进制数)
module led_display(input clk,input rst,input [3:0]number_1,input [3:0]number_2,output reg [7:0]led);always@(posedge clk or posedge rst)beginif(rst)led <= 8'h00;elsebeginled[3:0] <= number_1;led[7:4] <= number_2;endend
endmodule
8、顶层模块:
上面构建了这么多模块,终于要在顶层模块中实例化连接了
module top(input clk,input rst,input conversion,//用于选择输出模式(带符号十进制输出或十六进制输出)input [3:0]num1_comp,input [3:0]num2_comp,output [3:0]wei_code,output [7:0]duan_code,output [7:0]led_light);//声明内部信号wire clk_div;//1KHz时钟用于驱动数码管动态扫描wire [7:0]Output_number_1;//数码管右一显示输出wire [7:0]Output_number_2;//数码管右二显示输出wire [7:0]Output_number_3;//数码管右三显示输出wire [7:0]result;//将乘法运算结果传输给编码模块// wire Done;//乘法运算完成信号wire [3:0]L_bit;//校正后的低四位用于转换为段选码wire [3:0]H_bit;//校正后的高四位用于转换为段选码wire Sign;//判断十进制输出的符号//模块实例化//Booth乘法器Booth_mul multiplier(.clk(clk),.rst(rst),.num1_comp(num1_comp),.num2_comp(num2_comp),.result(result)// .Done(Done));//乘法结果(8位带符号二进制数)校正为高低两位(4位二进制数)用于转换为段选码output_conversion converse(.clk(clk),.rst(rst),.conversion(conversion),.hex_number(result),.L_bit(L_bit),.H_bit(H_bit),.Sign(Sign));//将乘法器输出的数字转化为段选码wei_encoder encoder_1(.hex_number(L_bit),.display_code(Output_number_1));wei_encoder encoder_2(.hex_number(H_bit),.display_code(Output_number_2));sign_encoder encoder_3(.Sign(Sign),.display_code(Output_number_3));//将板子50MHz时钟分频为1KHz时钟用于数码管动态扫描clk_div divider(.clk(clk),.rst(rst),.clk_div(clk_div));//数码管动态扫描模块Display display(.clk_div(clk_div),.rst(rst),.Out_number_1(Output_number_1),.Out_number_2(Output_number_2),.Out_number_3(Output_number_3),.duan_code(duan_code),.wei_code(wei_code));//led灯显示输入的补码(亮:1,灭:0),方便观察led_display led(.clk(clk),.rst(rst),.number_1(num1_comp),.number_2(num2_comp),.led(led_light));
endmodule
四、FPGA实现:
1、管脚约束
老样子,根据开发板手册在PlanAhead上进行绑定
生成的约束文件如下:
NET "duan_code[7]" LOC = N13;
NET "duan_code[6]" LOC = M12;
NET "duan_code[5]" LOC = L13;
NET "duan_code[4]" LOC = P12;
NET "duan_code[3]" LOC = N11;
NET "duan_code[2]" LOC = N14;
NET "duan_code[1]" LOC = H12;
NET "duan_code[0]" LOC = L14;
NET "led_light[7]" LOC = G1;
NET "led_light[6]" LOC = P4;
NET "led_light[5]" LOC = N4;
NET "led_light[4]" LOC = N5;
NET "led_light[3]" LOC = P6;
NET "led_light[2]" LOC = P7;
NET "led_light[1]" LOC = M11;
NET "led_light[0]" LOC = M5;
NET "num1_comp[0]" LOC = P11;
NET "num1_comp[1]" LOC = L3;
NET "num1_comp[2]" LOC = K3;
NET "num1_comp[3]" LOC = B4;
NET "num2_comp[0]" LOC = G3;
NET "num2_comp[1]" LOC = F3;
NET "num2_comp[2]" LOC = E2;
NET "num2_comp[3]" LOC = N3;
NET "wei_code[3]" LOC = K14;
NET "wei_code[2]" LOC = M13;
NET "clk" LOC = B8;NET "wei_code[1]" LOC = J12;
NET "wei_code[0]" LOC = F12;# PlanAhead Generated physical constraints NET "conversion" LOC = G12;
NET "rst" LOC = C11;
2、上板结果:
4’h7 * 4’h8 = 8’hC8,同时验证结果补码与源码转换
4’h7 * 4’h7 = 8’h31
4’h7 * 4’h3 = 8’h15
基于Basys2的Booth乘法器的设计相关推荐
- 基于basys2驱动LCDQC12864B的verilog设计图片显示
话不多说先上图 前言 在做这个实验的时候在网上找了许多资料,都是关于使用单片机驱动LCD显示,确实用单片机驱动是要简单不少,记得在FPGA学习交流群里问问题的时候,被前辈指教,说给我最好的指教便是别在 ...
- 基于Basys2的八位CPU的设计与FPGA实现
目录 一.设计指标(鲲鲲提的要求,直接贴过来) 二.设计思路: 1.完整的8位CPU的设计: 2.本次设计思路: 三.Verilog实现 1.RAM: 2.指令寄存器IR 3.ALU 4.CPU 5. ...
- 基于Basys2的分秒计时器的设计
目录 一.设计指标(同样的都是鲲鲲指定的,我直接贴过来) 二.计时器原理: 三.Verilog实现 1.十进制计数器: 2.六进制计数器: 3.六十进制计数器: 4.计时器: 5.时钟分频:50MHz ...
- 原码一位乘法器设计_数字IC校招基础知识点复习(七)——超前进位加法器、Wallace树、Booth乘法器...
1.超前进位加法器 看了一些面经,提到会让你用基础的门搭加法器,因此首先得熟悉半加器,全加器等最基础的加法器才能理解之后的超前进位加法器,树型加法器等复杂的加法器. 半加器的输入为a,b,输出为结果s ...
- 基于Basys2开发板的简易电子琴和音乐播放器设计
背景:华中科技大学 电测综合实验 主要功能:Basys2开发板外接一个扬声器(或无源蜂鸣器也可)实现电子琴和音乐播放器的功能.其中由于开发板上只有4个按键,所以电子琴功能只做了4个音调,分别对应于4个 ...
- 【HDL系列】乘法器(6)——Radix-4 Booth乘法器
目录 一.Radix-4 Booth乘法器原理 二.Verilog设计 一.Radix-4 Booth乘法器原理 上文中介绍了基2 Booth乘法器,本文继续介绍基4 Booth乘法器. 对于N比特数 ...
- booth乘法器原理
在微处理器芯片中,乘法器是进行数字信号处理的核心,同时也是微处理器中进行数据处理的关键部件.乘法器完成一次操作的周期基本上决定了微处理器的主频.乘法器的速度和面积优化对于整个CPU的性能来说是非常重要 ...
- 【HDL系列】乘法器(5)——Radix-2 Booth乘法器
一.Booth乘法器原理 Booth算法可以减少乘法运算中加法/减法次数,是二进制乘法补码运算的高效算法. 我们已经很熟悉,在乘法运算中包含2部分:(1):生成部分和:(2)部分和累积 而Booth算 ...
- Booth乘法器和wallace树乘法器的理解
<span style="font-family: FangSong_GB2312; color: rgb(51, 51, 51);"><span style=& ...
最新文章
- TickableObjects 和 ITickable
- JavaBean的保存范围与javaBean的删除
- 如何在Linux下统计高速网络中的流量
- Linux设备驱动程式之读书笔记(二) [转]
- 魅族用鸿蒙系统吗,魅族宣布接入鸿蒙是怎么回事?魅族手机可以刷鸿蒙系统吗?...
- HTML中transform菜鸟,HTML canvas
- python day5--正则表达式
- Python小数据池,代码块
- Storm消费Kafka异常 - topic其中两个分区达到某个值不进行消费,持续阻塞
- asyncio oracle 异步,带有asyncio futures和RuntimeError的InvalidStateError与aiohttp时使用期货回调...
- python svn库_python实现svn新老库迁移
- scp拷贝文件夹到另一个服务器目录中
- 计算机组成原理补充实验,计算机组成原理实验补充实验指导-实.doc
- nfine框架 上传文件,nfine(nfine快速开发框架)
- BilSTM 实体识别_“万创杯”中医药天池大数据竞赛——中药说明书实体识别挑战的一点感受...
- 申请ISO14001认证组织需要准备哪些资料
- UTAU中文版安装教程
- 如何把word文件转换成PDF格式?
- html+css网页开发 之 头部导航条(logo、导航栏、搜索框)
- Apifiny任命FBI前高管Timothy Murphy为董事会成员,帮助公司完成上市计划
热门文章
- numpy中ravel()与flatten()的区别
- C#生成含数字字母的随机字符串
- 解决linux无法启动,进入救援模式也报错:you don‘t have any linux partitions的问题
- sail.js学习 - 安装篇
- ad中按钮开关的符号_送给初学者电工最常用电气元件实物图及对应符号
- 厦门计算机大学排名,全国计算机专业大学排名
- 计算机远程用户屏蔽,允许/阻止用户使用远程桌面服务进行远程连接
- 【沙发管家】夏普电视怎么装软件?怎么才能看免费电影,电视直播?
- docker-jenkins将打包的镜像推送到镜像仓库
- outlook收件延迟严重_你(严重)对我不了解的五件事